diff --git a/src/ANCREC.CPP b/src/ANCREC.CPP index 0b267dda1..f87c35c87 100644 --- a/src/ANCREC.CPP +++ b/src/ANCREC.CPP @@ -93,8 +93,8 @@ record::record( BP _b, TI i, SI noZ/*=0*/) // construct record i of basAnc b, b->n++ : additional record in static array. CAUTION can be called from statSetup (til eliminated). */ - _b->validate("record::record"); // abort if base bad -- we depend on it for size - if (!noZ) // can be suppressed for data-init (static) records + _b->validate("record::record"); // abort if base bad -- we depend on it for size + if (!noZ) // can be suppressed for data-init (static) records memset( (char *)this+SZVFTP, 0, _b->eSz-SZVFTP); /* zero all members of DERIVED CLASS record except virtFcnTblPtr in 1st 2 or 4 bytes (ancrec.h define) */ b = _b; @@ -685,9 +685,9 @@ SI FC basAnc::ancNext( USI &an, BP * _b) // (registered) record anchor iterator //--------------------------------------------------------------------------------------------------------------------------- RC basAnc::validate( // validate an anchor: check self-consistency of anchor and its entry 0 - char *fcnName, // calling fcn name, for err msgs. - int erOp /*=ABT*/, // reporting control. ABT-->PABT, WRN-->PWRN here. - SI noStat /*=0*/ ) // 0: caller's action OK on static-storage anchor. nz: not ok. + const char* fcnName, // calling fcn name, for err msgs. + int erOp /*=ABT*/, // reporting control. ABT-->PABT, WRN-->PWRN here. + SI noStat /*=0*/ ) // 0: caller's action OK on static-storage anchor. nz: not ok. // if error, issues message, returns non-RCOK if not ABT { diff --git a/src/ANCREC.H b/src/ANCREC.H index f11560896..bc6363db2 100644 --- a/src/ANCREC.H +++ b/src/ANCREC.H @@ -108,7 +108,7 @@ class basAnc // base class for record anchors: basAnc static BP FC anc4n( USI an, int erOp=ABT); // access anchor by anchor # static RC FC findAnchorByNm( char *what, BP *b); static SI FC ancNext( USI &an, BP *_b); // iterate anchors - RC validate( char *fcnName, int erOp=ABT, SI noStat=0); // check for valid anchor + RC validate( const char* fcnName, int erOp=ABT, SI noStat=0); // check for valid anchor RC findRecByNm1( const char* _name, TI *_i, record **_r); // find record by 1st match on name RC findRecByNmU( const char* _name, TI *_i, record **_r); // find record by unique name match RC findRecByNmO( const char* _name, TI ownTi, TI *_i, record **_r); // find record by name and owner subscript diff --git a/src/CGCOMP.CPP b/src/CGCOMP.CPP index 0cf05d7e0..850c07bf7 100644 --- a/src/CGCOMP.CPP +++ b/src/CGCOMP.CPP @@ -1638,6 +1638,12 @@ RSYS* DUCTSEG::ds_GetRSYS() const return pRS; } // DUCTSEG::ds_GetRSYS //----------------------------------------------------------------------------- +bool DUCTSEG::ds_IsRound() const +{ // if ds_exArea is input, assume flat area-only model + // else round + return !IsSet( DUCTSEG_EXAREA); +} // DUCTSEG::ds_IsRound +//----------------------------------------------------------------------------- RC DUCTSEG::ds_TopDS( // set up run record const DUCTSEG* pDSi) // input record // caller must allocate this (in DsR) @@ -1646,10 +1652,7 @@ RC DUCTSEG::ds_TopDS( // set up run record Copy( pDSi); // copy record, incl name, excl internal front overhead. - BOOL bRound = !IsSet( DUCTSEG_EXAREA); // if exterior area is specified - // assume flat config (no radius adj) - - if (bRound) + if (ds_IsRound()) { if (!IsSet( DUCTSEG_DIAM)) { if (ds_len > 0.f) ds_diam = ds_inArea / (kPi * ds_len); @@ -1698,7 +1701,7 @@ RC DUCTSEG::ds_TopDS( // set up run record ds_RconvIn = 0.4; // approx inside convection resistance, ft2-F/Btuh // derived per HOF correlations per typical diam, temp, vel if (rc == RCOK) - { if (bRound) + { if (ds_IsRound()) { // round configuration double diamOut = ds_diam + 2.*ds_insulThk; double diamRat = diamOut / ds_diam; // ratio of outside to inside diameter @@ -1744,6 +1747,35 @@ void DUCTSEG::ds_SetRunConstants() // set constants that do not vary during sim ZNR* zpx = ds_GetExZone(); // zone outside duct (NULL if none) ds_sbcO.sb_SetRunConstants( zpx); } // DUCTSEG::ds_SetRunConstants +//---------------------------------------------------------------------------- +#if 0 +RC DUCTSEG::ds_SetSizeFromAVF( // adjust diameter based on flow + float avf) // design air volume flow, cfm +{ + const RSYS* pRS = ds_GetRSYS(); + + // # of runs + int nR = pRS->rs_areaServed / ds_desAirVel; + + float avfPerRun = avf / ds_nDuctRun; + + float ductArea = avfPerRun / ds_airVelDs; + + ds_diam = 2.f * sqrt( ductArea / kPi); + + +} // DUCTSEG::ds_SetSizeFromAVF +//----------------------------------------------------------------------------- +int DUCTSEG::ds_GetDuctRunInfo( + float& runLen) // average run length, ft +// returns # of runs +{ + const RSYS* pRS = ds_GetRSYS(); + + // # of runs + int nR = max( 1, iRound( pRS->rs_areaServed / ds_CFAperRun)); +} // DUCTSEG::ds_GetRunInfo +#endif //----------------------------------------------------------------------------- RC DUCTSEG::ds_BegHour() { diff --git a/src/CGWTHR.CPP b/src/CGWTHR.CPP index 80fbfe73f..260bb30d2 100644 --- a/src/CGWTHR.CPP +++ b/src/CGWTHR.CPP @@ -54,24 +54,33 @@ void FC cgWthrClean( // cgwthr overall init/cleanup routine cgWfDone(); // close any open weather file // init weather file info record - Wfile.wf_Init(); // mbr function in wfpak.cpp sets record to say no file open - Wthr.wd_Init(); // mbr function in wfpak.cpp clears record - WthrNxHr.wd_Init(); // mbr function in wfpak.cpp clears record + Wfile.wf_Init(); // sets record to say no file open + Wthr.wd_Init(); // clears record + WthrNxHr.wd_Init(); // clears record // add any other init/cleanup found necessary or desirable } // cgWthrClean //--------------------------------------------------------------------------- -RC TOPRAT::tp_WfInit() // Initialize weather file. Displays any error messages. -// also uses: Top.tp_wfName [,.isDT] +RC TOPRAT::tp_WthrInit() // Initialize weather data/ display any error messages. +// also uses: tp_wfName, tp_TDVfName, [,.isDT] // returns non-RCOK if error, message already issued. { RC rc = Wfile.wf_Open( tp_wfName, tp_TDVfName); // open wthr file and option TDV file // init WFILE object, msg if error. if (!rc) - rc = Wfile.wf_FillWDYEAR( WRN); + rc = Wfile.wf_FillWDYEAR( WRN); // read/cache entire weather file + // TODO: handle partial years + + // design conditions + // set any derived values + // WHY here: location dependence, call after locinit + DESCOND* pDC; + RLUP( DcR, pDC) + rc |= pDC->dc_RunInit(); + return rc; -} // TOPRAT::tp_WfInit +} // TOPRAT::tp_WthrInit //--------------------------------------------------------------------------- RC TOPRAT::tp_WthrBegHour() // start-hour weather stuff: read file, set up public Wthr and Top members. // tp_WthrBegSubhr must also be called, after this function. @@ -345,7 +354,7 @@ RC WDHR::wd_WfReader( // read an hour's weather data and make adjustments int iHrST = Top.iHrST; // hour 0-23, standard time. int wfOp = WF_SAVESLRGEOM; // wf_Read(): do not overwrite solar geometry values if (Top.isDT) - wfOp |= WF_DSTFIX; // wf_Read(): taDbPvPk during daylight savings + wfOp |= WF_DSTFIX; // wf_Read(): handle day-transition values during DST RC rc = RCOK; // modify iHrST and jDayST as needed @@ -432,7 +441,7 @@ RC WDHR::wd_WfReader( // read an hour's weather data and make adjustments if (Top.tp_AuszWthrSource() == TOPRAT_COOLDSCOND) { // DSCOND design day: overwrite/adjust weather file values with generated int iDC = Top.tp_coolDsCond[ Top.tp_dsDayI-1]; - const DESCOND& DC = DCiB[ iDC]; + const DESCOND& DC = DcR[ iDC]; wd_FillFromDESCOND( DC, iHrST); } } @@ -517,7 +526,7 @@ RC WDHR::wd_WfReader( // read an hour's weather data and make adjustments rc = pWF->wf_Read( jDayST, iHrST, this, WRN|wfOp); // Read hour's data from weather file if (Top.tp_AuszWthrSource() == TOPRAT_COOLDSCOND) { int iDC = Top.tp_coolDsCond[ Top.tp_dsDayI-1]; - const DESCOND& DC = DCiB[ iDC]; + const DESCOND& DC = DcR[ iDC]; DC.dc_GenerateTemps( iHrST, this); } @@ -611,11 +620,12 @@ void WDHR::wd_FillFromDESCOND( // overwrite/adjust hourly data for design condi wd_taDbAvg14 += dbAvgDiff / 14.f; wd_taDbAvg31 += dbAvgDiff / 31.f; - wd_wndSpd = dc.dc_wndSpd; wd_wndDir = 0.f; - if (wd_sunup) + // derive irradiance + // note: tauB/tauD both 0 -> no solar + if (wd_sunup && dc.dc_tauB > 0.f && dc.dc_tauD > 0.f) wd_glrad = slASHRAETauModel( kPiOver2 - wd_slAlt, dc.dc_tauB, dc.dc_tauD, @@ -636,17 +646,107 @@ void WDHR::wd_FillFromDESCOND( // overwrite/adjust hourly data for design condi ///////////////////////////////////////////////////////////////////////////// RC DESCOND::dc_CkF() // check after input { RC rc = RCOK; - if (dc_MCWB > dc_DB) - rc |= oer( "dcMCWB (%g) must be <= dcDB (%g)", dc_MCWB, dc_DB); return rc; } // DESCOND::dc_CkF //----------------------------------------------------------------------------- -DOY DESCOND::dc_GetDOY() const +#if defined( _DEBUG) +static void DCTauTest( int doy) { - return dc_day; +float ebnlist[] = { 150.f, 200.f, 250.f, 300.f, -1.f }; +float edflist[] = { 20.f, 30.f, 40.f }; + + DESCOND dc( &DcR, 1); + dc.dc_doy = doy; + strcpy( dc.name, "Test"); + + for (int ib=0; ebnlist[ ib]>=0.f; ib++) + { dc.dc_ebnSlrNoon = ebnlist[ ib]; + for (int id=0; edflist[ id]>=0.f; id++) + { dc.dc_edhSlrNoon = edflist[ id]; + dc.dc_CheckFixSolar( 0); + } + } +} // DCTauTest +#endif +//------------------------------------------------------------------------------ +RC DESCOND::dc_RunInit() // init for run +// call after all input-time expressions have been evaluated +// call after locInit (re latitude dependency) +{ +#if defined( _DEBUG) +static int tested = 0; + if (!tested) + { DCTauTest( dc_doy); + tested++; + } +#endif -} // DESCOND::dc_GetDOY + RC rc = RCOK; + + if (dc_MCWB > dc_DB) + rc |= oer( "dcMCWB (%g) must be <= dcDB (%g)", dc_MCWB, dc_DB); + // if any solar values given, check and cross-derive + // else leave all 0 = no solar + if (dc_tauB + dc_tauD + dc_ebnSlrNoon + dc_edhSlrNoon > 0.f) + { int nTau = IsSetCount( DESCOND_TAUB, DESCOND_TAUD, 0); + int nE = IsSetCount( DESCOND_EBNSLRNOON, DESCOND_EDHSLRNOON, 0); + if (nTau == 0) + rc |= dc_CheckFixSolar( 0); // derive tauB / tauD + else if (nE == 0) + rc |= dc_CheckFixSolar( 1); // derive Ebn / Edh + else + rc |= oer( "must give either dcTauB/dcTauD and" + " not dcEbnSlrNoon/dcEdhSlrNoon or vice-versa"); + } + else + oInfo( "no irradiance due to dcTauB/dcTauD/dcEbnSlrNoon/dcEdhSlrNoon all 0"); + + return rc; +} // DESCOND::dc_RunInit +//----------------------------------------------------------------------------- +RC DESCOND::dc_CheckFixSolar( + int options) // option bits + // 0: derive tau from solar noon + // 1: derive solar noon from tau +{ + RC rc = RCOK; + + // solar noon angles + slday( dc_doy, SLTMSOLAR, 1); + float sunAlt, sunAzm; + slaltazm( 12.f, &sunAlt, &sunAzm); + float sunZen = kPiOver2 - sunAlt; + + if (options & 1) + { rc |= limitCheck( DESCOND_TAUB, .08, 1.) + | limitCheck( DESCOND_TAUD, 1.2, 3.2); + if (!rc) + slASHRAETauModel( sunZen, dc_tauB, dc_tauD, + dc_ebnSlrNoon, dc_edhSlrNoon); + } + else + { rc |= limitCheck( DESCOND_EBNSLRNOON, 0., 370.) + | limitCheck( DESCOND_EDHSLRNOON, 0., 110.); + if (!rc) + { bool ret = slASHRAETauModelInv( sunZen, dc_ebnSlrNoon, dc_edhSlrNoon, + dc_tauB, dc_tauD); + if (!ret) + rc = oer( "failed to derive dcTauB and dcTauD." + " Check dcEbnSlrNoon and dcEdhSlrNoon input values."); +#if defined( _DEBUG) + else + { float ebn, edh; + float egl = slASHRAETauModel( sunZen, dc_tauB, dc_tauD, ebn, edh); + if (frDiff( ebn, dc_ebnSlrNoon) > .01f + || frDiff( edh, dc_edhSlrNoon) > .01f) + oWarn( "ebn/edh mismatch"); + } +#endif + } + } + return rc; +} // DESCOND::dc_CheckFixSolar //----------------------------------------------------------------------------- void DESCOND::dc_GenerateTemps( int iHr, // hour of day (0 - 23) diff --git a/src/CNAUSZ.CPP b/src/CNAUSZ.CPP index 57ae854ee..c5096657b 100644 --- a/src/CNAUSZ.CPP +++ b/src/CNAUSZ.CPP @@ -105,7 +105,7 @@ const char* TOPRAT::tp_AuszDoing() const // current autosizing activity else { int auszDoy; if (iAWS == TOPRAT_COOLDSCOND) - auszDoy = DCiB[ tp_coolDsCond[ iDs]].dc_GetDOY(); + auszDoy = DcR[ tp_coolDsCond[ iDs]].dc_GetDOY(); else if (iAWS == TOPRAT_COOLDSDAY) auszDoy = tp_coolDsDay[ iDs]; if (auszDoy > 0) @@ -232,7 +232,7 @@ x tp_dsDay = 1 + (tp_dsDayI != 0); // 1st desDay is heating (1), others coolin auszMon = tp_date.month; } else if (tp_AuszWthrSource() == TOPRAT_COOLDSCOND) - { const DESCOND* pDC = DCiB.GetAtSafe( tp_coolDsCond[ tp_dsDayI-1]); + { const DESCOND* pDC = DcR.GetAtSafe( tp_coolDsCond[ tp_dsDayI-1]); jDay = pDC->dc_GetDOY(); tddyi( tp_date, jDay); auszMon = tp_date.month; diff --git a/src/CNCULT.CPP b/src/CNCULT.CPP index 0b43b0ba2..6ee52007a 100644 --- a/src/CNCULT.CPP +++ b/src/CNCULT.CPP @@ -117,7 +117,7 @@ makAncRI2(XiB,"export"); // EXPORT input info makAncCOL(RcoliB); // REPORTCOL input info for UDT reports makAncCOL2(XcoliB,"exportCol"); // EXPORTCOL input info for UDT exports makAncIMPF(ImpfiB); // IMPORTFILE input info, 2-94 -// holidays + makAncHDAY(HdayiB); // HDAY input info makAncDESCOND(DCiB); // DESCOND input info @@ -1544,11 +1544,20 @@ RC DUCTSEG::ds_Ckf() RC rc=RCOK; if (IsSet( DUCTSEG_EXAREA)) - { rc |= disallow( DUCTSEG_INAREA, "when dsExArea is given"); - ignoreN( "when dsExArea is given", DUCTSEG_DIAM, DUCTSEG_LEN, 0); + { // flat configuration: area is fixed + rc |= disallow( DUCTSEG_INAREA, "when dsExArea is given"); + ignoreN( "when dsExArea is given", DUCTSEG_DIAM, DUCTSEG_LEN, + DUCTSEG_BRANCHCOUNT, DUCTSEG_BRANCHLEN, DUCTSEG_BRANCHCFA, DUCTSEG_AIRVELDS, 0); } else - { int dimCount = IsSet( DUCTSEG_DIAM) + IsSet( DUCTSEG_LEN) + IsSet( DUCTSEG_INAREA); + { // round: many interdependent defaults + // # of branches: user-input branch count takes precedence + if (IsSet( DUCTSEG_BRANCHCOUNT)) + ignore( DUCTSEG_BRANCHCFA, "when dsBranchCount is given"); + if (IsSet( DUCTSEG_BRANCHLEN)) + rc |= disallow( DUCTSEG_LEN, "when dsBranchLen is given"); + + int dimCount = IsSet( DUCTSEG_DIAM) + IsSet( DUCTSEG_LEN) + IsSet( DUCTSEG_INAREA); if (dimCount == 3) rc |= oer( "at most 2 of dsDiameter, dsLength, and dsInArea are allowed"); } @@ -1595,10 +1604,14 @@ static CULT dsT[] = //------ DUCTSEG cmd RAT Entry table, used from RSys CULT( "*", STAR, 0, 0, 0, 0, 0, 0, 0.f, N, &dsStarCkf), CULT( "dsRSys", DAT, DUCTSEG_OWNTI, NO_INP|RDFLIN,0,0, TYREF, &RSiB, 0, N, N), CULT( "dsTy", DAT, DUCTSEG_TY, RQD, 0, VEOI, TYCH, 0, -1, N, N), +CULT( "dsBranchLen", DAT, DUCTSEG_BRANCHLEN,0,0, VEOI, TYFL, 0, -1.f, N, N), +CULT( "dsBranchCount",DAT, DUCTSEG_BRANCHCOUNT,0,0,VEOI, TYSI, 0, -1, N, N), +CULT( "dsBranchCFA", DAT, DUCTSEG_BRANCHCFA,0,0, VEOI, TYFL, 0, -1, N, N), +CULT( "dsAirVelDs", DAT, DUCTSEG_AIRVELDS, 0,0, VEOI, TYFL, 0, -1.f, N, N), CULT( "dsExArea", DAT, DUCTSEG_EXAREA,0, 0, VEOI, TYFL, 0, 0.f, N, N), CULT( "dsInArea", DAT, DUCTSEG_INAREA,0, 0, VEOI, TYFL, 0, 0.f, N, N), CULT( "dsDiameter", DAT, DUCTSEG_DIAM, 0, 0, VEOI, TYFL, 0, 0.f, N, N), -CULT( "dsLength", DAT, DUCTSEG_LEN, 0, 0, VEOI, TYFL, 0, 0.f, N, N), +CULT( "dsLength", DAT, DUCTSEG_LEN, 0, 0, VEOI, TYFL, 0, 0.f, N, N), CULT( "dsExCnd", DAT, DUCTSEG_EXCND, 0, 0, 0, TYCH, 0, C_EXCNDCH_ADJZN, N, N), CULT( "dsAdjZn", DAT, DSBC( ZI), 0, 0, VEOI, TYREF, &ZiB, 0.f, N, N), CULT( "dsExT", DAT, DSBC( TXA), 0, 0, VSUBHRLY, TYFL, 0, 70.f, N, N), @@ -2420,15 +2433,19 @@ static CULT dcT[] = //---------- ----- --------------- ------- -- ------ ------ ---- ---------- ---- ---- CULT( "*", STAR, 0, 0, 0, 0, 0, 0, 0.f, N, dcStarCkf), -CULT( "dcDay", DAT, DESCOND_DAY, RQD, 0, VEOI, TYDOY, 0, 200, N, N), +CULT( "dcDay", DAT, DESCOND_DOY, RQD, 0, VEOI, TYDOY, 0, 200, N, N), CULT( "dcDB", DAT, DESCOND_DB, RQD, 0, VEOI, TYFL, 0, 0.f, N, N), CULT( "dcMCDBR", DAT, DESCOND_MCDBR, RQD, 0, VEOI, TYFL, 0, 0.f, N, N), CULT( "dcMCWB", DAT, DESCOND_MCWB, RQD, 0, VEOI, TYFL, 0, 0.f, N, N), CULT( "dcMCWBR", DAT, DESCOND_MCWBR, RQD, 0, VEOI, TYFL, 0, 0.f, N, N), CULT( "dcWindSpeed",DAT, DESCOND_WNDSPD, RQD, 0, VEOI, TYFL, 0, 0.f, N, N), -CULT( "dcTauB", DAT, DESCOND_TAUB, RQD, 0, VEOI, TYFL, 0, 0.f, N, N), -CULT( "dcTauD", DAT, DESCOND_TAUD, RQD, 0, VEOI, TYFL, 0, 0.f, N, N), +// Taub/Taud and Ebn/Ebh interact, see dc_TopDC +CULT( "dcTauB", DAT, DESCOND_TAUB, 0, 0, VEOI, TYFL, 0, 0.f, N, N), +CULT( "dcTauD", DAT, DESCOND_TAUD, 0, 0, VEOI, TYFL, 0, 0.f, N, N), +CULT( "dcEbnSlrNoon",DAT, DESCOND_EBNSLRNOON,0, 0, VEOI, TYFL, 0, 0.f, N, N), +CULT( "dcEdhSlrNoon",DAT, DESCOND_EDHSLRNOON,0, 0, VEOI, TYFL, 0, 0.f, N, N), + CULT( "endDesCond", ENDER, 0, 0, 0, 0, 0, 0, 0.f, N, N), CULT() diff --git a/src/CNCULT2.CPP b/src/CNCULT2.CPP index 6f7bda622..d24a5d635 100644 --- a/src/CNCULT2.CPP +++ b/src/CNCULT2.CPP @@ -59,7 +59,8 @@ LOCAL RC topCon2(); LOCAL RC topGt(); LOCAL RC topMtr(); LOCAL RC topGain(); -LOCAL RC topRSys(); +LOCAL RC topRSys1(); +LOCAL RC topRSys2(); LOCAL RC topDHW(); LOCAL RC topPV(); LOCAL RC topBT(); @@ -316,6 +317,7 @@ LOCAL RC topCkfI( // finish/check/set up inner function E( topMsCon()) // mass & masstype stuff between topSf1 and 2. cncult3.cpp E( topSg() ) // sgdists: do after windows pass 1. sets gz.sgdist[]: do b4 topSf2( , WINDOW). cncult3. E( topSh() ) // shades: do after windows pass 1. sets gz.x.iwshad: do b4 topSf2( , WINDOW). cncult3. + E( topRSys1() ) // RSYS basic setup: before TopDs E( topDs() ) // duct segments: before topZn2 E( topZn2() ) // zones: accum total surf areas etc. E( topSf2() ) // surfs pass 2: make XSRATs and MSRATs. @@ -324,7 +326,7 @@ LOCAL RC topCkfI( // finish/check/set up inner function E( topGain() ) // check gains / copy to run rat. local fcn. E( topRadGainDist() ) // set up distribution of radiant internal gains. Must follow most surface/zone stuff - E( topRSys() ) // RSYS + E( topRSys2() ) // RSYS final setup E( topPV() ) // PVArrays E( topBT() ) // Batteries E( topSX() ) // ShadeX external shading @@ -813,9 +815,8 @@ const char* TOPRAT::When( IVLCH ivl) const // date / time doc for error message return s; } // TOPRAT::When //----------------------------------------------------------------------------- -LOCAL RC topDC() // finalize DESCONDs -{ RC rc = RCOK; - // input records used at runtime, nothing to do +LOCAL RC topDC() // copy input DESCONDs to run records +{ RC rc = DcR.RunDup( DCiB); return rc; } // topDC //----------------------------------------------------------------------------- @@ -1367,7 +1368,7 @@ LOCAL RC topMtr() // check METERs / copy to run rat. Create sum-of-meters recor return rc; } // topMtr //----------------------------------------------------------------------------- -LOCAL RC topRSys() // check RSYS / copy to run rat +LOCAL RC topRSys1() // check RSYS / copy to run rat { RC rc = RCOK; E( RsR.al( RSiB.n, WRN) ) // delete old records, alloc to needed size now for min fragmentation @@ -1377,11 +1378,21 @@ LOCAL RC topRSys() // check RSYS / copy to run rat { RSYS* pRS; RsR.add( &pRS, ABT, pRSi->ss); // add run RSYS record. error not expected due to preceding al. *pRS = *pRSi; // copy input record to run record including name - rc |= pRS->rs_TopRSys(); + rc |= pRS->rs_TopRSys1(); } } return rc; -} // ::topRSys +} // ::topRSys1 +//----------------------------------------------------------------------------- +LOCAL RC topRSys2() // additional RSYS check / setup +{ + RC rc = RCOK; + RSYS* pRS; + // loop run records (added by topRSys2()) + RLUP( RsR, pRS) + rc |= pRS->rs_TopRSys2(); + return rc; +} // ::topRSys2 //============================================================================= LOCAL RC topDHW() // check DHWSYS/DHWHEATER ... copy to run rat { diff --git a/src/CNCULT3.CPP b/src/CNCULT3.CPP index ee51558e2..75cf80b6a 100644 --- a/src/CNCULT3.CPP +++ b/src/CNCULT3.CPP @@ -982,9 +982,9 @@ RC FC topSh() // SHADE processing at RUN // make SHADE run record, put its subscript in window.x.iwshad - E( WshadR.add( &shr, WRN) ) // add shade run record, return if error - *shr = *sh; // copy record data (except internal overhead), ancrec.cpp. - gz->x.iwshad = shr->ss; // WSHADRAT subscript to XSURF + E( WshadR.add( &shr, WRN) ) // add shade run record, return if error + *shr = *sh; // copy record data (except internal overhead), ancrec.cpp. + gz->x.iwshad = shr->ss; // WSHADRAT subscript to XSURF } return rc; } // topSh @@ -1189,10 +1189,6 @@ RC topZn2() // accumulate surface totals etc RLUP( ZrB, zp) { zp->zn_FinalizeSurfTotals(); zp->zn_RadX(); // set F and Fp values for air and surfaces -#if 0 // moved to topZn3(), 8-19-2013 -x zp->zn_AddIZXFERs(); // add internally-generated IZXFERs re -x // AIRNET modeling of duct leakage and system air -#endif } return rc; diff --git a/src/CNGLOB.H b/src/CNGLOB.H index e45644270..7e2947bde 100644 --- a/src/CNGLOB.H +++ b/src/CNGLOB.H @@ -231,6 +231,8 @@ template< typename T, typename TX> inline T setToMinOrMax( T &a, TX b, int doMin // return -1, 0, or 1 per value of v template< typename T> T xsign( T v) { return v==0 ? 0 : v>0 ? 1 : -1; } +// return -1 if <, 0 if == , or 1 if > +template< typename T> int LTEQGT( T v1, T v2) { return v1>v2 ? 1 : v1 inline T bracket( T vMin, T v, T vMax) @@ -405,9 +407,9 @@ const int NOSCRN = 0x0400; // logit: do not also display on screen const int QUIETIF= 0x0800; // screen: do not display if zn screenQuiet (rmkErr.cpp) -/* application option bits in same argument word as error action. - Options for specific functions are defined in other .h files in terms of - the following ---------- users include ------ */ +// application option bits in same argument word as error action. +// Options for specific functions are defined in other .h files in terms of +// the following ---------- users include ------ const int EROP1 = 0x010000; // vrpak.h dmpak.h xiopak.h [ratpak.h] const int EROP2 = 0x020000; // vrpak.h dmpak.h [xiopak.h] sytb.cpp const int EROP3 = 0x040000; // vrpak.h wfpak.h [xiopak.h] diff --git a/src/CNGUTS.CPP b/src/CNGUTS.CPP index a39508343..7d1e36d63 100644 --- a/src/CNGUTS.CPP +++ b/src/CNGUTS.CPP @@ -208,7 +208,7 @@ void FC runFazDataFree() // Note: entries are put into most of these in input code in cncult2.cpp:topCkf and its subfcns. - ZrB.free(); // Zones runtime info. basAnc::free is in lib\ancrec.cpp. + ZrB.free(); // Zones runtime info ZnresB.free(); // zone simulation results RSysResR.free(); // RSYS results IzxR.free(); // interzone transfers @@ -925,9 +925,10 @@ RC FC cgRddInit( // Perform initialization common to main simulation run and eac // inits Locsolar (comments below) // EF: return RCBAD on any non-RCOK return. -// Set up weather file -// do each phase, allowing name to change. Messages errors. - EF( Top.tp_WfInit() ) // also uses Top .tp_wfName, .skyModel [,.isDT]. EF: return RCBAD if error. +// Set up weather file, TDV file, and DESCONDs +// Do each phase, allowing file or location changes. +// Messages errors. + EF( Top.tp_WthrInit() ) // also uses Top .tp_wfName, .skyModel [,.isDT] // Open import files used in this run, if any EF( impfStart() ) // impf.cpp. related code: cncult4.cpp, cuparse.cpp. @@ -2503,7 +2504,7 @@ LOCAL void FC NEAR binResInit( int isAusz) // initialize & open binary results ( /* ***** TEMPORARY weather file info for initial DL test graphs ***** 9-4-94 Make names match values passed to setHourInfo() in doIvlAccum()! Expect will depend on wf type. - Coordinate via tp_WfInit (xxx called in this fcn about 100 lines up) ***** */ + Coordinate via tp_WthrInit(xxx called in this fcn about 100 lines up) ***** */ #ifdef TWOWV // bfr.h 9-94 2, "Est Direct", "Est Diffuse" ) ) // # dl weather vbls and their names. Estimated from CEC wthr file for now. #else @@ -2555,15 +2556,15 @@ static SLLOCDAT* NEAR Locsolar = NULL; /* Ptr to solar info structure (slpak.h) Daily info set by slpak:slday from cgwthr.cpp and cgsolar.cpp at least, 1-95. */ //------------------------------------------------------------------------ LOCAL RC FC NEAR locInit() // location-initializer for cne -// inits lib\slpak.cpp using location info in Top members (gotten weather file and/or user input in cncultx.cpp) +// inits slpak.cpp using location info in Top members (gotten weather file and/or user input in cncultx.cpp) // returns RCOK if ok, else message already issued. { -/* init lib\slpak.cpp: alloc SLLOCDAT (slpak.h) and init for location. - More of Locsolar is set each day by slday(). It is used by most other slpak calls. - slpak remembers its location internally. */ +// init slpak.cpp: alloc SLLOCDAT (slpak.h) and init for location. +// More of Locsolar is set each day by slday(). It is used by most other slpak calls. +// slpak remembers its location internally. Locsolar = slinit( RAD( Top.latitude), // latitude (to radians) - RAD( Top.longitude), // longitude + RAD( Top.longitude), // longitude Top.timeZone, // time zone Top.elevation ); // site altitude (ft) return RCOK; diff --git a/src/CNGUTS.H b/src/CNGUTS.H index f7cdf474d..8f913ffeb 100644 --- a/src/CNGUTS.H +++ b/src/CNGUTS.H @@ -113,8 +113,7 @@ extern anc WthrR; // basAnc for hour's weather data record. Runtime onl extern WFDATA Wthr; // the one static WFDATA record containing unpacked & adjusted data for hour 1-94 extern anc WthrNxHrR; // basAnc for next hour's weather data record ("weatherNextHour") extern WFDATA WthrNxHr; // static record for next hour's unpacked & adjusted data for cgwthr.cpp read-ahead - -extern anc DCiB; // design conditions (input records only) +extern anc DcR; // design conditions extern anc ZrB; // zones runtime info extern anc ZnresB; // Zones simulation results info diff --git a/src/CNLOADS.CPP b/src/CNLOADS.CPP index 848a4b724..2c8ab569e 100644 --- a/src/CNLOADS.CPP +++ b/src/CNLOADS.CPP @@ -1613,7 +1613,7 @@ x rs_capAuxH = 100000.f; return rc; } // RSYS::rs_CkF //----------------------------------------------------------------------------- -RC RSYS::rs_TopRSys() // check RSYS, set up for run +RC RSYS::rs_TopRSys1() // check RSYS, initial set up for run { RC rc = RCOK; @@ -1641,8 +1641,24 @@ RC RSYS::rs_TopRSys() // check RSYS, set up for run rs_fxCapHAsF = 1.4f; } - DUCTSEG* ds; + // loop all zones served by this RSYS + rs_areaServed = 0.; + rs_zonesServed = 0; ZNR* zp; + RLUP( ZrB, zp) + { if (rs_IsZoneServed( zp)) + { rs_areaServed += zp->i.znArea; + rs_zonesServed++; + } + } + return rc; +} // RSYS::rs_TopRSys1 +//----------------------------------------------------------------------------- +RC RSYS::rs_TopRSys2() // final set up for run +{ + RC rc = RCOK; + + DUCTSEG* ds; memset( rs_ducts, 0, sizeof( rs_ducts)); RLUP( DsR, ds) { ds->ds_SetRunConstants(); @@ -1673,23 +1689,12 @@ RC RSYS::rs_TopRSys() // check RSYS, set up for run } } - // if () determine unbalanced - - // loop all zones served by this RSYS - rs_areaServed = 0.; - rs_zonesServed = 0; - RLUP( ZrB, zp) - { if (rs_IsZoneServed( zp)) - { rs_areaServed += zp->i.znArea; - rs_zonesServed++; - } - } if (rc == RCOK) rs_SetRunConstants(); - return RCOK; -} // RSYS::rs_TopRSys + return rc; +} // RSYS::rs_TopRSys2 //----------------------------------------------------------------------------- RC RSYS::rs_FazInit( // init before autosize (once) and main sim int isAusz) // TRUE = autosize, FALSE = main simulation @@ -2473,6 +2478,18 @@ RC RSYS::rs_SetupCapC( // derive constants that depend on capacity } // RSYS::rs_SetupCapC //---------------------------------------------------------------------------- +#if 0 +RC RSYS::rs_SetDuctSizes() +{ + for (int iSR=0; iSR<2; iSR++) + { int iDS = rs_Dsi( iSR); + if (iDS > 0) + { DUCTSEG* pDS = DsR[ iDS]; + } + } +} +#endif +//---------------------------------------------------------------------------- int RSYS::rs_IsAutoSizing() const // returns rsmOFF, rsmHEAT, or rsmCOOL { diff --git a/src/CNRECS.DEF b/src/CNRECS.DEF index d0e20e9d5..aa621ddb8 100644 --- a/src/CNRECS.DEF +++ b/src/CNRECS.DEF @@ -138,7 +138,7 @@ RECORD TOPRAT "top" *RAT /* top level RAT: contains control info and all once-on *declare "RC tp_SetDerived();" *declare "void tp_ClearAuszFlags();" *declare "RC tp_Wfile( int* pHotMo);" - *declare "RC tp_WfInit();" + *declare "RC tp_WthrInit();" *declare "int tp_AuszWthrSource() const;" *declare "RC tp_MainSim();" *declare "RC tp_MainSimI();" @@ -733,13 +733,17 @@ RECORD WDHR "wfdata sub" *SUBSTRUCT // hourly data substructure for WFDATA *declare "RC wd_TDVReadHr( WFILE* pWF, int jHr, int erOp=WRN);" *declare "RC wd_EPWReadHr( WFILE* pWF, int jHr, int erOp=WRN);" *declare "void wd_FillFromDESCOND( const DESCOND& dc, int iHr);" + *declare "void wd_SetDayValues( const class WDDAY& wdd);" + *declare "void wd_SetDayValuesIfMissing( const class WDDAY& wdd);" + *declare "void wd_ShiftTdvElecHrRankForDST();" // wd_sunup, wd_slAzm, wd_slAlt MUST BE BEFORE wd_db // wd_db assumed 1st non-solar geometry mbr // re preservation of solar geometry info, see Copy() *h INT wd_sunup; // nz if sun is up for any portion of current hour // solar position at midpoint of hour (or portion of hour sun is up) - *h float wd_slAzm; // azmimuth, radians (0=N, +clockwise) + *h float wd_slAzm; // azimuth, radians (0=N, +clockwise) + // NOTE: code assumes wd_slAzm is 1st float *h float wd_slAlt; // altitude, radians (0=horizon, +upwards) *h float wd_db // air dry bulb temp, deg F @@ -759,6 +763,11 @@ RECORD WDHR "wfdata sub" *SUBSTRUCT // hourly data substructure for WFDATA *h float wd_tMains // cold water mains temp, F // computed using CEC ACM method + // time-of-day fuel values, units = TDV/Btu + // values are read from optional TDV file + *h float wd_tdvElec // electricity + *h float wd_tdvFuel // fuel + // derived (computed) drybulb temp values // values change at day beg / same all day *h float wd_taDbPk // current day peak DB (includes future hours), F @@ -769,11 +778,6 @@ RECORD WDHR "wfdata sub" *SUBSTRUCT // hourly data substructure for WFDATA *h float wd_taDbAvg14 // trailing 14-day avg DB (not including current day), F *h float wd_taDbAvg31 // trailing 31-day avg DB (not including current day), F - - // time-of-day fuel values, units = TDV/Btu - // values are read from optional TDV file - *h float wd_tdvElec // electricity - *h float wd_tdvFuel // fuel // derived (computed) electricity TDV values // values change at day beg / same all day @@ -781,6 +785,12 @@ RECORD WDHR "wfdata sub" *SUBSTRUCT // hourly data substructure for WFDATA *h float wd_tdvElecAvg // current day avg TDVelec (includes future hours) *h float wd_tdvElecPvPk // previous-day peak TDVelec *h float wd_tdvElecAvg01 // previous-day avg TDVelec (not including current day) + // NOTE: code assumes wd_tdvElecAvg01 is last float + *h *ARRAY 25 SI wd_tdvElecHrRank // hour ranking of TDV values + // [ 0]=unused + // [ 1]=hour of highest tdvElec, 1-24 + // [ 2]=hour of 2nd highest + // etc *END // WDHR //======================================================================================================== @@ -800,24 +810,27 @@ RECORD WFDATA "weather" *RAT // hourly weather data, one static instance "Wthr", RECORD DESCOND "DESCOND" *RAT // cooling design conditions *prefix dc_ *declare "RC dc_CkF();" - *declare "DOY dc_GetDOY() const;" + *declare "DOY dc_GetDOY() const { return dc_doy; }" + *declare "RC dc_RunInit();" + *declare "RC dc_CheckFixSolar( int options);" *declare "void dc_GenerateTemps( int iHr, float astCor, float& db, float& wb, float& dbAvg) const;" - *i DOY dc_day; // calc date for this DESCOND + *i DOY dc_doy; // calc date for this DESCOND (1-365) *i FLOAT dc_DB; // design dry-bulb temp, F *i FLOAT dc_MCDBR; // coincident daily db range, F *i FLOAT dc_MCWB; // coincident wet-bulb temp, F *i FLOAT dc_MCWBR; // coincident daily wb range, F - *i FLOAT dc_wndSpd; // wind speed, mph - *i FLOAT dc_tauB; // beam tau - *i FLOAT dc_tauD; // diffuse tau + // if omitted, constant dewpoint limited by saturation + *i FLOAT_GEZ dc_wndSpd; // wind speed, mph - // float dcGrRfl; // default ground reflectivity (0-1) - // CWString sDirRad; // schedule ID for direct solar on normal surface (W/m2) - // for testing, "" = use modelled - // CWString sDifRad; // schedule ID for diffuse solar on horiz surface (W/m2) - // for testing, "" = use modelled + // parameters for ASHRAE clear sky model + // if taub/d provided, ebn/edh derived else reverse + // if all 0, solar is 0 all hours + *i FLOAT_GEZ dc_tauB; // beam tau + *i FLOAT_GEZ dc_tauD; // diffuse tau + *i FLOAT_GEZ dc_ebnSlrNoon; // solar noon beam normal, Btuh/ft2 + *i FLOAT_GEZ dc_edhSlrNoon; // solar noon diffuse horiz, Btuh/ft2 *END // DESDAY //======================================================================================================== @@ -2773,8 +2786,10 @@ RECORD DUCTSEG "DuctSeg" *RAT // duct segment *declare "ZNR* ds_GetExZone() const;" *declare "RSYS* ds_GetRSYS() const;" *declare "RC ds_Ckf();" +*declare "bool ds_IsRound() const;" *declare "RC ds_TopDS( const DUCTSEG* pDSi);" *declare "void ds_SetRunConstants();" +*declare "RC ds_SetSizeFromAVF( float avf);" *declare "double ds_InsulK( float T) const { return ds_insulKA + ds_insulKB * T; }" *declare "int ds_IsSupply() const { return ds_ty == C_DUCTTYCH_SUP; }" *declare "RC ds_BegHour();" @@ -2790,10 +2805,18 @@ RECORD DUCTSEG "DuctSeg" *RAT // duct segment // represents coupling(s) between duct exterior // surface and adjacent zone or ambient -*i FLOAT ds_exArea // exterior heat transfer surface area, ft2 (outside of insulation) +*i FLOAT_GEZ ds_exArea // exterior heat transfer surface area, ft2 (outside of insulation) + // if input, flat area-only model is used, many inputs have no effect + // if NOT input, round ducts assumed *i FLOAT_GZ ds_diam // duct diameter (w/o insulation), ft -*i FLOAT_GEZ ds_len // segment length, ft +*i FLOAT_GEZ ds_len // total length (all branches), ft +*r FLOAT_GZ ds_branchLen // average branch length, ft +*i SI_GZ ds_branchCount // # of branches +*i FLOAT_GZ ds_branchCFA // floor area served per per branch, ft2 + // used re default ds_branchCount +*i FLOAT_GZ ds_airVelDs // design air velocity, fpm + // re flow-based sizing *i FLOAT_GEZ ds_inArea // interior surface area, ft2 // = inside wetted area / duct surf area w/o insulation @@ -2845,14 +2868,15 @@ RECORD DUCTSEG "DuctSeg" *RAT // duct segment *END // DUCTSEG //============================================================================= -RECORD RSYS "RSYS" *RAT // residential system +RECORD RSYS "RSYS" *RAT // residential HVAC system *prefix rs_ // *excon // explicit constructor *exdes // explicit destructor *ovrcopy *declare "RC rs_CkF();" -*declare "RC rs_TopRSys();" +*declare "RC rs_TopRSys1();" +*declare "RC rs_TopRSys2();" *declare "int rs_IsZoneServed( const ZNR* zp) const { return zp->i.zn_rsi == ss; }" *declare "RC rs_FazInit( int isAusz);" *declare "RC rs_RddInit( int isAusz);" @@ -2873,6 +2897,7 @@ RECORD RSYS "RSYS" *RAT // residential system *declare "RC rs_SetupCapH( float avfH=-1.f, int options=0);" *declare "void rs_SetupFanC( float avfC=-1.f);" *declare "RC rs_SetupCapC( float avfC=-1.f, int options=0);" +*declare "RC rs_SetDuctSizes();" *declare "void rs_SetModeAndClear( int rsModeNew);" *declare "RC rs_BegHour();" *declare "RC rs_BegSubhr();" diff --git a/src/CSE.vcxproj b/src/CSE.vcxproj index 9a6ac2864..a7bfcb80b 100644 --- a/src/CSE.vcxproj +++ b/src/CSE.vcxproj @@ -459,7 +459,9 @@ - + + false + diff --git a/src/CSE.vcxproj.filters b/src/CSE.vcxproj.filters index 0d5f79abb..cb97872cd 100644 --- a/src/CSE.vcxproj.filters +++ b/src/CSE.vcxproj.filters @@ -1,418 +1,204 @@ - - + + - - {a47f0fc4-3e1b-4cb6-bd89-20bca56d5684} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp - - - {85fcb70e-52db-432e-9cc1-fd25982093d7} - ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - {d7518ddd-5458-47b2-8a13-b1bc3a0d940d} - h;hpp;hxx;hm;inl;fi;fd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + + Source Files - + Source Files - + Source Files - + + + + + + + + + + + + + + + + + + + + + + + + + + + + Source Files - + + + + + + + + Source Files - + + Source Files - + + + + Source Files - + + + + + + + Source Files - + + + + Source Files - + + + + + Source Files - + Source Files - + + + + + Source Files - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + + + + Source Files + - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + Header Files - - Header Files + + + + + + + + CMake Rules - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {3AEEECE5-8E85-327D-B162-4253EA4B668F} + + + {96755E86-A021-3FFF-8C55-001847EF5D41} + + + {5DDD9D10-605A-30FA-9CBF-42E2A941212E} + + + diff --git a/src/RUNDATA.CPP b/src/RUNDATA.CPP index b0b3721cc..8a2dedced 100644 --- a/src/RUNDATA.CPP +++ b/src/RUNDATA.CPP @@ -66,6 +66,8 @@ WFDATA Wthr( (anc *)&WthrR, 0); // record containing current hour's wea makAncWFDATA2( WthrNxHrR,"weatherNextHour"); // basAnc for... WFDATA WthrNxHr( (anc *)&WthrNxHrR, 0); // record containing current next hour's weather data, // extracted and adjusted, for cgWthr.cpp read-ahead +makAncDESCOND( DcR); // design conditions + // zones, transfers, gains, meters makAncZNR( ZrB); // Zones runtime info: input set in cncult. makAncZNRES( ZnresB); // Month and year simulation results for zones diff --git a/src/SLPAK.CPP b/src/SLPAK.CPP index b936b6e95..edf2e9b25 100644 --- a/src/SLPAK.CPP +++ b/src/SLPAK.CPP @@ -361,6 +361,9 @@ void FC slday( // set up daily data in current SLLOCDAT /* sets members re declination of earth's axis, time / hour angle conversion (.tmconst), hourly sunupf[], dircos[], slazm[], etc. */ { + if (!slloccur) + err( PABT, "NULL slloccur"); + if ((options&1) && slloccur->doy == doy && slloccur->timetype == timetype) return; // already set for doy @@ -828,10 +831,9 @@ void FC slaniso( /* Adjust beam and diffuse radiation values #include "ASHRAE/solar.cpp" - float slASHRAETauModel( // ASHRAE "tau" clear sky model float sunZen, // solar zenith angle, radians - float tauB, // ASHRAE beam "pseudo optical depth" (from database) + float tauB, // ASHRAE beam "pseudo optical depth" float tauD, // ditto diffuse float& radDirN, // returned: direct normal irradiance, units per extBm float& radDifH) // returned: diffuse horizontal irradiance, units per extBm @@ -842,8 +844,83 @@ float slASHRAETauModel( // ASHRAE "tau" clear sky model return ASHRAETauModel( // ASHRAE "tau" clear sky model 1, extBm, sunZen, tauB, tauD, radDirN, radDifH); +} // slASHRAETauModel +//----------------------------------------------------------------------------- +static bool slASHRAETauModelInv( // derive tauB/tauD from irradiance + double Ebn, // beam normal irradiance (at m) + double Edh, // diffuse horizontal irradiance (at m) + double E0, // exterrestrial normal irradiance + double m, // air mass, dimless + double& tauB, // returned + double& tauD) // returned +// Ebn, Edh, and E0 should have same units +// Based on Python implementation by Michael Roth +// ASHRAE 2017 coefficients implicit +{ + double Kb = Ebn/E0; + double Kd = Edh/E0; + + double logm = log( m); + double loglogKb = log( log(1.0/Kb)); + double loglogKd = log( log(1.0/Kd)); + double tol = 1e-8; + + // First guess + tauB = 0.75; + tauD = 1.5; + + bool bConverge = false; + for (int iT=0; iT<20 && !bConverge; iT++) + { // update ab & ad + double ab = 1.454 -0.406*tauB -0.268*tauD +0.021*tauB*tauD; + double ad = 0.507 +0.205*tauB -0.080*tauD -0.190*tauB*tauD; + + // Calculate F + // Note: Took log twice of equations (17) and (18). F is the + // difference between LHS & RHS. We want F to approach zero. + double Fb = log(tauB) + ab*logm - loglogKb; + double Fd = log(tauD) + ad*logm - loglogKd; + + // calculate Jacobian + double Jbb = 1.0/tauB + logm*(-0.406 +0.021*tauD); + double Jbd = logm*(-0.268 + 0.021*tauB); + double Jdb = logm*(+0.205 - 0.190*tauD); + double Jdd = 1.0/tauD + logm*(-0.080 -0.190*tauB); + + // solve system {-F} = [J]{dtau} using Cramer's rule + double detJ = Jbb*Jdd - Jdb*Jbd; + double dtauB = (-Fb*Jdd + Fd*Jbd)/detJ; + double dtauD = (-Jbb*Fd + Jdb*Fb)/detJ; + + // update taus + tauB += dtauB; + tauD += dtauD; + + bConverge = abs( dtauB) <= tol && abs( dtauD) <= tol; + } + return bConverge; +} // slASHRAETauModelInv +//-------------------------------------------------------------------------- +bool slASHRAETauModelInv( // ASHRAE tau model inverse + double sunZen, // solar zenith angle, radians + double Ebn, // beam normal irradiance (typically solar noon) + double Edh, // diffuse horizontal irradiance (ditto) + float& tauB, // returned + float& tauD) // returned +{ + + float extBm = slloccur->extbm; + + double m = AirMass( kPiOver2-sunZen); + + double tauBd, tauDd; + bool bRet = slASHRAETauModelInv( Ebn, Edh, extBm, m, tauBd, tauDd); + tauB = float( tauBd); + tauD = float( tauDd); + return bRet; +} // slASHRAETauModelInv +//========================================================================== -} /************************ rest of file is if-outs *************************/ diff --git a/src/SLPAK.H b/src/SLPAK.H index 6d07eb5fa..c2d933c73 100644 --- a/src/SLPAK.H +++ b/src/SLPAK.H @@ -85,6 +85,7 @@ float slha( float fhour); float slASTCor(); float slASHRAETauModel( float sunZen, float tauB, float tauD, float& radDirN, float& radDifH); +bool slASHRAETauModelInv( double sunZen, double Ebn, double Edh, float& tauB, float& tauD); // end of slpak.h diff --git a/src/WFPAK.CPP b/src/WFPAK.CPP index 1c0eaa10e..0c02e300c 100644 --- a/src/WFPAK.CPP +++ b/src/WFPAK.CPP @@ -323,10 +323,14 @@ void WDHR::wd_Init( // initialize all members { static const NANDAT unset( UNSET); float unsetf; V unsetf = V unset; - // treat as all floats - int szFloat = sizeof( WDHR)/sizeof( float); - VSet( (float *)this, szFloat, unsetf); - wd_sunup = 0; // only integer, overwrite UNSET + float* pF0 = &wd_slAzm; + float* pFN = &wd_tdvElecAvg01; + int szFloat = pFN - pF0 + 1; + // attempt to detect layout change (+2 is due to packing) + ASSERT( szFloat*sizeof( float)+sizeof( wd_sunup)+sizeof( wd_tdvElecHrRank)+2==sizeof( WDHR)); + VSet( pF0, szFloat, unsetf); + wd_sunup = 0; // non-floats + VZero( wd_tdvElecHrRank, 25); } } // WDHR::wd_Init //------------------------------------------------------------------------------ @@ -386,7 +390,7 @@ RC WDHR::wd_Unpack( // single-hour unpack // returns RCOK { - wd_Init( 1); // set all to UNSET) + wd_Init( 1); // set all to UNSET int i = (wFileFormat==BSGSdemo); // normally fetch words 0,1,2, but to unscramble demo format, fetch 1,2,0 int w = phour[i++]; // word 0, or 1 if scrambled @@ -423,7 +427,8 @@ RC WDHR::wd_Unpack( // single-hour unpack class WDDAY { friend class WDYEAR; -friend class WFILE; +friend WDHR; +friend WFILE; float wdd_taDbPvPk; // previous day max dry bulb air temp, F float wdd_taDbPk; // current day max dry bulb air temp, F float wdd_taDbAvg; // this day mean dry bulb air temp, F @@ -445,12 +450,20 @@ friend class WFILE; float wdd_tdvElecAvg; // avg for cur day float wdd_tdvElecPvPk; // peak for prior day float wdd_tdvElecAvg01; // avg for print day + SI wdd_tdvElecHrRank[ 25];// hr rank public: void wdd_Init(); int wdd_Compare( const WDHR* wdHr) const; - void wdd_Set( WDHR* wdHr, int options=0) const; + void wdd_Set24( WDHR* wdHr, int options=0) const; }; // class WDDAY //---------------------------------------------------------------------------- +struct VHR // sort helper for wdy_Stats +{ double v; // value + SI iHr; // hour when value occurs + static int Compare( const void* pV1, const void* pV2) + { return LTEQGT( ((const VHR *)pV2)->v, ((const VHR *)pV1)->v); } +}; // struct VHR +//---------------------------------------------------------------------------- class WDYEAR { friend class WFILE; @@ -472,8 +485,8 @@ public: return wdy_day[ iD0]; } RC wdy_Fill( WFILE* pWF, int erOp=WRN); - void wdy_MeanMax( int jDay, double& taDbMean, double& taDbMax, - double& tdvElecMean, double& tdvElecMax) const; + void wdy_Stats( int jDay, double& taDbMean, double& taDbMax, + double& tdvElecMean, double& tdvElecMax, SI tdvElecHrRank[ 25]) const; float wdy_TaDbAvg( int jDay1, int jDay2); }; // class WDYEAR //----------------------------------------------------------------------------- @@ -499,7 +512,7 @@ x // others: fill always int yrLen = wf_pWDY->wdy_isLeap ? 366 : 365; int jD; for (jD=1; jD <= yrLen; jD++) - wf_pWDY->wdy_Day( jD).wdd_Set( &wf_pWDY->wdy_Hr( jD, 0), options); + wf_pWDY->wdy_Day( jD).wdd_Set24( &wf_pWDY->wdy_Hr( jD, 0), options); #if 0 && defined( _DEBUG) if (wFileFormat == CSW) { // CSW data should match calculated @@ -559,11 +572,12 @@ RC WDYEAR::wdy_Fill( // read weather data for entire file; compute averages etc. if (rc) break; double taDbMean, taDbMax, tdvElecMean, tdvElecMax; - wdy_MeanMax( jDay, taDbMean, taDbMax, tdvElecMean, tdvElecMax); + WDDAY& wdd = wdy_Day( jDay); + wdy_Stats( jDay, taDbMean, taDbMax, tdvElecMean, tdvElecMax, + wdd.wdd_tdvElecHrRank); // current day values // next day's previous day values = current day - WDDAY& wdd = wdy_Day( jDay); WDDAY& wdd1 = wdy_Day( jDay+1); wdd.wdd_taDbPk = wdd1.wdd_taDbPvPk = taDbMax; wdd.wdd_taDbAvg = wdd1.wdd_taDbAvg01 = taDbMean; @@ -620,17 +634,20 @@ RC WDYEAR::wdy_Fill( // read weather data for entire file; compute averages etc. return rc; } // WDYEAR::wdy_Fill //----------------------------------------------------------------------------- -void WDYEAR::wdy_MeanMax( // statistics for day +void WDYEAR::wdy_Stats( // statistics for day int jDay, // day of year (1-365/366) double& taDbMean, // returned: 24hr mean dry-bulb, F double& taDbMax, // returned: max dry-bulb, F double& tdvElecMean, // returned: mean TDV elec - double& tdvElecMax) const // returned: max TDV elec + double& tdvElecMax, // returned: max TDV elec + SI tdvElecHrRank[ 25]) const // returned: tdvElec ranked // returns min, mean, and max dry-bulb for day { + VHR tdvElecHr[ 24]; // day's tdvElec for hour-rank sort taDbMax = tdvElecMax = -9999.; taDbMean = tdvElecMean = 0.; - for (int iHr=0; iHr<24; iHr++) + int iHr; + for (iHr=0; iHr<24; iHr++) { const WDHR& wd = wdy_Hr( jDay, iHr); if (wd.wd_db > taDbMax) taDbMax = wd.wd_db; @@ -641,12 +658,25 @@ void WDYEAR::wdy_MeanMax( // statistics for day { if (wd.wd_tdvElec > tdvElecMax) tdvElecMax = wd.wd_tdvElec; tdvElecMean += wd.wd_tdvElec; + tdvElecHr[ iHr].v = wd.wd_tdvElec; // tdvElec for rank-hour sort + tdvElecHr[ iHr].iHr = iHr; // corresponding hour } } - taDbMean = taDbMean / 24.; + taDbMean /= 24.; if (!ISUNSET( tdvElecMean)) - tdvElecMean = tdvElecMean / 24.; -} // WDYEAR::wdy_MeanMax + { tdvElecMean /= 24.; + // sort the days tdvElec values is descending order + qsort( tdvElecHr, 24, sizeof( VHR), VHR::Compare); + // return hour ranking as 1-based + // tdvElecHrRank[ 1] = 1-based hour of peak TDV + // [ 2] = ditto, next highest + tdvElecHrRank[ 0] = 0; // [ 0] is unused + for (iHr=0; iHr<24; iHr++) + tdvElecHrRank[ iHr+1] = tdvElecHr[ iHr].iHr+1; + } + else + VZero( tdvElecHrRank, 25); // tdvElec values not complete +} // WDYEAR::wdy_Stats //----------------------------------------------------------------------------- float WDYEAR::wdy_TaDbAvg( // multi-day average dry bulb int jDay1, // 1st day (possibly < 0) @@ -674,6 +704,7 @@ void WDDAY::wdd_Init() wdd_tdvElecAvg = 0.f; wdd_tdvElecPvPk = 0.f; wdd_tdvElecAvg01 = 0.f; + VZero( wdd_tdvElecHrRank, 25); wdd_tGrnd = 0.f; wdd_tMains = 0.f; @@ -702,7 +733,7 @@ int WDDAY::wdd_Compare( // check that hour values match daily return diffCount; } // WDDAY::wdd_Compare //----------------------------------------------------------------------------- -void WDDAY::wdd_Set( // set hourly values from daily +void WDDAY::wdd_Set24( // set hourly values from daily WDHR* wdHr, // 1st hour data for day int options /*=0*/) const // option bits // 1: set iff destination is "missing" @@ -712,42 +743,62 @@ void WDDAY::wdd_Set( // set hourly values from daily #define SETIF( d, s) if (IsMissing( d)) d = s; if (!options) { for (int iHr=0; iHr<24; iHr++) - { WDHR& wd = wdHr[ iHr]; - wd.wd_taDbPk = wdd_taDbPk; - wd.wd_taDbAvg = wdd_taDbAvg; - wd.wd_taDbPvPk = wdd_taDbPvPk; - wd.wd_taDbAvg01 = wdd_taDbAvg01; - wd.wd_taDbAvg07 = wdd_taDbAvg07; - wd.wd_taDbAvg14 = wdd_taDbAvg14; - wd.wd_taDbAvg31 = wdd_taDbAvg31; - wd.wd_tGrnd = wdd_tGrnd; - wd.wd_tMains = wdd_tMains; - wd.wd_tdvElecPk = wdd_tdvElecPk; - wd.wd_tdvElecAvg = wdd_tdvElecAvg; - wd.wd_tdvElecPvPk = wdd_tdvElecPvPk; - wd.wd_tdvElecAvg01= wdd_tdvElecAvg01; - } + wdHr[ iHr].wd_SetDayValues( *this); } else { for (int iHr=0; iHr<24; iHr++) - { WDHR& wd = wdHr[ iHr]; - SETIF( wd.wd_taDbPk, wdd_taDbPk) - SETIF( wd.wd_taDbAvg, wdd_taDbAvg) - SETIF( wd.wd_taDbPvPk, wdd_taDbPvPk) - SETIF( wd.wd_taDbAvg01, wdd_taDbAvg01) - SETIF( wd.wd_taDbAvg07, wdd_taDbAvg07) - SETIF( wd.wd_taDbAvg14, wdd_taDbAvg14) - SETIF( wd.wd_taDbAvg31, wdd_taDbAvg31) - SETIF( wd.wd_tGrnd, wdd_tGrnd); - SETIF( wd.wd_tMains, wdd_tMains); - SETIF( wd.wd_tdvElecPk, wdd_tdvElecPk); - SETIF( wd.wd_tdvElecAvg, wdd_tdvElecAvg); - SETIF( wd.wd_tdvElecPvPk, wdd_tdvElecPvPk); - SETIF( wd.wd_tdvElecAvg01,wdd_tdvElecAvg01); - } + wdHr[ iHr].wd_SetDayValuesIfMissing( *this); } #undef SETIF -} // WDDAY::wdd_Set +} // WDDAY::wdd_Set24 +//----------------------------------------------------------------------------- +void WDHR::wd_SetDayValues( // set daily members + const WDDAY& wdd) // source +{ + wd_taDbPk = wdd.wdd_taDbPk; + wd_taDbAvg = wdd.wdd_taDbAvg; + wd_taDbPvPk = wdd.wdd_taDbPvPk; + wd_taDbAvg01 = wdd.wdd_taDbAvg01; + wd_taDbAvg07 = wdd.wdd_taDbAvg07; + wd_taDbAvg14 = wdd.wdd_taDbAvg14; + wd_taDbAvg31 = wdd.wdd_taDbAvg31; + wd_tGrnd = wdd.wdd_tGrnd; + wd_tMains = wdd.wdd_tMains; + wd_tdvElecPk = wdd.wdd_tdvElecPk; + wd_tdvElecAvg = wdd.wdd_tdvElecAvg; + wd_tdvElecPvPk = wdd.wdd_tdvElecPvPk; + wd_tdvElecAvg01= wdd.wdd_tdvElecAvg01; + VCopy( wd_tdvElecHrRank, 25, wdd.wdd_tdvElecHrRank); +} // WDHR::wd_SetDayValues +//----------------------------------------------------------------------------- +void WDHR::wd_SetDayValuesIfMissing( // set missing daily members + const WDDAY& wdd) // source +{ +#define SETIF( d, s) if (IsMissing( d)) d = s; + SETIF( wd_taDbPk, wdd.wdd_taDbPk) + SETIF( wd_taDbAvg, wdd.wdd_taDbAvg) + SETIF( wd_taDbPvPk, wdd.wdd_taDbPvPk) + SETIF( wd_taDbAvg01, wdd.wdd_taDbAvg01) + SETIF( wd_taDbAvg07, wdd.wdd_taDbAvg07) + SETIF( wd_taDbAvg14, wdd.wdd_taDbAvg14) + SETIF( wd_taDbAvg31, wdd.wdd_taDbAvg31) + SETIF( wd_tGrnd, wdd.wdd_tGrnd) + SETIF( wd_tMains, wdd.wdd_tMains) + SETIF( wd_tdvElecPk, wdd.wdd_tdvElecPk) + SETIF( wd_tdvElecAvg, wdd.wdd_tdvElecAvg) + SETIF( wd_tdvElecPvPk, wdd.wdd_tdvElecPvPk) + SETIF( wd_tdvElecAvg01, wdd.wdd_tdvElecAvg01) + VCopy( wd_tdvElecHrRank, 25, wdd.wdd_tdvElecHrRank); +#undef SETIF +} // WDHR::wd_SetDayValuesIfMissing +//---------------------------------------------------------------------------- +void WDHR::wd_ShiftTdvElecHrRankForDST() // handle DST +{ + for (int iHr=1; iHr<=24; iHr++) + { if (++wd_tdvElecHrRank[ iHr] == 25) + wd_tdvElecHrRank[ iHr] = 1; // wrap + } +} // WDHR::wd_ShiftTdvElecHrRankForDST //============================================================================ ////////////////////////////////////////////////////////////////////////////// @@ -1504,10 +1555,11 @@ RC WFILE::wf_Read( // read and unpack weather data for an hour // TODO: support partial weather years if (wf_pWDY && !(erOp & (WF_FORCEREAD|WF_DSNDAY))) { pwd->Copy( wf_pWDY->wdy_Hr( jDay, iHr), (erOp&WF_SAVESLRGEOM) != 0); - if ( iHr == 23 && (erOp&WF_DSTFIX)) + if (erOp & WF_DSTFIX) { WDDAY& wdd = wf_pWDY->wdy_Day( jDay+1); - pwd->wd_taDbPvPk = wdd.wdd_taDbPvPk; - pwd->wd_tdvElecPvPk = wdd.wdd_tdvElecPvPk; + if (iHr == 23) + pwd->wd_SetDayValues( wdd); + pwd->wd_ShiftTdvElecHrRankForDST(); } return RCOK; } diff --git a/src/cse.sln b/src/cse.sln index bf0cb3e1f..49ec2f61d 100644 --- a/src/cse.sln +++ b/src/cse.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CSE", "CSE.vcxproj", "{64CACC70-10B9-4D6D-8DCD-08EB2971467B}" ProjectSection(ProjectDependencies) = postProject @@ -19,10 +19,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{91FC6660-6ECF-4ED9-8D9C-061FB6719090}" EndProject Global - GlobalSection(VaultVsipSolution-v2) = preSolution - ExcludedFileCount = 1 - ExcludedFile0 = CFSCalc.cpp - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 DebugDLL|Win32 = DebugDLL|Win32 @@ -32,12 +28,12 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.Debug|Win32.ActiveCfg = Debug|Win32 {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.Debug|Win32.Build.0 = Debug|Win32 - {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 - {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.DebugDLL|Win32.ActiveCfg = Debug|Win32 + {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.DebugDLL|Win32.Build.0 = Debug|Win32 {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.Release|Win32.ActiveCfg = Release|Win32 {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.Release|Win32.Build.0 = Release|Win32 - {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 - {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 + {64CACC70-10B9-4D6D-8DCD-08EB2971467B}.ReleaseDLL|Win32.Build.0 = Release|Win32 {B5836D1F-2B51-4956-8127-76D1034DFBC8}.Debug|Win32.ActiveCfg = Common|Win32 {B5836D1F-2B51-4956-8127-76D1034DFBC8}.Debug|Win32.Build.0 = Common|Win32 {B5836D1F-2B51-4956-8127-76D1034DFBC8}.DebugDLL|Win32.ActiveCfg = Common|Win32 @@ -58,4 +54,8 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(VaultVsipSolution-v2) = preSolution + ExcludedFileCount = 1 + ExcludedFile0 = CFSCalc.cpp + EndGlobalSection EndGlobal diff --git a/src/csevrsn.h b/src/csevrsn.h index da4ccef8a..31952ea0f 100644 --- a/src/csevrsn.h +++ b/src/csevrsn.h @@ -14,7 +14,7 @@ // version # for current build // change ONLY here #define CSEVRSN_MAJOR 0 -#define CSEVRSN_MINOR 848 +#define CSEVRSN_MINOR 849 // version # as quoted text ("x.xxx") #define CSEVRSN_TEXT MAKE_LIT(CSEVRSN_MAJOR##.##CSEVRSN_MINOR) @@ -22,6 +22,7 @@ // ONLY comments below here /* History: + 0.849: added tdvElecHrRank; fix daily wthr/tdv values re DST; prelim DESCOND, committed 12-28-2017 0.848: merge 0.836b (alternate branch release) 0.847: fix inconsistent xs_UNom 0.846: SOLARFIX test version, 10-25-2017