@@ -323,10 +323,14 @@ void WDHR::wd_Init( // initialize all members
323323 { static const NANDAT unset ( UNSET);
324324 float unsetf;
325325 V unsetf = V unset;
326- // treat as all floats
327- int szFloat = sizeof ( WDHR)/sizeof ( float );
328- VSet ( (float *)this , szFloat, unsetf);
329- wd_sunup = 0 ; // only integer, overwrite UNSET
326+ float * pF0 = &wd_slAzm;
327+ float * pFN = &wd_tdvElecAvg01;
328+ int szFloat = pFN - pF0 + 1 ;
329+ // attempt to detect layout change (+2 is due to packing)
330+ ASSERT ( szFloat*sizeof ( float )+sizeof ( wd_sunup)+sizeof ( wd_tdvElecHrRank)+2 ==sizeof ( WDHR));
331+ VSet ( pF0, szFloat, unsetf);
332+ wd_sunup = 0 ; // non-floats
333+ VZero ( wd_tdvElecHrRank, 25 );
330334 }
331335} // WDHR::wd_Init
332336// ------------------------------------------------------------------------------
@@ -386,7 +390,7 @@ RC WDHR::wd_Unpack( // single-hour unpack
386390// returns RCOK
387391{
388392
389- wd_Init ( 1 ); // set all to UNSET)
393+ wd_Init ( 1 ); // set all to UNSET
390394
391395 int i = (wFileFormat==BSGSdemo); // normally fetch words 0,1,2, but to unscramble demo format, fetch 1,2,0
392396 int w = phour[i++]; // word 0, or 1 if scrambled
@@ -423,7 +427,8 @@ RC WDHR::wd_Unpack( // single-hour unpack
423427class WDDAY
424428{
425429friend class WDYEAR ;
426- friend class WFILE ;
430+ friend WDHR;
431+ friend WFILE;
427432 float wdd_taDbPvPk; // previous day max dry bulb air temp, F
428433 float wdd_taDbPk; // current day max dry bulb air temp, F
429434 float wdd_taDbAvg; // this day mean dry bulb air temp, F
@@ -445,12 +450,20 @@ friend class WFILE;
445450 float wdd_tdvElecAvg; // avg for cur day
446451 float wdd_tdvElecPvPk; // peak for prior day
447452 float wdd_tdvElecAvg01; // avg for print day
453+ SI wdd_tdvElecHrRank[ 25 ];// hr rank
448454public:
449455 void wdd_Init ();
450456 int wdd_Compare ( const WDHR* wdHr) const ;
451- void wdd_Set ( WDHR* wdHr, int options=0 ) const ;
457+ void wdd_Set24 ( WDHR* wdHr, int options=0 ) const ;
452458}; // class WDDAY
453459// ----------------------------------------------------------------------------
460+ struct VHR // sort helper for wdy_Stats
461+ { double v; // value
462+ SI iHr; // hour when value occurs
463+ static int Compare ( const void * pV1, const void * pV2)
464+ { return LTEQGT ( ((const VHR *)pV2)->v , ((const VHR *)pV1)->v ); }
465+ }; // struct VHR
466+ // ----------------------------------------------------------------------------
454467class WDYEAR
455468{
456469friend class WFILE ;
@@ -472,8 +485,8 @@ public:
472485 return wdy_day[ iD0];
473486 }
474487 RC wdy_Fill ( WFILE* pWF, int erOp=WRN);
475- void wdy_MeanMax ( int jDay, double & taDbMean, double & taDbMax,
476- double & tdvElecMean, double & tdvElecMax) const ;
488+ void wdy_Stats ( int jDay, double & taDbMean, double & taDbMax,
489+ double & tdvElecMean, double & tdvElecMax, SI tdvElecHrRank[ 25 ] ) const ;
477490 float wdy_TaDbAvg ( int jDay1, int jDay2);
478491}; // class WDYEAR
479492// -----------------------------------------------------------------------------
@@ -499,7 +512,7 @@ x // others: fill always
499512 int yrLen = wf_pWDY->wdy_isLeap ? 366 : 365 ;
500513 int jD;
501514 for (jD=1 ; jD <= yrLen; jD++)
502- wf_pWDY->wdy_Day ( jD).wdd_Set ( &wf_pWDY->wdy_Hr ( jD, 0 ), options);
515+ wf_pWDY->wdy_Day ( jD).wdd_Set24 ( &wf_pWDY->wdy_Hr ( jD, 0 ), options);
503516#if 0 && defined( _DEBUG)
504517 if (wFileFormat == CSW)
505518 { // CSW data should match calculated
@@ -559,11 +572,12 @@ RC WDYEAR::wdy_Fill( // read weather data for entire file; compute averages etc.
559572 if (rc)
560573 break ;
561574 double taDbMean, taDbMax, tdvElecMean, tdvElecMax;
562- wdy_MeanMax ( jDay, taDbMean, taDbMax, tdvElecMean, tdvElecMax);
575+ WDDAY& wdd = wdy_Day ( jDay);
576+ wdy_Stats ( jDay, taDbMean, taDbMax, tdvElecMean, tdvElecMax,
577+ wdd.wdd_tdvElecHrRank );
563578
564579 // current day values
565580 // next day's previous day values = current day
566- WDDAY& wdd = wdy_Day ( jDay);
567581 WDDAY& wdd1 = wdy_Day ( jDay+1 );
568582 wdd.wdd_taDbPk = wdd1.wdd_taDbPvPk = taDbMax;
569583 wdd.wdd_taDbAvg = wdd1.wdd_taDbAvg01 = taDbMean;
@@ -620,17 +634,20 @@ RC WDYEAR::wdy_Fill( // read weather data for entire file; compute averages etc.
620634 return rc;
621635} // WDYEAR::wdy_Fill
622636// -----------------------------------------------------------------------------
623- void WDYEAR::wdy_MeanMax ( // statistics for day
637+ void WDYEAR::wdy_Stats ( // statistics for day
624638 int jDay, // day of year (1-365/366)
625639 double & taDbMean, // returned: 24hr mean dry-bulb, F
626640 double & taDbMax, // returned: max dry-bulb, F
627641 double & tdvElecMean, // returned: mean TDV elec
628- double & tdvElecMax) const // returned: max TDV elec
642+ double & tdvElecMax, // returned: max TDV elec
643+ SI tdvElecHrRank[ 25 ]) const // returned: tdvElec ranked
629644// returns min, mean, and max dry-bulb for day
630645{
646+ VHR tdvElecHr[ 24 ]; // day's tdvElec for hour-rank sort
631647 taDbMax = tdvElecMax = -9999 .;
632648 taDbMean = tdvElecMean = 0 .;
633- for (int iHr=0 ; iHr<24 ; iHr++)
649+ int iHr;
650+ for (iHr=0 ; iHr<24 ; iHr++)
634651 { const WDHR& wd = wdy_Hr ( jDay, iHr);
635652 if (wd.wd_db > taDbMax)
636653 taDbMax = wd.wd_db ;
@@ -641,12 +658,25 @@ void WDYEAR::wdy_MeanMax( // statistics for day
641658 { if (wd.wd_tdvElec > tdvElecMax)
642659 tdvElecMax = wd.wd_tdvElec ;
643660 tdvElecMean += wd.wd_tdvElec ;
661+ tdvElecHr[ iHr].v = wd.wd_tdvElec ; // tdvElec for rank-hour sort
662+ tdvElecHr[ iHr].iHr = iHr; // corresponding hour
644663 }
645664 }
646- taDbMean = taDbMean / 24 .;
665+ taDbMean /= 24 .;
647666 if (!ISUNSET ( tdvElecMean))
648- tdvElecMean = tdvElecMean / 24 .;
649- } // WDYEAR::wdy_MeanMax
667+ { tdvElecMean /= 24 .;
668+ // sort the days tdvElec values is descending order
669+ qsort ( tdvElecHr, 24 , sizeof ( VHR), VHR::Compare);
670+ // return hour ranking as 1-based
671+ // tdvElecHrRank[ 1] = 1-based hour of peak TDV
672+ // [ 2] = ditto, next highest
673+ tdvElecHrRank[ 0 ] = 0 ; // [ 0] is unused
674+ for (iHr=0 ; iHr<24 ; iHr++)
675+ tdvElecHrRank[ iHr+1 ] = tdvElecHr[ iHr].iHr +1 ;
676+ }
677+ else
678+ VZero ( tdvElecHrRank, 25 ); // tdvElec values not complete
679+ } // WDYEAR::wdy_Stats
650680// -----------------------------------------------------------------------------
651681float WDYEAR::wdy_TaDbAvg ( // multi-day average dry bulb
652682 int jDay1, // 1st day (possibly < 0)
@@ -674,6 +704,7 @@ void WDDAY::wdd_Init()
674704 wdd_tdvElecAvg = 0 .f ;
675705 wdd_tdvElecPvPk = 0 .f ;
676706 wdd_tdvElecAvg01 = 0 .f ;
707+ VZero ( wdd_tdvElecHrRank, 25 );
677708
678709 wdd_tGrnd = 0 .f ;
679710 wdd_tMains = 0 .f ;
@@ -702,7 +733,7 @@ int WDDAY::wdd_Compare( // check that hour values match daily
702733 return diffCount;
703734} // WDDAY::wdd_Compare
704735// -----------------------------------------------------------------------------
705- void WDDAY::wdd_Set ( // set hourly values from daily
736+ void WDDAY::wdd_Set24 ( // set hourly values from daily
706737 WDHR* wdHr, // 1st hour data for day
707738 int options /* =0*/ ) const // option bits
708739 // 1: set iff destination is "missing"
@@ -712,42 +743,62 @@ void WDDAY::wdd_Set( // set hourly values from daily
712743#define SETIF ( d, s ) if (IsMissing( d)) d = s;
713744 if (!options)
714745 { for (int iHr=0 ; iHr<24 ; iHr++)
715- { WDHR& wd = wdHr[ iHr];
716- wd.wd_taDbPk = wdd_taDbPk;
717- wd.wd_taDbAvg = wdd_taDbAvg;
718- wd.wd_taDbPvPk = wdd_taDbPvPk;
719- wd.wd_taDbAvg01 = wdd_taDbAvg01;
720- wd.wd_taDbAvg07 = wdd_taDbAvg07;
721- wd.wd_taDbAvg14 = wdd_taDbAvg14;
722- wd.wd_taDbAvg31 = wdd_taDbAvg31;
723- wd.wd_tGrnd = wdd_tGrnd;
724- wd.wd_tMains = wdd_tMains;
725- wd.wd_tdvElecPk = wdd_tdvElecPk;
726- wd.wd_tdvElecAvg = wdd_tdvElecAvg;
727- wd.wd_tdvElecPvPk = wdd_tdvElecPvPk;
728- wd.wd_tdvElecAvg01 = wdd_tdvElecAvg01;
729- }
746+ wdHr[ iHr].wd_SetDayValues ( *this );
730747 }
731748 else
732749 { for (int iHr=0 ; iHr<24 ; iHr++)
733- { WDHR& wd = wdHr[ iHr];
734- SETIF ( wd.wd_taDbPk , wdd_taDbPk)
735- SETIF ( wd.wd_taDbAvg , wdd_taDbAvg)
736- SETIF ( wd.wd_taDbPvPk , wdd_taDbPvPk)
737- SETIF ( wd.wd_taDbAvg01 , wdd_taDbAvg01)
738- SETIF ( wd.wd_taDbAvg07 , wdd_taDbAvg07)
739- SETIF ( wd.wd_taDbAvg14 , wdd_taDbAvg14)
740- SETIF ( wd.wd_taDbAvg31 , wdd_taDbAvg31)
741- SETIF ( wd.wd_tGrnd , wdd_tGrnd);
742- SETIF ( wd.wd_tMains , wdd_tMains);
743- SETIF ( wd.wd_tdvElecPk , wdd_tdvElecPk);
744- SETIF ( wd.wd_tdvElecAvg , wdd_tdvElecAvg);
745- SETIF ( wd.wd_tdvElecPvPk , wdd_tdvElecPvPk);
746- SETIF ( wd.wd_tdvElecAvg01 ,wdd_tdvElecAvg01);
747- }
750+ wdHr[ iHr].wd_SetDayValuesIfMissing ( *this );
748751 }
749752#undef SETIF
750- } // WDDAY::wdd_Set
753+ } // WDDAY::wdd_Set24
754+ // -----------------------------------------------------------------------------
755+ void WDHR::wd_SetDayValues ( // set daily members
756+ const WDDAY& wdd) // source
757+ {
758+ wd_taDbPk = wdd.wdd_taDbPk ;
759+ wd_taDbAvg = wdd.wdd_taDbAvg ;
760+ wd_taDbPvPk = wdd.wdd_taDbPvPk ;
761+ wd_taDbAvg01 = wdd.wdd_taDbAvg01 ;
762+ wd_taDbAvg07 = wdd.wdd_taDbAvg07 ;
763+ wd_taDbAvg14 = wdd.wdd_taDbAvg14 ;
764+ wd_taDbAvg31 = wdd.wdd_taDbAvg31 ;
765+ wd_tGrnd = wdd.wdd_tGrnd ;
766+ wd_tMains = wdd.wdd_tMains ;
767+ wd_tdvElecPk = wdd.wdd_tdvElecPk ;
768+ wd_tdvElecAvg = wdd.wdd_tdvElecAvg ;
769+ wd_tdvElecPvPk = wdd.wdd_tdvElecPvPk ;
770+ wd_tdvElecAvg01= wdd.wdd_tdvElecAvg01 ;
771+ VCopy ( wd_tdvElecHrRank, 25 , wdd.wdd_tdvElecHrRank );
772+ } // WDHR::wd_SetDayValues
773+ // -----------------------------------------------------------------------------
774+ void WDHR::wd_SetDayValuesIfMissing ( // set missing daily members
775+ const WDDAY& wdd) // source
776+ {
777+ #define SETIF ( d, s ) if (IsMissing( d)) d = s;
778+ SETIF ( wd_taDbPk, wdd.wdd_taDbPk )
779+ SETIF ( wd_taDbAvg, wdd.wdd_taDbAvg )
780+ SETIF ( wd_taDbPvPk, wdd.wdd_taDbPvPk )
781+ SETIF ( wd_taDbAvg01, wdd.wdd_taDbAvg01 )
782+ SETIF ( wd_taDbAvg07, wdd.wdd_taDbAvg07 )
783+ SETIF ( wd_taDbAvg14, wdd.wdd_taDbAvg14 )
784+ SETIF ( wd_taDbAvg31, wdd.wdd_taDbAvg31 )
785+ SETIF ( wd_tGrnd, wdd.wdd_tGrnd )
786+ SETIF ( wd_tMains, wdd.wdd_tMains )
787+ SETIF ( wd_tdvElecPk, wdd.wdd_tdvElecPk )
788+ SETIF ( wd_tdvElecAvg, wdd.wdd_tdvElecAvg )
789+ SETIF ( wd_tdvElecPvPk, wdd.wdd_tdvElecPvPk )
790+ SETIF ( wd_tdvElecAvg01, wdd.wdd_tdvElecAvg01 )
791+ VCopy ( wd_tdvElecHrRank, 25 , wdd.wdd_tdvElecHrRank );
792+ #undef SETIF
793+ } // WDHR::wd_SetDayValuesIfMissing
794+ // ----------------------------------------------------------------------------
795+ void WDHR::wd_ShiftTdvElecHrRankForDST () // handle DST
796+ {
797+ for (int iHr=1 ; iHr<=24 ; iHr++)
798+ { if (++wd_tdvElecHrRank[ iHr] == 25 )
799+ wd_tdvElecHrRank[ iHr] = 1 ; // wrap
800+ }
801+ } // WDHR::wd_ShiftTdvElecHrRankForDST
751802// ============================================================================
752803
753804// ////////////////////////////////////////////////////////////////////////////
@@ -1504,10 +1555,11 @@ RC WFILE::wf_Read( // read and unpack weather data for an hour
15041555 // TODO: support partial weather years
15051556 if (wf_pWDY && !(erOp & (WF_FORCEREAD|WF_DSNDAY)))
15061557 { pwd->Copy ( wf_pWDY->wdy_Hr ( jDay, iHr), (erOp&WF_SAVESLRGEOM) != 0 );
1507- if ( iHr == 23 && (erOp& WF_DSTFIX) )
1558+ if (erOp & WF_DSTFIX)
15081559 { WDDAY& wdd = wf_pWDY->wdy_Day ( jDay+1 );
1509- pwd->wd_taDbPvPk = wdd.wdd_taDbPvPk ;
1510- pwd->wd_tdvElecPvPk = wdd.wdd_tdvElecPvPk ;
1560+ if (iHr == 23 )
1561+ pwd->wd_SetDayValues ( wdd);
1562+ pwd->wd_ShiftTdvElecHrRankForDST ();
15111563 }
15121564 return RCOK;
15131565 }
0 commit comments