diff --git a/src/CGCOMP.CPP b/src/CGCOMP.CPP index ad639463c..186d7ccde 100644 --- a/src/CGCOMP.CPP +++ b/src/CGCOMP.CPP @@ -265,27 +265,40 @@ float TOPRAT::tp_WindPresV( // wind velocity pressure // NAFCATS s/b same as AFCAT choices + 1 (for total) static_assert(AFMTR_IVL::NAFCATS == C_AFCAT_COUNT+1, "Inconsistent AFMTR constants"); //----------------------------------------------------------------------------- -void AFMTR_IVL::amt_Copy( - const AFMTR_IVL* s) +void AFMTR_IVL::amt_Copy( // copy + const AFMTR_IVL* sIvl, // source + float mult /*=1.f*/) // optional multiplier { - memcpy(this, s, sizeof(AFMTR_IVL)); + if (mult == 1.f) + memcpy(this, sIvl, sizeof(AFMTR_IVL)); + else + { amt_count = sIvl->amt_count; + VCopy(&amt_total, NAFCATS, &sIvl->amt_total, double(mult)); + } } // AFMTR_IVL::amt_Copy //----------------------------------------------------------------------------- void AFMTR_IVL::amt_Accum( // accumulate const AFMTR_IVL* sIvl, // source int firstFlg, // true iff first accum into this (beg of ivl) - int lastFlg) // true iff last accum into this (end of ivl) - + int lastFlg, // true iff last accum into this (end of ivl) + int options /*=0*/) // option bits + // 1: use sIvl.amt_count to scale totals + // effectively averages by day for annual values + // 2: sum only (do not average) { + int count = (options & 1) ? sIvl->amt_count : 1; if (firstFlg) - { amt_Copy(sIvl); - amt_count = 1; + { amt_Copy(sIvl, float( count)); + amt_count = count; } else - { VAccum(&amt_total, NAFCATS, &sIvl->amt_total); - amt_count++; + { VAccum(&amt_total, NAFCATS, &sIvl->amt_total, float( count)); + amt_count += count; } - if (lastFlg) + + // average unless caller says don't + // Note: VMul1() nops if amt_count==1 + if (lastFlg && !(options & 2)) VMul1(&amt_total, NAFCATS, 1.f / amt_count); } // AFMTR_IVL //----------------------------------------------------------------------------- @@ -296,7 +309,8 @@ RC AFMTR::amt_CkF() //----------------------------------------------------------------------------- RC AFMTR::amt_BegSubhr() // init at beg of subhr { - S.amt_Clear(); + S[ 0].amt_Clear(); + S[ 1].amt_Clear(); return RCOK; } // AFMTR::amt_BegSubhr //----------------------------------------------------------------------------- @@ -304,25 +318,42 @@ void AFMTR::amt_AccumCat( // accumulate air flow value for current subhour AFCAT afCat, // air flow category float amf) // air mass flow, lbm/sec { - if (amf > 0.f) // record only flow into zone - { // convert lbm/s -> cfm std air - S.amt_AccumCat(afCat, AMFtoAVF2( amf)); - } + int iNeg = amf < 0.f; + S[ iNeg].amt_AccumCat(afCat, AMFtoAVF2(amf)); } // AFMTR::amt_AccumCat //----------------------------------------------------------------------------- +AFMTR_IVL* AFMTR::amt_GetAFMTR_IVL( + IVLCH ivl, // interval + int iPN /*=0*/) // flow direction 0: pos (in), 1: neg (out) +{ + return Y + 2 * (ivl - C_IVLCH_Y) + iPN; +} +//----------------------------------------------------------------------------- void AFMTR::amt_Accum( IVLCH ivl, // destination interval: hour/day/month/year // Accumulates from subhour/day/month. Not Top.ivl! int firstFlg, // iff TRUE, destination will be initialized before values are accumulated into it int lastFlg) // iff TRUE, destination averages will be computed as needed { - AFMTR_IVL* dIvl = &Y + (ivl - C_IVLCH_Y); // point destination substruct for interval - // ASSUMES interval members ordered like DTIVLCH choices - AFMTR_IVL* sIvl = dIvl + 1; // source: next shorter interval + AFMTR_IVL* dIvl0 = amt_GetAFMTR_IVL( ivl); // point destination substruct for interval + // ASSUMES interval members ordered like DTIVLCH choices + AFMTR_IVL* sIvl0 = amt_GetAFMTR_IVL(ivl + 1); // source: next shorter interval + + int options = 0; // default: track average - // accumulate: copy on first call (in lieu of 0'ing dIvl). - // Note: amt_Init() call in doBegIvl 0s H values - dIvl->amt_Accum(sIvl, firstFlg, lastFlg); + if (ivl == C_IVLCH_Y) + options = 1; // average by day for non-sum-of year values + // handles diffs due to month length + for (int iPN=0; iPN<2; iPN++) + dIvl0[ iPN].amt_Accum(sIvl0+iPN, firstFlg, lastFlg, options); + + if (lastFlg) + { + AFMTR* pAMSum = AfMtrR.p + AfMtrR.n; + AFMTR_IVL* dIvlSum0 = pAMSum->amt_GetAFMTR_IVL( ivl); + for (int iPN = 0; iPN < 2; iPN++) + dIvlSum0[ iPN].amt_Accum(dIvl0+iPN, ss == 1, 0); + } } // AFMTR::amt_Accum //============================================================================= @@ -518,7 +549,6 @@ double ZNR::zn_Rho0() const // zone air density // returns moist air density lb/ft3 at nominal z=0 for current zone conditions // Note: not *dry* air { -#if 1 // air density rework, 10-18-2012 double rho = psyDenMoistAir( tz, wz, LbSfToInHg( zn_pz0)); if (rho < .0001) { err( WRN, "Zone '%s', %s: moist air density <= 0\n", @@ -526,15 +556,6 @@ double ZNR::zn_Rho0() const // zone air density rho = 0.01; // set to small but physically possible value } return rho; -#elif 1 -x double rho1 = psyDenMoistAir( tz, wz, LbSfToInHg( zn_pz0)); -x double rho2 = psyDensity( tz, wz, LbSfToInHg( zn_pz0)); -x if (FEQX( rho1, rho2) > .001) -x printf( "Mismatch\n"); -x return rho2; -#else -x return psyDensity( tz, wz, LbSfToInHg( zn_pz0)); -#endif } // ZNR::zn_Rho0 //------------------------------------------------------------------------------ void ZNR::zn_AccumAirFlow( // accumulate zone bal values due to air flow @@ -1034,15 +1055,28 @@ void IZXRAT::iz_SetupAfMtrs() // AFMTR ptrs: NULL if no meter specified -> no air flow accounting // one pointer for positive flows, one for negative - const ZNR* zp; - if (iz_zi1 > 0) - { zp = ZrB.GetAt(iz_zi1); - iz_pPosAfMtr = AfMtrR.GetAtSafe(zp->i.zn_afMtri); - } - if (iz_zi2 > 0) - { zp = ZrB.GetAt(iz_zi2); - iz_pNegAfMtr = AfMtrR.GetAtSafe(zp->i.zn_afMtri); + iz_pAfMtr1 = iz_pAfMtr2 = NULL; // insurance + if (iz_afCat > 0) + { // set up ptrs to AFMTR(s) + const ZNR* zp; + if (iz_zi1 > 0) + { zp = ZrB.GetAt(iz_zi1); + iz_pAfMtr1 = AfMtrR.GetAtSafe(zp->i.zn_afMtri); + } + if (iz_zi2 > 0) + { // interzone transfers recorded iff to a different meter + zp = ZrB.GetAt(iz_zi2); + AFMTR* pAM = AfMtrR.GetAtSafe(zp->i.zn_afMtri); + if (pAM == iz_pAfMtr1) + iz_pAfMtr1 = NULL; // same meter on both sides of IZ + // don't record IZ within meter + else + iz_pAfMtr2 = pAM; // z2 meter specified and differs from z1 + } } + iz_doingAfMtr // say this IZXRAT has AFMTR (speedier test) + = iz_pAfMtr1 != NULL || iz_pAfMtr2 != NULL; + } // IZXRAT::iz_SetupAfMtrs //----------------------------------------------------------------------------- AFCAT IZXRAT::iz_AfCatDefault() const @@ -1061,8 +1095,10 @@ AFCAT IZXRAT::iz_AfCatDefault() const else { if (iz_IsFixedFlow()) afCat = C_AFCAT_FANIZ; - else + else if (iz_IsAirNet()) afCat = C_AFCAT_INFILIZ; + else + afCat = 0; } return afCat; @@ -1505,14 +1541,12 @@ RC IZXRAT::iz_EndSubhr() // end-of-subhour vent calcs if (iz_nvcntrl == C_IZNVTYCH_ANHORIZ) iz_amfNom += (1.f - fVent)*iz_ad[0].ad_mdotB + fVent * iz_ad[1].ad_mdotB; - if (iz_amfNom > 0.f) - { if (iz_pPosAfMtr) - iz_pPosAfMtr->amt_AccumCat(iz_afCat, iz_amfNom); - } - else if (iz_amfNom < 0.f) - { // flow is out of zn1 = into zn2 - if (iz_pNegAfMtr) - iz_pNegAfMtr->amt_AccumCat(iz_afCat, -iz_amfNom); + if (iz_doingAfMtr && iz_amfNom != 0.f) + { if (iz_pAfMtr1) + iz_pAfMtr1->amt_AccumCat(iz_afCat, iz_amfNom); + if (iz_pAfMtr2) + // flow is opposite direction from z2 POV + iz_pAfMtr2->amt_AccumCat(iz_afCat, -iz_amfNom); } return RCOK; diff --git a/src/CGRESULT.CPP b/src/CGRESULT.CPP index cfb06442c..7bf287a00 100644 --- a/src/CGRESULT.CPP +++ b/src/CGRESULT.CPP @@ -235,8 +235,9 @@ static COLDEF wMtrColdef[] = #undef oWMtr // columns definition for "Airflow meter" (AFMTR) report/export -#define oAFMtr(m) offsetof( AFMTR_IVL, m) -#define D 3 // decimal digits +#define oAFMt0(m) offsetof( AFMTR_IVL, m) +#define oAFMt1(m) (offsetof( AFMTR_IVL, m)+sizeof( AFMTR_IVL)) +#define D 1 // decimal digits static COLDEF afMtrColdef[] = /* max offset cvflag */ /* colhd flags wid dfw (cnguts.h) (above) */ @@ -247,21 +248,31 @@ static COLDEF afMtrColdef[] = { "Day", 8 | 4, 2, 0, USE_NEXT_ARG, CVI }, { "Hr", 8 | 4, 2, 0, USE_NEXT_ARG, CVI }, { "Subhr", 8 | 4, 1, 0, USE_NEXT_ARG, CVS }, // .. - { "Total", 0, 7, D, oAFMtr(amt_total), CV1 }, - { "Unknown", 0, 7, D, oAFMtr(amt_unknown),CV1 }, - { "InfilEx", 0, 7, D, oAFMtr(amt_infilEx),CV1 }, - { "VentEx", 0, 7, D, oAFMtr(amt_ventEx), CV1 }, - { "FanEx", 0, 7, D, oAFMtr(amt_fanEx), CV1 }, - { "InfilIz", 0, 7, D, oAFMtr(amt_infilIz),CV1 }, - { "VentIz", 0, 7, D, oAFMtr(amt_ventIz), CV1 }, - { "FanIz", 0, 7, D, oAFMtr(amt_fanIz), CV1 }, - { "DuctLk", 0, 7, D, oAFMtr(amt_ductLk), CV1 }, - { "HVAC", 0, 7, D, oAFMtr(amt_hvac), CV1 }, + { "Tot+", 0, 5, D, oAFMt0(amt_total), CV1 }, + { "Unkn+", 0, 5, D, oAFMt0(amt_unknown),CV1 }, + { "InfX+", 0, 5, D, oAFMt0(amt_infilEx),CV1 }, + { "VntX+", 0, 5, D, oAFMt0(amt_ventEx), CV1 }, + { "FanX+", 0, 5, D, oAFMt0(amt_fanEx), CV1 }, + { "InfZ+", 0, 5, D, oAFMt0(amt_infilIz),CV1 }, + { "VntZ+", 0, 5, D, oAFMt0(amt_ventIz), CV1 }, + { "FanZ+", 0, 5, D, oAFMt0(amt_fanIz), CV1 }, + { "Duct+", 0, 5, D, oAFMt0(amt_ductLk), CV1 }, + { "HVAC+", 0, 5, D, oAFMt0(amt_hvac), CV1 }, + { "Tot-", 0, 5, D, oAFMt1(amt_total), CV1 }, + { "Unkn-", 0, 5, D, oAFMt1(amt_unknown),CV1 }, + { "InfX-", 0, 5, D, oAFMt1(amt_infilEx),CV1 }, + { "VntX-", 0, 5, D, oAFMt1(amt_ventEx), CV1 }, + { "FanX-", 0, 5, D, oAFMt1(amt_fanEx), CV1 }, + { "InfZ-", 0, 5, D, oAFMt1(amt_infilIz),CV1 }, + { "VntZ-", 0, 5, D, oAFMt1(amt_ventIz), CV1 }, + { "FanZ-", 0, 5, D, oAFMt1(amt_fanIz), CV1 }, + { "Duct-", 0, 5, D, oAFMt1(amt_ductLk), CV1 }, + { "HVAC-", 0, 5, D, oAFMt1(amt_hvac), CV1 }, { 0, 0, 0, 0, 0, CV1 } }; #undef D -#undef oAFMtr - +#undef oAFMt0 +#undef oAFMt1 // columns definition for "air handler" (AH) report/export #define oAhr(m) offsetof( AHRES_IVL_SUB, m) @@ -1258,10 +1269,10 @@ o && dvrip->rpDayEnd >= Top.tp_endDay ) <--- new year's bug! 2-94 vpRxRow( dvrip, &rxt, pIvl, shortIvlTexts[rxt.fq]); // do DHWMTR rpt row. Uses rxt.flags, colDef. } - else if (dvrip->rpTy == C_RPTYCH_AFMTR) // if DHW meter report + else if (dvrip->rpTy == C_RPTYCH_AFMTR) // if AFMETER report { - TI afMtri = dvrip->dv_afMtri; // subscript - AFMTR_IVL* pIvl = &AfMtrR[afMtri].Y + (rxt.fq - 1); // .M is after .Y, etc + TI afMtri = dvrip->dv_afMtri > 0 ? dvrip->dv_afMtri : AfMtrR.n; // subscript + AFMTR_IVL* pIvl = AfMtrR[afMtri].amt_GetAFMTR_IVL( rxt.fq); rxt.colDef = afMtrColdef; // columns definition table for vpRxRow vpRxRow(dvrip, &rxt, pIvl, shortIvlTexts[rxt.fq]); // do DHWMTR rpt row. Uses rxt.flags, colDef. } @@ -1487,8 +1498,10 @@ void DVRI::dv_vpAfMtrRow(RXPORTINFO *rxt, TI afMtri /*=-1*/) { if (afMtri < 0) afMtri = dv_afMtri; + if (afMtri == TI_SUM) + afMtri = AfMtrR.n; // handle "sum" AFMTR* pM = AfMtrR.GetAt(afMtri); // record - AFMTR_IVL* pIvl = (&pM->Y) + (rxt->fq - 1); // interval + AFMTR_IVL* pIvl = pM->amt_GetAFMTR_IVL( rxt->fq); // interval vpRxRow(this, rxt, pIvl, rxt->col1, pM->name, &rxt->xebM, &rxt->xebD, &rxt->xebH, rxt->xebS); } // dv_vpDHWMtrRow diff --git a/src/CNCULT4.CPP b/src/CNCULT4.CPP index ac5627bf7..9453d7f41 100644 --- a/src/CNCULT4.CPP +++ b/src/CNCULT4.CPP @@ -695,8 +695,7 @@ badZn4ty: // check meter reference or ALL or SUM if (mtri > 0) // if specific meter given (error'd above if omitted when rqd) - { - if (ckRefPt( &MtrB, mtri, isEx ? "exMeter" : "rpMeter" ) ) + { if (ckRefPt( &MtrB, mtri, isEx ? "exMeter" : "rpMeter" ) ) return RCBAD; } else // no meter given, or ALL or SUM. @@ -769,10 +768,15 @@ badDHWMtr4ty: { char *mtrTx /*=""*/; if (ri_afMtri == TI_SUM) - { - mtrTx = "sum"; - goto badAFMtr4ty; - } + switch (rpTy) + { + case 0: // rpTy 0: not set, no message here + case C_RPTYCH_AFMTR: + break; // AFMTR (air flow meter): SUM allowed. + default: + mtrTx = "sum"; + goto badAFMtr4ty; + } else if (ri_afMtri == TI_ALL) switch (rpTy) { diff --git a/src/CNGUTS.CPP b/src/CNGUTS.CPP index 46a46a29a..2ebe5b26e 100644 --- a/src/CNGUTS.CPP +++ b/src/CNGUTS.CPP @@ -547,12 +547,13 @@ LOCAL RC FC NEAR doBegIvl() // simulation run start-of-interval processing: init EF( Top.tp_ExshBegHour()); // Penumbra external shading: sets sun position default: // case C_IVLCH_S: // at start of each subhour, incl longer intervals (fall in) + Top.isEndHour = (Top.iSubhr + 1 >= Top.nSubSteps); // set flag if last subHour of hour + #if defined( DEBUGDUMP) DbDo( dbdSTARTSTEP); // nothing yet debug-printed for this subhour // (sets flag re on-demand heading printing #endif EF( Top.tp_WthrBegSubhr() ); // set Top subhourly weather members, eg tDbOSh. Mostly interpolated. cgwthr.cpp. - Top.isEndHour = (Top.iSubhr + 1 >= Top.nSubSteps); // set flag if last subHour of hour // clear subhour values in air flow meters AFMTR* pAM; @@ -1563,9 +1564,12 @@ LOCAL void FC NEAR doIvlAccum() AFMTR* pAMSum = AfMtrR.p + AfMtrR.n; AFMTR* pAM; RLUP(AfMtrR, pAM) // loop AFMTRs - { if (pAM->ss < AfMtrR.n) - pAMSum->S.amt_Accum(&pAM->S, pAM->ss == 1, pAM->ss == AfMtrR.n - 1); - pAM->amt_Accum( C_IVLCH_H, Top.isBegHour, Top.isEndHour); + { + if (pAM->ss < AfMtrR.n) + { pAMSum->S[0].amt_Accum(pAM->S, pAM->ss == 1, pAM->ss == AfMtrR.n - 1); + pAMSum->S[1].amt_Accum(pAM->S+1, pAM->ss == 1, pAM->ss == AfMtrR.n - 1); + pAM->amt_Accum(C_IVLCH_H, Top.isBegHour, Top.isEndHour); + } } if (Top.ivl > C_IVLCH_H) // if subhour call, done @@ -1724,8 +1728,8 @@ LOCAL void FC NEAR doIvlAccum() RLUP(WsResR, pWSR) // loop DHWSYS simulation results incl sum_of. pWSR->M.wsr_Accum(&pWSR->D, Top.isBegMonth, Top.isEndMonth); // accumulate month from day RLUP( AhresB, ahres) // loop air handers sim results - accumAhr( &ahres->D, &ahres->M, Top.isBegMonth, Top.isEndMonth); // accumulate day ah results to month - mtrsAccum( C_IVLCH_M, Top.isBegMonth, Top.isEndMonth); // accum metered energy: day to month. local,below. + accumAhr( &ahres->D, &ahres->M, Top.isBegMonth, Top.isEndMonth); // accumulate day ah results to month + mtrsAccum( C_IVLCH_M, Top.isBegMonth, Top.isEndMonth); // accum METERs, DHWMETERs, AFMETERS: day to month #ifdef BINRES if (brf) // if outputting binary results for this run //if (!Top.tp_autoSizing) // not for ausz yet 6-95: tested above, and brf is off. @@ -2054,7 +2058,9 @@ LOCAL void FC NEAR mtrsAccum( // Accumulate metered results: add interval to ne // AFMETERs AFMTR* pAM; RLUP(AfMtrR, pAM) - pAM->amt_Accum(ivl, firstflg, lastflg); + { if (pAM->ss < AfMtrR.n) + pAM->amt_Accum(ivl, firstflg, lastflg); + } } // mtrsAccum //----------------------------------------------------------------------------------------------------------- LOCAL void FC NEAR mtrsFinalize( // Finalize meters (after post-stage calcs e.g. battery) diff --git a/src/CNRECS.DEF b/src/CNRECS.DEF index 6ab0a1f6c..48e2f60db 100644 --- a/src/CNRECS.DEF +++ b/src/CNRECS.DEF @@ -2827,14 +2827,13 @@ RECORD IZXRAT "izXfer" *RAT // interzone heat transfers: conductive and/or vent. // C_IZNVTYCH_ANSYSAIR: system air flow // C_IZNVTYCH_ANOAVRLF: RSYS OAV relief air // ( = interzone hole sized per flow) - *r AFCAT iz_afCat // air flow category (accounting only) - // C_AFCAT_xxx + *r AFCAT iz_afCat // air flow category (accounting only) C_AFCAT_xxx + // AFMTR pointers, derived from zone zn_afMtri - // one for pos flows, one for neg - // WHY: AFMTRs track flow into zone - // IZ transfers have different zones per size - *declare "AFMTR* iz_pPosAfMtr;" - *declare "AFMTR* iz_pNegAfMtr;" + // NULL if not specified or same on both sides of IZ type + *declare "AFMTR* iz_pAfMtr1;" // for iz_zn1 + *declare "AFMTR* iz_pAfMtr2;" // for iz_zn2 + *declare "bool iz_doingAfMtr;" // true iff iz_pAfMtr1 or iz_pAfMtr2 != NULL *h AREA_GEZ iz_a1 // vent area 1, ft2 // _TWOWAY = low vent area @@ -3403,9 +3402,9 @@ RECORD AFMTR_IVL "Airflow meter interval sub" *SUBSTRUCT // interval substruct *prefix amt_ *declare "void amt_Clear() { memset( this, 0, sizeof( AFMTR_IVL));}" - *declare "void amt_Copy( const AFMTR_IVL* s);" + *declare "void amt_Copy( const AFMTR_IVL* sIvl, float mult=1.f);" *declare "void amt_AccumCat( AFCAT cat, FLOAT v) { (&amt_unknown)[ cat] += v; amt_total += v; }" - *declare "void amt_Accum( const AFMTR_IVL* sIvl, int firstFlg, int lastFlg);" + *declare "void amt_Accum( const AFMTR_IVL* sIvl, int firstFlg, int lastFlg, int options=0);" *declare "static const int NAFCATS;" @@ -3428,20 +3427,24 @@ RECORD AFMTR_IVL "Airflow meter interval sub" *SUBSTRUCT // interval substruct *END // AFMTR_IVL //============================================================================= RECORD AFMTR "AFMETER" *RAT // Airflow meter - + *prefix amt_ *declare "RC amt_CkF();" + // *declare "void amt_Clear();" + *declare "bool amt_IsSumOf() const { return ss == b->n; }" *declare "RC amt_BegSubhr();" *declare "void amt_AccumCat( AFCAT afCat, float amf);" *declare "void amt_Accum( IVLCH ivl, int firstflg, int lastFlg);" + *declare "AFMTR_IVL* amt_GetAFMTR_IVL( IVLCH ivl, int iPN=0);" + // results: average cfm std air // for each interval (member here), usage by end use (substruct member): // CAUTION: ordered for subscripting by IVLCH-1. - *y *e *nest AFMTR_IVL Y // run (aka year or annual) - *m *e *nest AFMTR_IVL M // month - *d *e *nest AFMTR_IVL D // day - *h *e *nest AFMTR_IVL H // hour - *s *e *nest AFMTR_IVL S // subhour + *y *e *array 2 *nest AFMTR_IVL Y // run (aka year or annual) + *m *e *array 2 *nest AFMTR_IVL M // month + *d *e *array 2 *nest AFMTR_IVL D // day + *h *e *array 2 *nest AFMTR_IVL H // hour + *s *e *array 2 *nest AFMTR_IVL S // subhour *END // AFMETER //============================================================================= RECORD DHWMTR_IVL "DHW meter interval sub" *SUBSTRUCT // interval substruct for DHW meter diff --git a/src/CSE.cpp b/src/CSE.cpp index a1469c93d..9eb7d1ca7 100644 --- a/src/CSE.cpp +++ b/src/CSE.cpp @@ -57,7 +57,6 @@ #include "cnglob.h" #include // exit -#include // jmp_buf setjmp longjmp #include // record: base class for rccn.h classes #include // TOPRATstr diff --git a/src/VECPAK.H b/src/VECPAK.H index 490ee1853..f91156b74 100644 --- a/src/VECPAK.H +++ b/src/VECPAK.H @@ -336,8 +336,9 @@ template< typename T1, typename T2> void VMul1( // vector * constant T1* v, // vector int n, // dim of v T2 f) // factor -{ for (int i=0; i < n; i++) - v[ i] = T1( v[ i] * f); +{ if (f != T2( 1)) + for (int i=0; i < n; i++) + v[ i] = T1( v[ i] * f); } // VMul1< T1, T2> //------------------------------------------------------------------------- template< typename T> T DotProd3( // 3-vector dot product