diff --git a/resources/energyplus/ProposedEnergy+.idd b/resources/energyplus/ProposedEnergy+.idd index d48f2465ac..115432744c 100644 --- a/resources/energyplus/ProposedEnergy+.idd +++ b/resources/energyplus/ProposedEnergy+.idd @@ -36941,37 +36941,13 @@ HeatExchanger:AirToAir:SensibleAndLatent, \minimum 0.0 \maximum 1.0 \default 0.0 - N4, \field Sensible Effectiveness at 75% Heating Air Flow + N4, \field Sensible Effectiveness at 100% Cooling Air Flow \type real \units dimensionless \minimum 0.0 \maximum 1.0 \default 0.0 - N5, \field Latent Effectiveness at 75% Heating Air Flow - \type real - \units dimensionless - \minimum 0.0 - \maximum 1.0 - \default 0.0 - N6, \field Sensible Effectiveness at 100% Cooling Air Flow - \type real - \units dimensionless - \minimum 0.0 - \maximum 1.0 - \default 0.0 - N7, \field Latent Effectiveness at 100% Cooling Air Flow - \type real - \units dimensionless - \minimum 0.0 - \maximum 1.0 - \default 0.0 - N8, \field Sensible Effectiveness at 75% Cooling Air Flow - \type real - \units dimensionless - \minimum 0.0 - \maximum 1.0 - \default 0.0 - N9, \field Latent Effectiveness at 75% Cooling Air Flow + N5, \field Latent Effectiveness at 100% Cooling Air Flow \type real \units dimensionless \minimum 0.0 @@ -36989,7 +36965,7 @@ HeatExchanger:AirToAir:SensibleAndLatent, A6, \field Exhaust Air Outlet Node Name \required-field \type node - N10,\field Nominal Electric Power + N6, \field Nominal Electric Power \type real \units W \ip-units W @@ -37012,14 +36988,14 @@ HeatExchanger:AirToAir:SensibleAndLatent, \key ExhaustOnly \key MinimumExhaustTemperature \default None - N11,\field Threshold Temperature + N7, \field Threshold Temperature \type real \units C \default 1.7 \note Supply (outdoor) air inlet temp threshold for exhaust air recirculation and \note exhaust only frost control types. Exhaust air outlet threshold Temperature for \note minimum exhaust temperature frost control type. - N12,\field Initial Defrost Time Fraction + N8, \field Initial Defrost Time Fraction \type real \units dimensionless \minimum 0.0 @@ -37027,20 +37003,44 @@ HeatExchanger:AirToAir:SensibleAndLatent, \default 0.083 \note Fraction of the time when frost control will be invoked at the threshold temperature. \note This field only used for exhaust air recirc and exhaust-only frost control types. - N13,\field Rate of Defrost Time Fraction Increase + N9, \field Rate of Defrost Time Fraction Increase \type real \units 1/K \minimum 0.0 \default 0.012 \note Rate of increase in defrost time fraction as actual temp falls below threshold temperature. \note This field only used for exhaust air recirc and exhaust-only frost control types. - A10;\field Economizer Lockout + A10,\field Economizer Lockout \type choice \key Yes \key No \default Yes \note Yes means that the heat exchanger will be locked out (off) \note when the economizer is operating or high humidity control is active + A11,\field Sensible Effectiveness of Heating Air Flow Curve Name + \note optional + \note if this field has value, then the sensivle effectiveness for heating + \note will be the value in N2 multiplied by this curve value + \type object-list + \object-list UnivariateFunctions + A12,\field Latent Effectiveness of Heating Air Flow Curve Name + \note optional + \note if this field has value, then the latent effectiveness for heating + \note will be the value in N3 multiplied by this curve value + \type object-list + \object-list UnivariateFunctions + A13,\field Sensible Effectiveness of Cooling Air Flow Curve Name + \note optional + \note if this field has value, then the sensivle effectiveness for cooling + \note will be the value in N4 multiplied by this curve value + \type object-list + \object-list UnivariateFunctions + A14;\field Latent Effectiveness of Cooling Air Flow Curve Name + \note optional + \note if this field has value, then the latent effectiveness for cooling + \note will be the value in N5 multiplied by this curve value + \type object-list + \object-list UnivariateFunctions HeatExchanger:Desiccant:BalancedFlow, \memo This object models a balanced desiccant heat exchanger. diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd index 714e8753ce..72b547f3dc 100644 --- a/resources/model/OpenStudio.idd +++ b/resources/model/OpenStudio.idd @@ -24742,37 +24742,13 @@ OS:HeatExchanger:AirToAir:SensibleAndLatent, \units dimensionless \minimum 0.0 \maximum 1.0 - N4, \field Sensible Effectiveness at 75% Heating Air Flow + N4, \field Sensible Effectiveness at 100% Cooling Air Flow \type real \required-field \units dimensionless \minimum 0.0 \maximum 1.0 - N5, \field Latent Effectiveness at 75% Heating Air Flow - \type real - \required-field - \units dimensionless - \minimum 0.0 - \maximum 1.0 - N6, \field Sensible Effectiveness at 100% Cooling Air Flow - \type real - \required-field - \units dimensionless - \minimum 0.0 - \maximum 1.0 - N7, \field Latent Effectiveness at 100% Cooling Air Flow - \type real - \required-field - \units dimensionless - \minimum 0.0 - \maximum 1.0 - N8, \field Sensible Effectiveness at 75% Cooling Air Flow - \type real - \required-field - \units dimensionless - \minimum 0.0 - \maximum 1.0 - N9, \field Latent Effectiveness at 75% Cooling Air Flow + N5, \field Latent Effectiveness at 100% Cooling Air Flow \type real \required-field \units dimensionless @@ -24790,7 +24766,7 @@ OS:HeatExchanger:AirToAir:SensibleAndLatent, A7, \field Exhaust Air Outlet Node \type object-list \object-list ConnectionNames - N10,\field Nominal Electric Power + N6, \field Nominal Electric Power \type real \required-field \units W @@ -24813,33 +24789,57 @@ OS:HeatExchanger:AirToAir:SensibleAndLatent, \key ExhaustAirRecirculation \key ExhaustOnly \key MinimumExhaustTemperature - N11,\field Threshold Temperature + N7, \field Threshold Temperature \type real \units C \default 1.7 \note Supply (outdoor) air inlet temp threshold for exhaust air recirculation and \note exhaust only frost control types. Exhaust air outlet threshold Temperature for \note minimum exhaust temperature frost control type. - N12,\field Initial Defrost Time Fraction + N8, \field Initial Defrost Time Fraction \type real \units dimensionless \minimum 0.0 \maximum 1.0 \note Fraction of the time when frost control will be invoked at the threshold temperature. \note This field only used for exhaust air recirc and exhaust-only frost control types. - N13,\field Rate of Defrost Time Fraction Increase + N9, \field Rate of Defrost Time Fraction Increase \type real \units 1/K \minimum 0.0 \note Rate of increase in defrost time fraction as actual temp falls below threshold temperature. \note This field only used for exhaust air recirc and exhaust-only frost control types. - A11;\field Economizer Lockout + A11,\field Economizer Lockout \type choice \required-field \key Yes \key No \note Yes means that the heat exchanger will be locked out (off) \note when the economizer is operating or high humidity control is active + A12,\field Sensible Effectiveness of Heating Air Flow Curve Name + \note optional + \note if this field has value, then the sensivle effectiveness for heating + \note will be the value in N2 multiplied by this curve value + \type object-list + \object-list UnivariateFunctions + A13,\field Latent Effectiveness of Heating Air Flow Curve Name + \note optional + \note if this field has value, then the latent effectiveness for heating + \note will be the value in N3 multiplied by this curve value + \type object-list + \object-list UnivariateFunctions + A14,\field Sensible Effectiveness of Cooling Air Flow Curve Name + \note optional + \note if this field has value, then the sensivle effectiveness for cooling + \note will be the value in N4 multiplied by this curve value + \type object-list + \object-list UnivariateFunctions + A15;\field Latent Effectiveness of Cooling Air Flow Curve Name + \note optional + \note if this field has value, then the latent effectiveness for cooling + \note will be the value in N5 multiplied by this curve value + \type object-list + \object-list UnivariateFunctions OS:HeatExchanger:Desiccant:BalancedFlow, \memo This object models a balanced desiccant heat exchanger. diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateHeatExchangerAirToAirSensibleAndLatent.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateHeatExchangerAirToAirSensibleAndLatent.cpp index 200dbbf2bf..b05b2d3fe1 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateHeatExchangerAirToAirSensibleAndLatent.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateHeatExchangerAirToAirSensibleAndLatent.cpp @@ -10,6 +10,7 @@ #include "../../model/Node.hpp" #include "../../model/Node_Impl.hpp" #include "../../model/Schedule.hpp" +#include "../../model/Curve.hpp" #include "../../utilities/idf/Workspace.hpp" #include "../../utilities/core/Logger.hpp" #include @@ -63,18 +64,6 @@ namespace energyplus { idfObject.setDouble(HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessat100_HeatingAirFlow, d.get()); } - // SensibleEffectivenessat75_HeatingAirFlow - d = modelObject.sensibleEffectivenessat75HeatingAirFlow(); - if (d) { - idfObject.setDouble(HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessat75_HeatingAirFlow, d.get()); - } - - // LatentEffectivenessat75_HeatingAirFlow - d = modelObject.latentEffectivenessat75HeatingAirFlow(); - if (d) { - idfObject.setDouble(HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessat75_HeatingAirFlow, d.get()); - } - // SensibleEffectivenessat100_CoolingAirFlow d = modelObject.sensibleEffectivenessat100CoolingAirFlow(); if (d) { @@ -87,18 +76,6 @@ namespace energyplus { idfObject.setDouble(HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessat100_CoolingAirFlow, d.get()); } - // SensibleEffectivenessat75_CoolingAirFlow - d = modelObject.sensibleEffectivenessat75CoolingAirFlow(); - if (d) { - idfObject.setDouble(HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessat75_CoolingAirFlow, d.get()); - } - - // LatentEffectivenessat75_CoolingAirFlow - d = modelObject.latentEffectivenessat75CoolingAirFlow(); - if (d) { - idfObject.setDouble(HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessat75_CoolingAirFlow, d.get()); - } - // SupplyAirInletNodeName temp = modelObject.primaryAirInletModelObject(); if (temp) { @@ -185,6 +162,34 @@ namespace energyplus { idfObject.setString(HeatExchanger_AirToAir_SensibleAndLatentFields::EconomizerLockout, "No"); } + // SensibleEffectivenessofHeatingAirFlowCurveName + if (boost::optional sensibleEffectivenessofHeatingAirFlowCurve_ = modelObject.sensibleEffectivenessofHeatingAirFlowCurve()) { + if (boost::optional wo_ = translateAndMapModelObject(sensibleEffectivenessofHeatingAirFlowCurve_.get())) { + idfObject.setString(HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessofHeatingAirFlowCurveName, wo_->nameString()); + } + } + + // LatentEffectivenessofHeatingAirFlowCurveName + if (boost::optional latentEffectivenessofHeatingAirFlowCurve_ = modelObject.latentEffectivenessofHeatingAirFlowCurve()) { + if (boost::optional wo_ = translateAndMapModelObject(latentEffectivenessofHeatingAirFlowCurve_.get())) { + idfObject.setString(HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessofHeatingAirFlowCurveName, wo_->nameString()); + } + } + + // SensibleEffectivenessofCoolingAirFlowCurveName + if (boost::optional sensibleEffectivenessofCoolingAirFlowCurve_ = modelObject.sensibleEffectivenessofCoolingAirFlowCurve()) { + if (boost::optional wo_ = translateAndMapModelObject(sensibleEffectivenessofCoolingAirFlowCurve_.get())) { + idfObject.setString(HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessofCoolingAirFlowCurveName, wo_->nameString()); + } + } + + // LatentEffectivenessofCoolingAirFlowCurveName + if (boost::optional latentEffectivenessofCoolingAirFlowCurve_ = modelObject.latentEffectivenessofCoolingAirFlowCurve()) { + if (boost::optional wo_ = translateAndMapModelObject(latentEffectivenessofCoolingAirFlowCurve_.get())) { + idfObject.setString(HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessofCoolingAirFlowCurveName, wo_->nameString()); + } + } + return idfObject; } diff --git a/src/model/HeatExchangerAirToAirSensibleAndLatent.cpp b/src/model/HeatExchangerAirToAirSensibleAndLatent.cpp index 13ed43bf37..55209a07cb 100644 --- a/src/model/HeatExchangerAirToAirSensibleAndLatent.cpp +++ b/src/model/HeatExchangerAirToAirSensibleAndLatent.cpp @@ -17,14 +17,24 @@ #include "ScheduleTypeRegistry.hpp" #include "AirflowNetworkEquivalentDuct.hpp" #include "AirflowNetworkEquivalentDuct_Impl.hpp" +#include "Curve.hpp" +#include "Curve_Impl.hpp" +#include "TableLookup.hpp" +#include "TableLookup_Impl.hpp" +#include "TableIndependentVariable.hpp" +#include "TableIndependentVariable_Impl.hpp" #include "../utilities/core/Assert.hpp" #include "../utilities/data/DataEnums.hpp" +#include "../utilities/math/FloatCompare.hpp" #include #include #include +// Remove when deprecated methods are removed +#include "../utilities/core/DeprecatedHelpers.hpp" + namespace openstudio { namespace model { @@ -174,18 +184,6 @@ namespace model { return value.get(); } - double HeatExchangerAirToAirSensibleAndLatent_Impl::sensibleEffectivenessat75HeatingAirFlow() const { - boost::optional value = getDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessat75_HeatingAirFlow, true); - OS_ASSERT(value); - return value.get(); - } - - double HeatExchangerAirToAirSensibleAndLatent_Impl::latentEffectivenessat75HeatingAirFlow() const { - boost::optional value = getDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessat75_HeatingAirFlow, true); - OS_ASSERT(value); - return value.get(); - } - double HeatExchangerAirToAirSensibleAndLatent_Impl::sensibleEffectivenessat100CoolingAirFlow() const { boost::optional value = getDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessat100_CoolingAirFlow, true); OS_ASSERT(value); @@ -198,18 +196,6 @@ namespace model { return value.get(); } - double HeatExchangerAirToAirSensibleAndLatent_Impl::sensibleEffectivenessat75CoolingAirFlow() const { - boost::optional value = getDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessat75_CoolingAirFlow, true); - OS_ASSERT(value); - return value.get(); - } - - double HeatExchangerAirToAirSensibleAndLatent_Impl::latentEffectivenessat75CoolingAirFlow() const { - boost::optional value = getDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessat75_CoolingAirFlow, true); - OS_ASSERT(value); - return value.get(); - } - double HeatExchangerAirToAirSensibleAndLatent_Impl::nominalElectricPower() const { boost::optional value = getDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::NominalElectricPower, true); OS_ASSERT(value); @@ -258,6 +244,26 @@ namespace model { return openstudio::istringEqual(value.get(), "Yes"); } + boost::optional HeatExchangerAirToAirSensibleAndLatent_Impl::sensibleEffectivenessofHeatingAirFlowCurve() const { + return getObject().getModelObjectTarget( + OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessofHeatingAirFlowCurveName); + } + + boost::optional HeatExchangerAirToAirSensibleAndLatent_Impl::latentEffectivenessofHeatingAirFlowCurve() const { + return getObject().getModelObjectTarget( + OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessofHeatingAirFlowCurveName); + } + + boost::optional HeatExchangerAirToAirSensibleAndLatent_Impl::sensibleEffectivenessofCoolingAirFlowCurve() const { + return getObject().getModelObjectTarget( + OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessofCoolingAirFlowCurveName); + } + + boost::optional HeatExchangerAirToAirSensibleAndLatent_Impl::latentEffectivenessofCoolingAirFlowCurve() const { + return getObject().getModelObjectTarget( + OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessofCoolingAirFlowCurveName); + } + bool HeatExchangerAirToAirSensibleAndLatent_Impl::setAvailabilitySchedule(Schedule& schedule) { bool result = setSchedule(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::AvailabilitySchedule, "HeatExchangerAirToAirSensibleAndLatent", "Availability", schedule); @@ -278,53 +284,33 @@ namespace model { } bool HeatExchangerAirToAirSensibleAndLatent_Impl::setSensibleEffectivenessat100HeatingAirFlow(double sensibleEffectivenessat100HeatingAirFlow) { + // FIXME: wouldn't this value need to get set on the tablelookup if it exists? bool result = setDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessat100_HeatingAirFlow, sensibleEffectivenessat100HeatingAirFlow); return result; } bool HeatExchangerAirToAirSensibleAndLatent_Impl::setLatentEffectivenessat100HeatingAirFlow(double latentEffectivenessat100HeatingAirFlow) { + // FIXME: wouldn't this value need to get set on the tablelookup if it exists? bool result = setDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessat100_HeatingAirFlow, latentEffectivenessat100HeatingAirFlow); return result; } - bool HeatExchangerAirToAirSensibleAndLatent_Impl::setSensibleEffectivenessat75HeatingAirFlow(double sensibleEffectivenessat75HeatingAirFlow) { - bool result = setDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessat75_HeatingAirFlow, - sensibleEffectivenessat75HeatingAirFlow); - return result; - } - - bool HeatExchangerAirToAirSensibleAndLatent_Impl::setLatentEffectivenessat75HeatingAirFlow(double latentEffectivenessat75HeatingAirFlow) { - bool result = - setDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessat75_HeatingAirFlow, latentEffectivenessat75HeatingAirFlow); - return result; - } - bool HeatExchangerAirToAirSensibleAndLatent_Impl::setSensibleEffectivenessat100CoolingAirFlow(double sensibleEffectivenessat100CoolingAirFlow) { + // FIXME: wouldn't this value need to get set on the tablelookup if it exists? bool result = setDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessat100_CoolingAirFlow, sensibleEffectivenessat100CoolingAirFlow); return result; } bool HeatExchangerAirToAirSensibleAndLatent_Impl::setLatentEffectivenessat100CoolingAirFlow(double latentEffectivenessat100CoolingAirFlow) { + // FIXME: wouldn't this value need to get set on the tablelookup if it exists? bool result = setDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessat100_CoolingAirFlow, latentEffectivenessat100CoolingAirFlow); return result; } - bool HeatExchangerAirToAirSensibleAndLatent_Impl::setSensibleEffectivenessat75CoolingAirFlow(double sensibleEffectivenessat75CoolingAirFlow) { - bool result = setDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessat75_CoolingAirFlow, - sensibleEffectivenessat75CoolingAirFlow); - return result; - } - - bool HeatExchangerAirToAirSensibleAndLatent_Impl::setLatentEffectivenessat75CoolingAirFlow(double latentEffectivenessat75CoolingAirFlow) { - bool result = - setDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessat75_CoolingAirFlow, latentEffectivenessat75CoolingAirFlow); - return result; - } - bool HeatExchangerAirToAirSensibleAndLatent_Impl::setNominalElectricPower(double nominalElectricPower) { bool result = setDouble(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::NominalElectricPower, nominalElectricPower); return result; @@ -394,6 +380,54 @@ namespace model { return setBooleanFieldValue(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::EconomizerLockout, economizerLockout); } + bool HeatExchangerAirToAirSensibleAndLatent_Impl::setSensibleEffectivenessofHeatingAirFlowCurve( + const Curve& sensibleEffectivenessofHeatingAirFlowCurve) { + bool result = setPointer(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessofHeatingAirFlowCurveName, + sensibleEffectivenessofHeatingAirFlowCurve.handle()); + return result; + } + + bool HeatExchangerAirToAirSensibleAndLatent_Impl::setLatentEffectivenessofHeatingAirFlowCurve( + const Curve& latentEffectivenessofHeatingAirFlowCurve) { + bool result = setPointer(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessofHeatingAirFlowCurveName, + latentEffectivenessofHeatingAirFlowCurve.handle()); + return result; + } + + bool HeatExchangerAirToAirSensibleAndLatent_Impl::setSensibleEffectivenessofCoolingAirFlowCurve( + const Curve& sensibleEffectivenessofCoolingAirFlowCurve) { + bool result = setPointer(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessofCoolingAirFlowCurveName, + sensibleEffectivenessofCoolingAirFlowCurve.handle()); + return result; + } + + bool HeatExchangerAirToAirSensibleAndLatent_Impl::setLatentEffectivenessofCoolingAirFlowCurve( + const Curve& latentEffectivenessofCoolingAirFlowCurve) { + bool result = setPointer(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessofCoolingAirFlowCurveName, + latentEffectivenessofCoolingAirFlowCurve.handle()); + return result; + } + + void HeatExchangerAirToAirSensibleAndLatent_Impl::resetSensibleEffectivenessofHeatingAirFlowCurve() { + bool result = setString(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessofHeatingAirFlowCurveName, ""); + OS_ASSERT(result); + } + + void HeatExchangerAirToAirSensibleAndLatent_Impl::resetLatentEffectivenessofHeatingAirFlowCurve() { + bool result = setString(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessofHeatingAirFlowCurveName, ""); + OS_ASSERT(result); + } + + void HeatExchangerAirToAirSensibleAndLatent_Impl::resetSensibleEffectivenessofCoolingAirFlowCurve() { + bool result = setString(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::SensibleEffectivenessofCoolingAirFlowCurveName, ""); + OS_ASSERT(result); + } + + void HeatExchangerAirToAirSensibleAndLatent_Impl::resetLatentEffectivenessofCoolingAirFlowCurve() { + bool result = setString(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::LatentEffectivenessofCoolingAirFlowCurveName, ""); + OS_ASSERT(result); + } + boost::optional HeatExchangerAirToAirSensibleAndLatent_Impl::optionalAvailabilitySchedule() const { return getObject().getModelObjectTarget(OS_HeatExchanger_AirToAir_SensibleAndLatentFields::AvailabilitySchedule); } @@ -511,18 +545,10 @@ namespace model { setLatentEffectivenessat100HeatingAirFlow(0.68); - setSensibleEffectivenessat75HeatingAirFlow(0.81); - - setLatentEffectivenessat75HeatingAirFlow(0.73); - setSensibleEffectivenessat100CoolingAirFlow(0.76); setLatentEffectivenessat100CoolingAirFlow(0.68); - setSensibleEffectivenessat75CoolingAirFlow(0.81); - - setLatentEffectivenessat75CoolingAirFlow(0.73); - setNominalElectricPower(0.0); setSupplyAirOutletTemperatureControl(true); @@ -536,6 +562,87 @@ namespace model { setEconomizerLockout(true); } + bool HeatExchangerAirToAirSensibleAndLatent::assignHistoricalEffectivenessCurves() { + + Model model = this->model(); + + TableIndependentVariable var(model); + var.setName(nameString() + "_IndependentVariable"); + var.setInterpolationMethod("Linear"); + var.setExtrapolationMethod("Linear"); + var.setMinimumValue(0.0); + var.setMaximumValue(10.0); + var.setUnitType("Dimensionless"); + var.addValue(0.75); + var.addValue(1.0); + + { + TableLookup s75heating(model); + s75heating.setName(fmt::format("{}_SensHeatEff", nameString())); + s75heating.addIndependentVariable(var); + + s75heating.setNormalizationMethod("DivisorOnly"); + s75heating.setNormalizationDivisor(0.76); + s75heating.setMinimumOutput(0.0); + s75heating.setMaximumOutput(10.0); + s75heating.setOutputUnitType("Dimensionless"); + s75heating.addOutputValue(0.81); + s75heating.addOutputValue(0.76); + + setSensibleEffectivenessofHeatingAirFlowCurve(s75heating); + } + + { + TableLookup l75heating(model); + l75heating.setName(fmt::format("{}_LatHeatEff", nameString())); + l75heating.addIndependentVariable(var); + + l75heating.setNormalizationMethod("DivisorOnly"); + l75heating.setNormalizationDivisor(0.68); + l75heating.setMinimumOutput(0.0); + l75heating.setMaximumOutput(10.0); + l75heating.setOutputUnitType("Dimensionless"); + l75heating.addOutputValue(0.73); + l75heating.addOutputValue(0.68); + + setLatentEffectivenessofHeatingAirFlowCurve(l75heating); + } + + { + TableLookup s75cooling(model); + s75cooling.setName(fmt::format("{}_SensCoolEff", nameString())); + s75cooling.addIndependentVariable(var); + + s75cooling.setNormalizationMethod("DivisorOnly"); + s75cooling.setNormalizationDivisor(0.76); + s75cooling.setMinimumOutput(0.0); + s75cooling.setMaximumOutput(10.0); + s75cooling.setOutputUnitType("Dimensionless"); + s75cooling.addOutputValue(0.81); + s75cooling.addOutputValue(0.76); + + setSensibleEffectivenessofCoolingAirFlowCurve(s75cooling); + } + + { + TableLookup l75cooling(model); + l75cooling.setName(fmt::format("{}_LatCoolEff", nameString())); + l75cooling.addIndependentVariable(var); + + l75cooling.setNormalizationMethod("DivisorOnly"); + l75cooling.setNormalizationDivisor(0.68); + l75cooling.setMinimumOutput(0.0); + l75cooling.setMaximumOutput(10.0); + l75cooling.setOutputUnitType("Dimensionless"); + l75cooling.addOutputValue(0.73); + l75cooling.addOutputValue(0.68); + + setLatentEffectivenessofCoolingAirFlowCurve(l75cooling); + } + + return true; + } + IddObjectType HeatExchangerAirToAirSensibleAndLatent::iddObjectType() { return {IddObjectType::OS_HeatExchanger_AirToAir_SensibleAndLatent}; } @@ -570,14 +677,6 @@ namespace model { return getImpl()->latentEffectivenessat100HeatingAirFlow(); } - double HeatExchangerAirToAirSensibleAndLatent::sensibleEffectivenessat75HeatingAirFlow() const { - return getImpl()->sensibleEffectivenessat75HeatingAirFlow(); - } - - double HeatExchangerAirToAirSensibleAndLatent::latentEffectivenessat75HeatingAirFlow() const { - return getImpl()->latentEffectivenessat75HeatingAirFlow(); - } - double HeatExchangerAirToAirSensibleAndLatent::sensibleEffectivenessat100CoolingAirFlow() const { return getImpl()->sensibleEffectivenessat100CoolingAirFlow(); } @@ -586,14 +685,6 @@ namespace model { return getImpl()->latentEffectivenessat100CoolingAirFlow(); } - double HeatExchangerAirToAirSensibleAndLatent::sensibleEffectivenessat75CoolingAirFlow() const { - return getImpl()->sensibleEffectivenessat75CoolingAirFlow(); - } - - double HeatExchangerAirToAirSensibleAndLatent::latentEffectivenessat75CoolingAirFlow() const { - return getImpl()->latentEffectivenessat75CoolingAirFlow(); - } - double HeatExchangerAirToAirSensibleAndLatent::nominalElectricPower() const { return getImpl()->nominalElectricPower(); } @@ -630,6 +721,22 @@ namespace model { return getImpl()->economizerLockout(); } + boost::optional HeatExchangerAirToAirSensibleAndLatent::sensibleEffectivenessofHeatingAirFlowCurve() const { + return getImpl()->sensibleEffectivenessofHeatingAirFlowCurve(); + } + + boost::optional HeatExchangerAirToAirSensibleAndLatent::latentEffectivenessofHeatingAirFlowCurve() const { + return getImpl()->latentEffectivenessofHeatingAirFlowCurve(); + } + + boost::optional HeatExchangerAirToAirSensibleAndLatent::sensibleEffectivenessofCoolingAirFlowCurve() const { + return getImpl()->sensibleEffectivenessofCoolingAirFlowCurve(); + } + + boost::optional HeatExchangerAirToAirSensibleAndLatent::latentEffectivenessofCoolingAirFlowCurve() const { + return getImpl()->latentEffectivenessofCoolingAirFlowCurve(); + } + bool HeatExchangerAirToAirSensibleAndLatent::setAvailabilitySchedule(Schedule& schedule) { return getImpl()->setAvailabilitySchedule(schedule); } @@ -652,16 +759,6 @@ namespace model { latentEffectivenessat100HeatingAirFlow); } - bool HeatExchangerAirToAirSensibleAndLatent::setSensibleEffectivenessat75HeatingAirFlow(double sensibleEffectivenessat75HeatingAirFlow) { - return getImpl()->setSensibleEffectivenessat75HeatingAirFlow( - sensibleEffectivenessat75HeatingAirFlow); - } - - bool HeatExchangerAirToAirSensibleAndLatent::setLatentEffectivenessat75HeatingAirFlow(double latentEffectivenessat75HeatingAirFlow) { - return getImpl()->setLatentEffectivenessat75HeatingAirFlow( - latentEffectivenessat75HeatingAirFlow); - } - bool HeatExchangerAirToAirSensibleAndLatent::setSensibleEffectivenessat100CoolingAirFlow(double sensibleEffectivenessat100CoolingAirFlow) { return getImpl()->setSensibleEffectivenessat100CoolingAirFlow( sensibleEffectivenessat100CoolingAirFlow); @@ -672,16 +769,6 @@ namespace model { latentEffectivenessat100CoolingAirFlow); } - bool HeatExchangerAirToAirSensibleAndLatent::setSensibleEffectivenessat75CoolingAirFlow(double sensibleEffectivenessat75CoolingAirFlow) { - return getImpl()->setSensibleEffectivenessat75CoolingAirFlow( - sensibleEffectivenessat75CoolingAirFlow); - } - - bool HeatExchangerAirToAirSensibleAndLatent::setLatentEffectivenessat75CoolingAirFlow(double latentEffectivenessat75CoolingAirFlow) { - return getImpl()->setLatentEffectivenessat75CoolingAirFlow( - latentEffectivenessat75CoolingAirFlow); - } - bool HeatExchangerAirToAirSensibleAndLatent::setNominalElectricPower(double nominalElectricPower) { return getImpl()->setNominalElectricPower(nominalElectricPower); } @@ -726,6 +813,44 @@ namespace model { return getImpl()->setEconomizerLockout(economizerLockout); } + bool + HeatExchangerAirToAirSensibleAndLatent::setSensibleEffectivenessofHeatingAirFlowCurve(const Curve& sensibleEffectivenessofHeatingAirFlowCurve) { + return getImpl()->setSensibleEffectivenessofHeatingAirFlowCurve( + sensibleEffectivenessofHeatingAirFlowCurve); + } + + void HeatExchangerAirToAirSensibleAndLatent::resetSensibleEffectivenessofHeatingAirFlowCurve() { + getImpl()->resetSensibleEffectivenessofHeatingAirFlowCurve(); + } + + bool HeatExchangerAirToAirSensibleAndLatent::setLatentEffectivenessofHeatingAirFlowCurve(const Curve& latentEffectivenessofHeatingAirFlowCurve) { + return getImpl()->setLatentEffectivenessofHeatingAirFlowCurve( + latentEffectivenessofHeatingAirFlowCurve); + } + + void HeatExchangerAirToAirSensibleAndLatent::resetLatentEffectivenessofHeatingAirFlowCurve() { + getImpl()->resetLatentEffectivenessofHeatingAirFlowCurve(); + } + + bool + HeatExchangerAirToAirSensibleAndLatent::setSensibleEffectivenessofCoolingAirFlowCurve(const Curve& sensibleEffectivenessofCoolingAirFlowCurve) { + return getImpl()->setSensibleEffectivenessofCoolingAirFlowCurve( + sensibleEffectivenessofCoolingAirFlowCurve); + } + + void HeatExchangerAirToAirSensibleAndLatent::resetSensibleEffectivenessofCoolingAirFlowCurve() { + getImpl()->resetSensibleEffectivenessofCoolingAirFlowCurve(); + } + + bool HeatExchangerAirToAirSensibleAndLatent::setLatentEffectivenessofCoolingAirFlowCurve(const Curve& latentEffectivenessofCoolingAirFlowCurve) { + return getImpl()->setLatentEffectivenessofCoolingAirFlowCurve( + latentEffectivenessofCoolingAirFlowCurve); + } + + void HeatExchangerAirToAirSensibleAndLatent::resetLatentEffectivenessofCoolingAirFlowCurve() { + getImpl()->resetLatentEffectivenessofCoolingAirFlowCurve(); + } + AirflowNetworkEquivalentDuct HeatExchangerAirToAirSensibleAndLatent::getAirflowNetworkEquivalentDuct(double length, double diameter) { return getImpl()->getAirflowNetworkEquivalentDuct(length, diameter); } @@ -744,5 +869,203 @@ namespace model { return getImpl()->autosizedNominalSupplyAirFlowRate(); } + // DEPRECATED + + boost::optional evalCurveAt75(const Curve& curve) { + if (boost::optional tableLookup_ = curve.optionalCast()) { + if (tableLookup_->numVariables() == 1) { + if (!tableLookup_->outputValues().empty() && !tableLookup_->independentVariables().front().values().empty() + && openstudio::equal(tableLookup_->independentVariables().front().values().front(), 0.75)) { + auto val = tableLookup_->outputValues().front(); + + auto normMethod = tableLookup_->normalizationMethod(); + if (istringEqual(normMethod, "None")) { + // No-op + + } else if (istringEqual(normMethod, "DivisorOnly")) { + val /= tableLookup_->normalizationDivisor(); + } else if (istringEqual(normMethod, "AutomaticWithDivisor")) { + const double i = tableLookup_->independentVariables().front().normalizationReferenceValue().get_value_or(1.0); + val /= tableLookup_->normalizationDivisor(); + val /= i; + } + return val; + } + } else { + LOG_FREE(Warn, "openstudio.model.HeatExchangerAirToAirSensibleAndLatent", "Wrong number of variables"); + } + } else { + return curve.evaluate(0.75); + } + + return boost::none; + } + + double HeatExchangerAirToAirSensibleAndLatent::sensibleEffectivenessat75HeatingAirFlow() const { + DEPRECATED_AT_MSG(3, 8, 0, "Use sensibleEffectivenessofHeatingAirFlowCurve instead."); + + auto eff100 = sensibleEffectivenessat100HeatingAirFlow(); + + if (auto curve_ = sensibleEffectivenessofHeatingAirFlowCurve()) { + auto val = evalCurveAt75(*curve_); + if (val && *val > 0.0) { + return *val * eff100; + } else { + LOG(Warn, briefDescription() << " has a sensibleEffectivenessofHeatingAirFlowCurve assigned but failed to retrieve the value at 0.75."); + } + } + + // Constant effectiveness if no curves + return eff100; + } + + double HeatExchangerAirToAirSensibleAndLatent::latentEffectivenessat75HeatingAirFlow() const { + DEPRECATED_AT_MSG(3, 8, 0, "Use latentEffectivenessofHeatingAirFlowCurve instead."); + + auto eff100 = latentEffectivenessat100HeatingAirFlow(); + + if (auto curve_ = latentEffectivenessofHeatingAirFlowCurve()) { + auto val = evalCurveAt75(*curve_); + if (val && *val > 0.0) { + return *val * eff100; + } else { + LOG(Warn, briefDescription() << " has a latentEffectivenessofHeatingAirFlowCurve assigned but failed to retrieve the value at 0.75."); + } + } + + // Constant effectiveness if no curves + return eff100; + } + + double HeatExchangerAirToAirSensibleAndLatent::sensibleEffectivenessat75CoolingAirFlow() const { + DEPRECATED_AT_MSG(3, 8, 0, "Use sensibleEffectivenessofCoolingAirFlowCurve instead."); + + auto eff100 = sensibleEffectivenessat100CoolingAirFlow(); + + if (auto curve_ = sensibleEffectivenessofCoolingAirFlowCurve()) { + auto val = evalCurveAt75(*curve_); + if (val && *val > 0.0) { + return *val * eff100; + } else { + LOG(Warn, briefDescription() << " has a sensibleEffectivenessofCoolingAirFlowCurve assigned but failed to retrieve the value at 0.75."); + } + } + + // Constant effectiveness if no curves + return eff100; + } + + double HeatExchangerAirToAirSensibleAndLatent::latentEffectivenessat75CoolingAirFlow() const { + DEPRECATED_AT_MSG(3, 8, 0, "Use latentEffectivenessofCoolingAirFlowCurve instead."); + + auto eff100 = latentEffectivenessat100CoolingAirFlow(); + + if (auto curve_ = latentEffectivenessofCoolingAirFlowCurve()) { + auto val = evalCurveAt75(*curve_); + if (val && *val > 0.0) { + return *val * eff100; + } else { + LOG(Warn, briefDescription() << " has a latentEffectivenessofCoolingAirFlowCurve assigned but failed to retrieve the value at 0.75."); + } + } + + return eff100; + } + + bool setCurveAt75(const Curve& curve, double valueAt75) { + + if (boost::optional tableLookup_ = curve.optionalCast()) { + + if (tableLookup_->numVariables() != 1) { + LOG_FREE(Warn, "openstudio.model.HeatExchangerAirToAirSensibleAndLatent", "Wrong number of variables"); + return false; + } + + auto indVarVals = tableLookup_->independentVariables().front().values(); + auto outVals = tableLookup_->outputValues(); + + if (!outVals.empty() && !indVarVals.empty() && openstudio::equal(indVarVals.front(), 0.75)) { + outVals.front() = valueAt75; + return tableLookup_->setOutputValues(outVals); + } + } + + LOG_FREE(Warn, "openstudio.model.HeatExchangerAirToAirSensibleAndLatent", "Cannot set effectiveness for a Curve that isn't a TableLookup."); + return false; + } + + TableLookup makeTable(double val75, double val100, const Model& model, const std::string& tableName) { + TableIndependentVariable var(model); + var.setName(fmt::format("{}_IndependentVariable", tableName)); + var.setInterpolationMethod("Linear"); + var.setExtrapolationMethod("Linear"); + var.setMinimumValue(0.0); + var.setMaximumValue(10.0); + var.setUnitType("Dimensionless"); + var.addValue(0.75); + var.addValue(1.0); + + TableLookup tableLookup(model); + tableLookup.setName(tableName); + tableLookup.setNormalizationMethod("DivisorOnly"); + tableLookup.setNormalizationDivisor(val100); + tableLookup.setMinimumOutput(0.0); + tableLookup.setMaximumOutput(10.0); + tableLookup.setOutputUnitType("Dimensionless"); + tableLookup.addOutputValue(val75); + tableLookup.addOutputValue(val100); + tableLookup.addIndependentVariable(var); + + return tableLookup; + } + + bool HeatExchangerAirToAirSensibleAndLatent::setSensibleEffectivenessat75HeatingAirFlow(double sensibleEffectivenessat75HeatingAirFlow) { + DEPRECATED_AT_MSG(3, 8, 0, "Use sensibleEffectivenessofHeatingAirFlowCurve instead."); + + if (auto curve_ = sensibleEffectivenessofHeatingAirFlowCurve()) { + return setCurveAt75(*curve_, sensibleEffectivenessat75HeatingAirFlow); + } + + auto tableLookup = makeTable(sensibleEffectivenessat75HeatingAirFlow, sensibleEffectivenessat100HeatingAirFlow(), model(), + fmt::format("{}_SensHeatEff", nameString())); + return setSensibleEffectivenessofHeatingAirFlowCurve(tableLookup); + } + + bool HeatExchangerAirToAirSensibleAndLatent::setLatentEffectivenessat75HeatingAirFlow(double latentEffectivenessat75HeatingAirFlow) { + DEPRECATED_AT_MSG(3, 8, 0, "Use latentEffectivenessofHeatingAirFlowCurve instead."); + + if (auto curve_ = latentEffectivenessofHeatingAirFlowCurve()) { + return setCurveAt75(*curve_, latentEffectivenessat75HeatingAirFlow); + } + + auto tableLookup = + makeTable(latentEffectivenessat75HeatingAirFlow, latentEffectivenessat100HeatingAirFlow(), model(), fmt::format("{}_LatHeatEff", nameString())); + return setLatentEffectivenessofHeatingAirFlowCurve(tableLookup); + } + + bool HeatExchangerAirToAirSensibleAndLatent::setSensibleEffectivenessat75CoolingAirFlow(double sensibleEffectivenessat75CoolingAirFlow) { + DEPRECATED_AT_MSG(3, 8, 0, "Use sensibleEffectivenessofCoolingAirFlowCurve instead."); + + if (auto curve_ = sensibleEffectivenessofCoolingAirFlowCurve()) { + return setCurveAt75(*curve_, sensibleEffectivenessat75CoolingAirFlow); + } + + auto tableLookup = makeTable(sensibleEffectivenessat75CoolingAirFlow, sensibleEffectivenessat100CoolingAirFlow(), model(), + fmt::format("{}_SensCoolEff", nameString())); + return setSensibleEffectivenessofCoolingAirFlowCurve(tableLookup); + } + + bool HeatExchangerAirToAirSensibleAndLatent::setLatentEffectivenessat75CoolingAirFlow(double latentEffectivenessat75CoolingAirFlow) { + DEPRECATED_AT_MSG(3, 8, 0, "Use latentEffectivenessofCoolingAirFlowCurve instead."); + + if (auto curve_ = latentEffectivenessofCoolingAirFlowCurve()) { + return setCurveAt75(*curve_, latentEffectivenessat75CoolingAirFlow); + } + + auto tableLookup = + makeTable(latentEffectivenessat75CoolingAirFlow, latentEffectivenessat100CoolingAirFlow(), model(), fmt::format("{}_LatCoolEff", nameString())); + return setLatentEffectivenessofCoolingAirFlowCurve(tableLookup); + } + } // namespace model } // namespace openstudio diff --git a/src/model/HeatExchangerAirToAirSensibleAndLatent.hpp b/src/model/HeatExchangerAirToAirSensibleAndLatent.hpp index 0e5737bd50..6dcbdb69ce 100644 --- a/src/model/HeatExchangerAirToAirSensibleAndLatent.hpp +++ b/src/model/HeatExchangerAirToAirSensibleAndLatent.hpp @@ -9,12 +9,15 @@ #include "ModelAPI.hpp" #include "AirToAirComponent.hpp" +#include "../utilities/core/Deprecated.hpp" + namespace openstudio { namespace model { class Schedule; class AirflowNetworkEquivalentDuct; + class Curve; namespace detail { @@ -27,6 +30,12 @@ namespace model { { public: + /** @name Constructors and Destructors */ + //@{ + + /** Constructor. It will **not** instantiate the optional effectivness curve/tables objects and effectiveness will be constant. + * You can then call the helper method `bool assignHistoricalEffectivenessCurves()` to assign 4 TableLookups that will match the pre E+ 24.1.0 + * defaults for Sensible/Latent Effectiveness at 75% Heating/Cooling airflow */ explicit HeatExchangerAirToAirSensibleAndLatent(const Model& model); virtual ~HeatExchangerAirToAirSensibleAndLatent() = default; @@ -36,6 +45,8 @@ namespace model { HeatExchangerAirToAirSensibleAndLatent& operator=(const HeatExchangerAirToAirSensibleAndLatent&) = default; HeatExchangerAirToAirSensibleAndLatent& operator=(HeatExchangerAirToAirSensibleAndLatent&&) = default; + //@} + static IddObjectType iddObjectType(); static std::vector heatExchangerTypeValues(); @@ -62,13 +73,13 @@ namespace model { bool setLatentEffectivenessat100HeatingAirFlow(double latentEffectivenessat100HeatingAirFlow); - double sensibleEffectivenessat75HeatingAirFlow() const; + OS_DEPRECATED(3, 8, 0) double sensibleEffectivenessat75HeatingAirFlow() const; - bool setSensibleEffectivenessat75HeatingAirFlow(double sensibleEffectivenessat75HeatingAirFlow); + OS_DEPRECATED(3, 8, 0) bool setSensibleEffectivenessat75HeatingAirFlow(double sensibleEffectivenessat75HeatingAirFlow); - double latentEffectivenessat75HeatingAirFlow() const; + OS_DEPRECATED(3, 8, 0) double latentEffectivenessat75HeatingAirFlow() const; - bool setLatentEffectivenessat75HeatingAirFlow(double latentEffectivenessat75HeatingAirFlow); + OS_DEPRECATED(3, 8, 0) bool setLatentEffectivenessat75HeatingAirFlow(double latentEffectivenessat75HeatingAirFlow); double sensibleEffectivenessat100CoolingAirFlow() const; @@ -78,13 +89,13 @@ namespace model { bool setLatentEffectivenessat100CoolingAirFlow(double latentEffectivenessat100CoolingAirFlow); - double sensibleEffectivenessat75CoolingAirFlow() const; + OS_DEPRECATED(3, 8, 0) double sensibleEffectivenessat75CoolingAirFlow() const; - bool setSensibleEffectivenessat75CoolingAirFlow(double sensibleEffectivenessat75CoolingAirFlow); + OS_DEPRECATED(3, 8, 0) bool setSensibleEffectivenessat75CoolingAirFlow(double sensibleEffectivenessat75CoolingAirFlow); - double latentEffectivenessat75CoolingAirFlow() const; + OS_DEPRECATED(3, 8, 0) double latentEffectivenessat75CoolingAirFlow() const; - bool setLatentEffectivenessat75CoolingAirFlow(double latentEffectivenessat75CoolingAirFlow); + OS_DEPRECATED(3, 8, 0) bool setLatentEffectivenessat75CoolingAirFlow(double latentEffectivenessat75CoolingAirFlow); double nominalElectricPower() const; @@ -126,11 +137,35 @@ namespace model { bool setEconomizerLockout(bool economizerLockout); + boost::optional sensibleEffectivenessofHeatingAirFlowCurve() const; + bool setSensibleEffectivenessofHeatingAirFlowCurve(const Curve& sensibleEffectivenessofHeatingAirFlowCurve); + void resetSensibleEffectivenessofHeatingAirFlowCurve(); + + boost::optional latentEffectivenessofHeatingAirFlowCurve() const; + bool setLatentEffectivenessofHeatingAirFlowCurve(const Curve& latentEffectivenessofHeatingAirFlowCurve); + void resetLatentEffectivenessofHeatingAirFlowCurve(); + + boost::optional sensibleEffectivenessofCoolingAirFlowCurve() const; + bool setSensibleEffectivenessofCoolingAirFlowCurve(const Curve& sensibleEffectivenessofCoolingAirFlowCurve); + void resetSensibleEffectivenessofCoolingAirFlowCurve(); + + boost::optional latentEffectivenessofCoolingAirFlowCurve() const; + bool setLatentEffectivenessofCoolingAirFlowCurve(const Curve& latentEffectivenessofCoolingAirFlowCurve); + void resetLatentEffectivenessofCoolingAirFlowCurve(); + + /** @name Other */ + //@{ + boost::optional autosizedNominalSupplyAirFlowRate() const; AirflowNetworkEquivalentDuct getAirflowNetworkEquivalentDuct(double length, double diameter); boost::optional airflowNetworkEquivalentDuct() const; + // Helper that creates defaulted Optional Curves (TableLookups) to match the pre E+ 24.1.0 effectiveness defaults + bool assignHistoricalEffectivenessCurves(); + + //@} + protected: /// @cond using ImplType = detail::HeatExchangerAirToAirSensibleAndLatent_Impl; diff --git a/src/model/HeatExchangerAirToAirSensibleAndLatent_Impl.hpp b/src/model/HeatExchangerAirToAirSensibleAndLatent_Impl.hpp index 3070cb6065..f25df1e29f 100644 --- a/src/model/HeatExchangerAirToAirSensibleAndLatent_Impl.hpp +++ b/src/model/HeatExchangerAirToAirSensibleAndLatent_Impl.hpp @@ -14,6 +14,7 @@ namespace model { class Schedule; class Connection; + class Curve; namespace detail { @@ -84,18 +85,10 @@ namespace model { double latentEffectivenessat100HeatingAirFlow() const; - double sensibleEffectivenessat75HeatingAirFlow() const; - - double latentEffectivenessat75HeatingAirFlow() const; - double sensibleEffectivenessat100CoolingAirFlow() const; double latentEffectivenessat100CoolingAirFlow() const; - double sensibleEffectivenessat75CoolingAirFlow() const; - - double latentEffectivenessat75CoolingAirFlow() const; - double nominalElectricPower() const; bool supplyAirOutletTemperatureControl() const; @@ -114,7 +107,13 @@ namespace model { bool economizerLockout() const; - boost::optional autosizedNominalSupplyAirFlowRate() const; + boost::optional sensibleEffectivenessofHeatingAirFlowCurve() const; + + boost::optional latentEffectivenessofHeatingAirFlowCurve() const; + + boost::optional sensibleEffectivenessofCoolingAirFlowCurve() const; + + boost::optional latentEffectivenessofCoolingAirFlowCurve() const; //@} /** @name Setters */ @@ -123,25 +122,16 @@ namespace model { bool setAvailabilitySchedule(Schedule& schedule); bool setNominalSupplyAirFlowRate(boost::optional nominalSupplyAirFlowRate); - void autosizeNominalSupplyAirFlowRate(); bool setSensibleEffectivenessat100HeatingAirFlow(double sensibleEffectivenessat100HeatingAirFlow); bool setLatentEffectivenessat100HeatingAirFlow(double latentEffectivenessat100HeatingAirFlow); - bool setSensibleEffectivenessat75HeatingAirFlow(double sensibleEffectivenessat75HeatingAirFlow); - - bool setLatentEffectivenessat75HeatingAirFlow(double latentEffectivenessat75HeatingAirFlow); - bool setSensibleEffectivenessat100CoolingAirFlow(double sensibleEffectivenessat100CoolingAirFlow); bool setLatentEffectivenessat100CoolingAirFlow(double latentEffectivenessat100CoolingAirFlow); - bool setSensibleEffectivenessat75CoolingAirFlow(double sensibleEffectivenessat75CoolingAirFlow); - - bool setLatentEffectivenessat75CoolingAirFlow(double latentEffectivenessat75CoolingAirFlow); - bool setNominalElectricPower(double nominalElectricPower); bool setSupplyAirOutletTemperatureControl(bool supplyAirOutletTemperatureControl); @@ -151,19 +141,28 @@ namespace model { bool setFrostControlType(const std::string& frostControlType); bool setThresholdTemperature(double thresholdTemperature); - void resetThresholdTemperature(); bool setInitialDefrostTimeFraction(boost::optional initialDefrostTimeFraction); - void resetInitialDefrostTimeFraction(); bool setRateofDefrostTimeFractionIncrease(boost::optional rateofDefrostTimeFractionIncrease); - void resetRateofDefrostTimeFractionIncrease(); bool setEconomizerLockout(bool economizerLockout); + bool setSensibleEffectivenessofHeatingAirFlowCurve(const Curve& sensibleEffectivenessofHeatingAirFlowCurve); + void resetSensibleEffectivenessofHeatingAirFlowCurve(); + + bool setLatentEffectivenessofHeatingAirFlowCurve(const Curve& latentEffectivenessofHeatingAirFlowCurve); + void resetLatentEffectivenessofHeatingAirFlowCurve(); + + bool setSensibleEffectivenessofCoolingAirFlowCurve(const Curve& sensibleEffectivenessofCoolingAirFlowCurve); + void resetSensibleEffectivenessofCoolingAirFlowCurve(); + + bool setLatentEffectivenessofCoolingAirFlowCurve(const Curve& latentEffectivenessofCoolingAirFlowCurve); + void resetLatentEffectivenessofCoolingAirFlowCurve(); + //@} /** @name Other */ //@{ @@ -171,6 +170,8 @@ namespace model { AirflowNetworkEquivalentDuct getAirflowNetworkEquivalentDuct(double length, double diameter); boost::optional airflowNetworkEquivalentDuct() const; + boost::optional autosizedNominalSupplyAirFlowRate() const; + //@} protected: diff --git a/src/model/test/HeatExchangerAirToAirSensibleAndLatent_GTest.cpp b/src/model/test/HeatExchangerAirToAirSensibleAndLatent_GTest.cpp index b26c6b1903..be3ccabcfe 100644 --- a/src/model/test/HeatExchangerAirToAirSensibleAndLatent_GTest.cpp +++ b/src/model/test/HeatExchangerAirToAirSensibleAndLatent_GTest.cpp @@ -19,6 +19,10 @@ #include "../EvaporativeCoolerDirectResearchSpecial_Impl.hpp" #include "../HVACTemplates.hpp" #include "../ScheduleCompact.hpp" +#include "../Curve.hpp" +#include "../TableLookup.hpp" +#include "../TableLookup_Impl.hpp" +#include "../TableIndependentVariable.hpp" using namespace openstudio; using namespace openstudio::model; @@ -60,38 +64,18 @@ TEST_F(ModelFixture, HeatExchangerAirToAirSensibleAndLatent_GettersSetters) { // Latent Effectiveness at 100% Heating Air Flow: Double // No Default - EXPECT_TRUE(hx.setLatentEffectivenessat100HeatingAirFlow(0.5)); - EXPECT_EQ(0.5, hx.latentEffectivenessat100HeatingAirFlow()); - - // Sensible Effectiveness at 75% Heating Air Flow: Double - // No Default - EXPECT_TRUE(hx.setSensibleEffectivenessat75HeatingAirFlow(0.5)); - EXPECT_EQ(0.5, hx.sensibleEffectivenessat75HeatingAirFlow()); - - // Latent Effectiveness at 75% Heating Air Flow: Double - // No Default - EXPECT_TRUE(hx.setLatentEffectivenessat75HeatingAirFlow(0.5)); - EXPECT_EQ(0.5, hx.latentEffectivenessat75HeatingAirFlow()); + EXPECT_TRUE(hx.setLatentEffectivenessat100HeatingAirFlow(0.55)); + EXPECT_EQ(0.55, hx.latentEffectivenessat100HeatingAirFlow()); // Sensible Effectiveness at 100% Cooling Air Flow: Double // No Default - EXPECT_TRUE(hx.setSensibleEffectivenessat100CoolingAirFlow(0.5)); - EXPECT_EQ(0.5, hx.sensibleEffectivenessat100CoolingAirFlow()); + EXPECT_TRUE(hx.setSensibleEffectivenessat100CoolingAirFlow(0.7)); + EXPECT_EQ(0.7, hx.sensibleEffectivenessat100CoolingAirFlow()); // Latent Effectiveness at 100% Cooling Air Flow: Double // No Default - EXPECT_TRUE(hx.setLatentEffectivenessat100CoolingAirFlow(0.5)); - EXPECT_EQ(0.5, hx.latentEffectivenessat100CoolingAirFlow()); - - // Sensible Effectiveness at 75% Cooling Air Flow: Double - // No Default - EXPECT_TRUE(hx.setSensibleEffectivenessat75CoolingAirFlow(0.5)); - EXPECT_EQ(0.5, hx.sensibleEffectivenessat75CoolingAirFlow()); - - // Latent Effectiveness at 75% Cooling Air Flow: Double - // No Default - EXPECT_TRUE(hx.setLatentEffectivenessat75CoolingAirFlow(0.5)); - EXPECT_EQ(0.5, hx.latentEffectivenessat75CoolingAirFlow()); + EXPECT_TRUE(hx.setLatentEffectivenessat100CoolingAirFlow(0.75)); + EXPECT_EQ(0.75, hx.latentEffectivenessat100CoolingAirFlow()); // Supply Air Inlet Node: Optional Object @@ -260,3 +244,246 @@ TEST_F(ModelFixture, HeatExchangerAirToAirSensibleAndLatent_remove) { EXPECT_TRUE(!loop.remove().empty()); } + +TEST_F(ModelFixture, HeatExchangerAirToAirSensibleAndLatent_EffectivenessCurves) { + Model m; + HeatExchangerAirToAirSensibleAndLatent hx(m); + + { + hx.resetSensibleEffectivenessofHeatingAirFlowCurve(); + EXPECT_FALSE(hx.sensibleEffectivenessofHeatingAirFlowCurve()); + + TableLookup sensibleHeatingEff(m); + EXPECT_TRUE(hx.setSensibleEffectivenessofHeatingAirFlowCurve(sensibleHeatingEff)); + ASSERT_TRUE(hx.sensibleEffectivenessofHeatingAirFlowCurve()); + EXPECT_EQ(sensibleHeatingEff, hx.sensibleEffectivenessofHeatingAirFlowCurve().get()); + + hx.resetSensibleEffectivenessofHeatingAirFlowCurve(); + EXPECT_FALSE(hx.sensibleEffectivenessofHeatingAirFlowCurve()); + } + + { + hx.resetLatentEffectivenessofHeatingAirFlowCurve(); + EXPECT_FALSE(hx.latentEffectivenessofHeatingAirFlowCurve()); + + TableLookup latentHeatingEff(m); + EXPECT_TRUE(hx.setLatentEffectivenessofHeatingAirFlowCurve(latentHeatingEff)); + ASSERT_TRUE(hx.latentEffectivenessofHeatingAirFlowCurve()); + EXPECT_EQ(latentHeatingEff, hx.latentEffectivenessofHeatingAirFlowCurve().get()); + + hx.resetLatentEffectivenessofHeatingAirFlowCurve(); + EXPECT_FALSE(hx.latentEffectivenessofHeatingAirFlowCurve()); + } + + { + hx.resetSensibleEffectivenessofCoolingAirFlowCurve(); + EXPECT_FALSE(hx.sensibleEffectivenessofCoolingAirFlowCurve()); + + TableLookup sensibleCoolingEff(m); + EXPECT_TRUE(hx.setSensibleEffectivenessofCoolingAirFlowCurve(sensibleCoolingEff)); + ASSERT_TRUE(hx.sensibleEffectivenessofCoolingAirFlowCurve()); + EXPECT_EQ(sensibleCoolingEff, hx.sensibleEffectivenessofCoolingAirFlowCurve().get()); + + hx.resetSensibleEffectivenessofCoolingAirFlowCurve(); + EXPECT_FALSE(hx.sensibleEffectivenessofCoolingAirFlowCurve()); + } + + { + hx.resetLatentEffectivenessofCoolingAirFlowCurve(); + EXPECT_FALSE(hx.latentEffectivenessofCoolingAirFlowCurve()); + + TableLookup latentCoolingEff(m); + EXPECT_TRUE(hx.setLatentEffectivenessofCoolingAirFlowCurve(latentCoolingEff)); + ASSERT_TRUE(hx.latentEffectivenessofCoolingAirFlowCurve()); + EXPECT_EQ(latentCoolingEff, hx.latentEffectivenessofCoolingAirFlowCurve().get()); + + hx.resetLatentEffectivenessofCoolingAirFlowCurve(); + EXPECT_FALSE(hx.latentEffectivenessofCoolingAirFlowCurve()); + } +} + +TEST_F(ModelFixture, HeatExchangerAirToAirSensibleAndLatent_Deprecated75Effectiveness) { + Model m; + HeatExchangerAirToAirSensibleAndLatent hx(m); + + // Ensure no curves assigned for now + hx.resetSensibleEffectivenessofHeatingAirFlowCurve(); + hx.resetLatentEffectivenessofHeatingAirFlowCurve(); + hx.resetSensibleEffectivenessofCoolingAirFlowCurve(); + hx.resetLatentEffectivenessofCoolingAirFlowCurve(); + + constexpr double sensibleHeatingEff100 = 0.76; + constexpr double latentHeatingEff100 = 0.68; + constexpr double sensibleCoolingEff100 = 0.72; + constexpr double latentCoolingEff100 = 0.63; + constexpr double sensibleHeatingEff75 = sensibleHeatingEff100 * 1.05; + constexpr double latentHeatingEff75 = latentHeatingEff100 * 1.05; + constexpr double sensibleCoolingEff75 = sensibleCoolingEff100 * 1.05; + constexpr double latentCoolingEff75 = latentCoolingEff100 * 1.05; + + EXPECT_TRUE(hx.setSensibleEffectivenessat100HeatingAirFlow(sensibleHeatingEff100)); + EXPECT_TRUE(hx.setLatentEffectivenessat100HeatingAirFlow(latentHeatingEff100)); + EXPECT_TRUE(hx.setSensibleEffectivenessat100CoolingAirFlow(sensibleCoolingEff100)); + EXPECT_TRUE(hx.setLatentEffectivenessat100CoolingAirFlow(latentCoolingEff100)); + + // When no curves assigned, the effectiveness is constant + EXPECT_EQ(sensibleHeatingEff100, hx.sensibleEffectivenessat75HeatingAirFlow()); + EXPECT_EQ(latentHeatingEff100, hx.latentEffectivenessat75HeatingAirFlow()); + EXPECT_EQ(sensibleCoolingEff100, hx.sensibleEffectivenessat75CoolingAirFlow()); + EXPECT_EQ(latentCoolingEff100, hx.latentEffectivenessat75CoolingAirFlow()); + + const std::vector expectedIndVals{0.75, 1.0}; + + // Sensible Effectiveness at 75% Heating Air Flow: Double + { + EXPECT_FALSE(hx.sensibleEffectivenessofHeatingAirFlowCurve()); + EXPECT_TRUE(hx.setSensibleEffectivenessat75HeatingAirFlow(sensibleHeatingEff75)); + ASSERT_TRUE(hx.sensibleEffectivenessofHeatingAirFlowCurve()); + ASSERT_TRUE(hx.sensibleEffectivenessofHeatingAirFlowCurve()->optionalCast()); + auto tableLookup = hx.sensibleEffectivenessofHeatingAirFlowCurve()->cast(); + EXPECT_EQ(1, tableLookup.numVariables()); + ASSERT_EQ(expectedIndVals, tableLookup.independentVariables().front().values()); + EXPECT_DOUBLE_EQ(sensibleHeatingEff75, hx.sensibleEffectivenessat75HeatingAirFlow()); + + // Works to modify when an existing table lookup is in the expected format + auto val2 = sensibleHeatingEff75 + 0.025; + EXPECT_TRUE(hx.setSensibleEffectivenessat75HeatingAirFlow(val2)); + EXPECT_DOUBLE_EQ(val2, hx.sensibleEffectivenessat75HeatingAirFlow()); + } + + // Latent Effectiveness at 75% Heating Air Flow: Double + { + EXPECT_FALSE(hx.latentEffectivenessofHeatingAirFlowCurve()); + EXPECT_TRUE(hx.setLatentEffectivenessat75HeatingAirFlow(latentHeatingEff75)); + ASSERT_TRUE(hx.latentEffectivenessofHeatingAirFlowCurve()); + ASSERT_TRUE(hx.latentEffectivenessofHeatingAirFlowCurve()->optionalCast()); + auto tableLookup = hx.latentEffectivenessofHeatingAirFlowCurve()->cast(); + EXPECT_EQ(1, tableLookup.numVariables()); + ASSERT_EQ(expectedIndVals, tableLookup.independentVariables().front().values()); + EXPECT_DOUBLE_EQ(latentHeatingEff75, hx.latentEffectivenessat75HeatingAirFlow()); + + // Works to modify when an existing table lookup is in the expected format + auto val2 = latentHeatingEff75 + 0.025; + EXPECT_TRUE(hx.setLatentEffectivenessat75HeatingAirFlow(val2)); + EXPECT_DOUBLE_EQ(val2, hx.latentEffectivenessat75HeatingAirFlow()); + } + + // Sensible Effectiveness at 75% Cooling Air Flow: Double + { + EXPECT_FALSE(hx.sensibleEffectivenessofCoolingAirFlowCurve()); + EXPECT_TRUE(hx.setSensibleEffectivenessat75CoolingAirFlow(sensibleCoolingEff75)); + ASSERT_TRUE(hx.sensibleEffectivenessofCoolingAirFlowCurve()); + ASSERT_TRUE(hx.sensibleEffectivenessofCoolingAirFlowCurve()->optionalCast()); + auto tableLookup = hx.sensibleEffectivenessofCoolingAirFlowCurve()->cast(); + EXPECT_EQ(1, tableLookup.numVariables()); + ASSERT_EQ(expectedIndVals, tableLookup.independentVariables().front().values()); + EXPECT_DOUBLE_EQ(sensibleCoolingEff75, hx.sensibleEffectivenessat75CoolingAirFlow()); + + // Works to modify when an existing table lookup is in the expected format + auto val2 = sensibleCoolingEff75 + 0.025; + EXPECT_TRUE(hx.setSensibleEffectivenessat75CoolingAirFlow(val2)); + EXPECT_DOUBLE_EQ(val2, hx.sensibleEffectivenessat75CoolingAirFlow()); + } + + // Latent Effectiveness at 75% Cooling Air Flow: Double + { + EXPECT_FALSE(hx.latentEffectivenessofCoolingAirFlowCurve()); + EXPECT_TRUE(hx.setLatentEffectivenessat75CoolingAirFlow(latentCoolingEff75)); + ASSERT_TRUE(hx.latentEffectivenessofCoolingAirFlowCurve()); + ASSERT_TRUE(hx.latentEffectivenessofCoolingAirFlowCurve()->optionalCast()); + auto tableLookup = hx.latentEffectivenessofCoolingAirFlowCurve()->cast(); + EXPECT_EQ(1, tableLookup.numVariables()); + ASSERT_EQ(expectedIndVals, tableLookup.independentVariables().front().values()); + EXPECT_DOUBLE_EQ(latentCoolingEff75, hx.latentEffectivenessat75CoolingAirFlow()); + + // Works to modify when an existing table lookup is in the expected format + auto val2 = latentCoolingEff75 + 0.025; + EXPECT_TRUE(hx.setLatentEffectivenessat75CoolingAirFlow(val2)); + EXPECT_DOUBLE_EQ(val2, hx.latentEffectivenessat75CoolingAirFlow()); + } +} + +TEST_F(ModelFixture, HeatExchangerAirToAirSensibleAndLatent_assignHistoricalEffectivenessCurves) { + + Model m; + HeatExchangerAirToAirSensibleAndLatent hx(m); + + // Ensure no curves assigned for now + hx.resetSensibleEffectivenessofHeatingAirFlowCurve(); + hx.resetLatentEffectivenessofHeatingAirFlowCurve(); + hx.resetSensibleEffectivenessofCoolingAirFlowCurve(); + hx.resetLatentEffectivenessofCoolingAirFlowCurve(); + + EXPECT_TRUE(hx.assignHistoricalEffectivenessCurves()); + + constexpr double sensibleHeatingEff75 = 0.81; + constexpr double latentHeatingEff75 = 0.73; + constexpr double sensibleCoolingEff75 = 0.81; + constexpr double latentCoolingEff75 = 0.73; + + const std::vector expectedIndVals{0.75, 1.0}; + + // Sensible Effectiveness at 75% Heating Air Flow: Double + { + ASSERT_TRUE(hx.sensibleEffectivenessofHeatingAirFlowCurve()); + ASSERT_TRUE(hx.sensibleEffectivenessofHeatingAirFlowCurve()->optionalCast()); + auto tableLookup = hx.sensibleEffectivenessofHeatingAirFlowCurve()->cast(); + EXPECT_EQ(1, tableLookup.numVariables()); + ASSERT_EQ(expectedIndVals, tableLookup.independentVariables().front().values()); + auto val100 = hx.sensibleEffectivenessat100HeatingAirFlow(); + EXPECT_EQ("DivisorOnly", tableLookup.normalizationMethod()); + EXPECT_DOUBLE_EQ(val100, tableLookup.normalizationDivisor()); + const std::vector expectedOutVals = {sensibleHeatingEff75, val100}; + ASSERT_EQ(expectedOutVals, tableLookup.outputValues()); + + EXPECT_DOUBLE_EQ(sensibleHeatingEff75, hx.sensibleEffectivenessat75HeatingAirFlow()); // DEPRECATED + } + + // Latent Effectiveness at 75% Heating Air Flow: Double + { + ASSERT_TRUE(hx.latentEffectivenessofHeatingAirFlowCurve()); + ASSERT_TRUE(hx.latentEffectivenessofHeatingAirFlowCurve()->optionalCast()); + auto tableLookup = hx.latentEffectivenessofHeatingAirFlowCurve()->cast(); + EXPECT_EQ(1, tableLookup.numVariables()); + ASSERT_EQ(expectedIndVals, tableLookup.independentVariables().front().values()); + auto val100 = hx.latentEffectivenessat100HeatingAirFlow(); + EXPECT_EQ("DivisorOnly", tableLookup.normalizationMethod()); + EXPECT_DOUBLE_EQ(val100, tableLookup.normalizationDivisor()); + const std::vector expectedOutVals = {latentHeatingEff75, val100}; + ASSERT_EQ(expectedOutVals, tableLookup.outputValues()); + + EXPECT_DOUBLE_EQ(latentHeatingEff75, hx.latentEffectivenessat75HeatingAirFlow()); // DEPRECATED + } + + // Sensible Effectiveness at 75% Cooling Air Flow: Double + { + ASSERT_TRUE(hx.sensibleEffectivenessofCoolingAirFlowCurve()); + ASSERT_TRUE(hx.sensibleEffectivenessofCoolingAirFlowCurve()->optionalCast()); + auto tableLookup = hx.sensibleEffectivenessofCoolingAirFlowCurve()->cast(); + EXPECT_EQ(1, tableLookup.numVariables()); + ASSERT_EQ(expectedIndVals, tableLookup.independentVariables().front().values()); + auto val100 = hx.sensibleEffectivenessat100CoolingAirFlow(); + EXPECT_EQ("DivisorOnly", tableLookup.normalizationMethod()); + EXPECT_DOUBLE_EQ(val100, tableLookup.normalizationDivisor()); + const std::vector expectedOutVals = {sensibleCoolingEff75, val100}; + ASSERT_EQ(expectedOutVals, tableLookup.outputValues()); + + EXPECT_DOUBLE_EQ(sensibleCoolingEff75, hx.sensibleEffectivenessat75CoolingAirFlow()); // DEPRECATED + } + + // Latent Effectiveness at 75% Cooling Air Flow: Double + { + ASSERT_TRUE(hx.latentEffectivenessofCoolingAirFlowCurve()); + ASSERT_TRUE(hx.latentEffectivenessofCoolingAirFlowCurve()->optionalCast()); + auto tableLookup = hx.latentEffectivenessofCoolingAirFlowCurve()->cast(); + EXPECT_EQ(1, tableLookup.numVariables()); + ASSERT_EQ(expectedIndVals, tableLookup.independentVariables().front().values()); + auto val100 = hx.latentEffectivenessat100CoolingAirFlow(); + EXPECT_EQ("DivisorOnly", tableLookup.normalizationMethod()); + EXPECT_DOUBLE_EQ(val100, tableLookup.normalizationDivisor()); + const std::vector expectedOutVals = {latentCoolingEff75, val100}; + ASSERT_EQ(expectedOutVals, tableLookup.outputValues()); + + EXPECT_DOUBLE_EQ(latentCoolingEff75, hx.latentEffectivenessat75CoolingAirFlow()); // DEPRECATED + } +} diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index 31a3334ada..1b8531422f 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -143,7 +143,8 @@ namespace osversion { m_updateMethods[VersionString("3.5.1")] = &VersionTranslator::update_3_5_0_to_3_5_1; m_updateMethods[VersionString("3.6.0")] = &VersionTranslator::update_3_5_1_to_3_6_0; m_updateMethods[VersionString("3.7.0")] = &VersionTranslator::update_3_6_1_to_3_7_0; - m_updateMethods[VersionString("3.8.0")] = &VersionTranslator::defaultUpdate; + m_updateMethods[VersionString("3.8.0")] = &VersionTranslator::update_3_7_0_to_3_8_0; + // m_updateMethods[VersionString("3.8.0")] = &VersionTranslator::defaultUpdate; // List of previous versions that may be updated to this one. // - To increment the translator, add an entry for the version just released (branched for @@ -8951,5 +8952,127 @@ namespace osversion { } // end update_3_6_1_to_3_7_0 + std::string VersionTranslator::update_3_7_0_to_3_8_0(const IdfFile& idf_3_7_0, const IddFileAndFactoryWrapper& idd_3_8_0) { + std::stringstream ss; + boost::optional value; + + ss << idf_3_7_0.header() << '\n' << '\n'; + IdfFile targetIdf(idd_3_8_0.iddFile()); + ss << targetIdf.versionObject().get(); + + constexpr std::array hx_old_100effectiveness_idxs{4, 5, 8, 9}; + constexpr std::array hx_new_effectiveness_curves_idxs{20, 21, 22, 23}; + constexpr std::array hx_new_table_names{"SensHeat", "LatHeat", "SensCool", "LatCool"}; + + for (const IdfObject& object : idf_3_7_0.objects()) { + auto iddname = object.iddObject().name(); + + if (iddname == "OS:HeatExchanger:AirToAir:SensibleAndLatent") { + + // 4 Fields have been added from 3.7.0 to 3.8.0: + // ---------------------------------------------- + // * Sensible Effectiveness at 75% Heating Air Flow {dimensionless} * 6 + // * Latent Effectiveness at 75% Heating Air Flow {dimensionless} * 7 + // * Sensible Effectiveness at 75% Cooling Air Flow {dimensionless} * 10 + // * Latent Effectiveness at 75% Cooling Air Flow {dimensionless} * 11 + + // 4 Fields have been added from 3.7.0 to 3.8.0: + // ---------------------------------------------- + // * Sensible Effectiveness of Heating Air Flow Curve Name * 20 + // * Latent Effectiveness of Heating Air Flow Curve Name * 21 + // * Sensible Effectiveness of Cooling Air Flow Curve Name * 22 + // * Latent Effectiveness of Cooling Air Flow Curve Name * 23 + + auto iddObject = idd_3_8_0.getObject(iddname); + IdfObject newObject(iddObject.get()); + + for (size_t i = 0; i < object.numFields(); ++i) { + if ((value = object.getString(i))) { + if (i < 6) { + newObject.setString(i, value.get()); + } else if (i < 8) { + // no op + } else if (i < 10) { + newObject.setString(i - 2, value.get()); + } else if (i < 12) { + // no op + } else { + newObject.setString(i - 4, value.get()); + } + } + } + + const std::string varListHandle = toString(createUUID()); + bool tableAdded = false; + for (size_t i = 0; i < hx_old_100effectiveness_idxs.size(); ++i) { + // Sensible/Latent Effectiveness at 100% Heating/Cooling Air Flow {dimensionless} + if (auto e100 = object.getDouble(hx_old_100effectiveness_idxs[i])) { + // Sensible/Latent Effectiveness at 75% Heating/Cooling Air Flow {dimensionless} + + if (auto e75 = object.getDouble(hx_old_100effectiveness_idxs[i] + 2)) { + if (e100.get() != e75.get()) { + tableAdded = true; + + IdfObject tableLookup(idd_3_8_0.getObject("OS:Table:Lookup").get()); + std::string uuid = toString(createUUID()); + tableLookup.setString(0, uuid); // Handle + tableLookup.setString(1, fmt::format("{}_{}Eff", object.nameString(), hx_new_table_names[i])); // Name + tableLookup.setString(2, varListHandle); // Independent Variable List Name + tableLookup.setString(3, "DivisorOnly"); // Normalization Method + tableLookup.setDouble(4, e100.get()); // Normalization Divisor + tableLookup.setDouble(5, 0.0); // Minimum Output + tableLookup.setDouble(6, 10.0); // Maximum Output + tableLookup.setString(7, "Dimensionless"); // Output Unit Type + tableLookup.pushExtensibleGroup().setDouble(0, e75.get()); // Output Value 1 + tableLookup.pushExtensibleGroup().setDouble(0, e100.get()); // Output Value 2 + + // Sensible/Latent Effectiveness of Heating/Cooling Air Flow Curve Name + newObject.setString(hx_new_effectiveness_curves_idxs[i], uuid); + + ss << tableLookup; + m_new.push_back(tableLookup); + } + } + } + } + + ss << newObject; + m_refactored.emplace_back(object, std::move(newObject)); + + if (tableAdded) { + IdfObject varList(idd_3_8_0.getObject("OS:ModelObjectList").get()); + varList.setString(0, varListHandle); + varList.setString(1, object.nameString() + "_IndependentVariableList"); // Name + + IdfObject var(idd_3_8_0.getObject("OS:Table:IndependentVariable").get()); + std::string varHandle = toString(createUUID()); + var.setString(0, varHandle); + varList.pushExtensibleGroup({varHandle}); // Model Object 1 + var.setString(1, object.nameString() + "_IndependentVariable"); // Name + var.setString(2, "Linear"); // Interpolation Method + var.setString(3, "Linear"); // Extrapolation Method + var.setDouble(4, 0.0); // Minimum Value + var.setDouble(5, 10.0); // Maximum Value + var.setString(7, "Dimensionless"); // Unit Type + var.pushExtensibleGroup().setDouble(0, 0.75); // Value 1 + var.pushExtensibleGroup().setDouble(0, 1.0); // Value 2 + + ss << varList; + m_new.emplace_back(std::move(varList)); + + ss << var; + m_new.emplace_back(std::move(var)); + } + + // No-op + } else { + ss << object; + } + } + + return ss.str(); + + } // end update_3_7_0_to_3_8_0 + } // namespace osversion } // namespace openstudio diff --git a/src/osversion/VersionTranslator.hpp b/src/osversion/VersionTranslator.hpp index ca4a4d3b8a..b5a93555c6 100644 --- a/src/osversion/VersionTranslator.hpp +++ b/src/osversion/VersionTranslator.hpp @@ -235,6 +235,7 @@ namespace osversion { std::string update_3_5_0_to_3_5_1(const IdfFile& idf_3_5_0, const IddFileAndFactoryWrapper& idd_3_5_1); std::string update_3_5_1_to_3_6_0(const IdfFile& idf_3_5_1, const IddFileAndFactoryWrapper& idd_3_6_0); std::string update_3_6_1_to_3_7_0(const IdfFile& idf_3_6_1, const IddFileAndFactoryWrapper& idd_3_7_0); + std::string update_3_7_0_to_3_8_0(const IdfFile& idf_3_7_0, const IddFileAndFactoryWrapper& idd_3_8_0); IdfObject updateUrlField_0_7_1_to_0_7_2(const IdfObject& object, unsigned index); diff --git a/src/osversion/test/3_8_0/test_vt_HeatExchangerAirToAirSensibleAndLatent.osm b/src/osversion/test/3_8_0/test_vt_HeatExchangerAirToAirSensibleAndLatent.osm new file mode 100644 index 0000000000..3e1852fdb0 --- /dev/null +++ b/src/osversion/test/3_8_0/test_vt_HeatExchangerAirToAirSensibleAndLatent.osm @@ -0,0 +1,159 @@ + +OS:Version, + {35621888-8471-4654-b196-7a10e6d60d77}, !- Handle + 3.7.0; !- Version Identifier + +OS:HeatExchanger:AirToAir:SensibleAndLatent, + {67e2de0d-3ea9-42c1-88b8-0a04128deac9}, !- Handle + ERV, !- Name + {2a77b641-92f2-4915-a135-3d358f2ed6d0}, !- Availability Schedule + autosize, !- Nominal Supply Air Flow Rate {m3/s} + 0.76, !- Sensible Effectiveness at 100% Heating Air Flow {dimensionless} + 0.68, !- Latent Effectiveness at 100% Heating Air Flow {dimensionless} + 0.81, !- Sensible Effectiveness at 75% Heating Air Flow {dimensionless} + 0.73, !- Latent Effectiveness at 75% Heating Air Flow {dimensionless} + 0.74, !- Sensible Effectiveness at 100% Cooling Air Flow {dimensionless} + 0.67, !- Latent Effectiveness at 100% Cooling Air Flow {dimensionless} + 0.8, !- Sensible Effectiveness at 75% Cooling Air Flow {dimensionless} + 0.72, !- Latent Effectiveness at 75% Cooling Air Flow {dimensionless} + {0a300f71-b1bc-4ad0-b33d-78538aba9f4d}, !- Supply Air Inlet Node + {d8090337-7cf3-4469-91e6-4cf247eb4a14}, !- Supply Air Outlet Node + {96f29526-15b8-419d-9d22-18e2f34655b7}, !- Exhaust Air Inlet Node + {34c68d89-61b1-4354-9845-2bcbfa55bdde}, !- Exhaust Air Outlet Node + 0, !- Nominal Electric Power {W} + Yes, !- Supply Air Outlet Temperature Control + Plate, !- Heat Exchanger Type + None, !- Frost Control Type + 1.7, !- Threshold Temperature {C} + , !- Initial Defrost Time Fraction {dimensionless} + , !- Rate of Defrost Time Fraction Increase {1/K} + No; !- Economizer Lockout + +OS:Schedule:Constant, + {2a77b641-92f2-4915-a135-3d358f2ed6d0}, !- Handle + Always On Discrete, !- Name + {424ab631-0001-433e-a6c6-3c9bf194df94}, !- Schedule Type Limits Name + 1; !- Value + +OS:ScheduleTypeLimits, + {424ab631-0001-433e-a6c6-3c9bf194df94}, !- Handle + OnOff, !- Name + 0, !- Lower Limit Value + 1, !- Upper Limit Value + Discrete, !- Numeric Type + Availability; !- Unit Type + +OS:Controller:OutdoorAir, + {2f48a111-690e-4cac-a0c4-4a7daaf03f94}, !- Handle + Controller Outdoor Air 1, !- Name + , !- Relief Air Outlet Node Name + , !- Return Air Node Name + , !- Mixed Air Node Name + , !- Actuator Node Name + 0, !- Minimum Outdoor Air Flow Rate {m3/s} + Autosize, !- Maximum Outdoor Air Flow Rate {m3/s} + NoEconomizer, !- Economizer Control Type + ModulateFlow, !- Economizer Control Action Type + 28, !- Economizer Maximum Limit Dry-Bulb Temperature {C} + 64000, !- Economizer Maximum Limit Enthalpy {J/kg} + , !- Economizer Maximum Limit Dewpoint Temperature {C} + , !- Electronic Enthalpy Limit Curve Name + -100, !- Economizer Minimum Limit Dry-Bulb Temperature {C} + NoLockout, !- Lockout Type + FixedMinimum, !- Minimum Limit Type + , !- Minimum Outdoor Air Schedule Name + , !- Minimum Fraction of Outdoor Air Schedule Name + , !- Maximum Fraction of Outdoor Air Schedule Name + {5b6f1b3f-2d43-4874-8e80-1f863931595b}, !- Controller Mechanical Ventilation + , !- Time of Day Economizer Control Schedule Name + No, !- High Humidity Control + , !- Humidistat Control Zone Name + , !- High Humidity Outdoor Air Flow Ratio + , !- Control High Indoor Humidity Based on Outdoor Humidity Ratio + BypassWhenWithinEconomizerLimits, !- Heat Recovery Bypass Control Type + InterlockedWithMechanicalCooling; !- Economizer Operation Staging + +OS:Controller:MechanicalVentilation, + {5b6f1b3f-2d43-4874-8e80-1f863931595b}, !- Handle + Controller Mechanical Ventilation 1, !- Name + {2a77b641-92f2-4915-a135-3d358f2ed6d0}, !- Availability Schedule + , !- Demand Controlled Ventilation + ; !- System Outdoor Air Method + +OS:AirLoopHVAC:OutdoorAirSystem, + {a5b85d9c-2fc9-4b26-aa5c-da16db98efaa}, !- Handle + Air Loop HVAC Outdoor Air System 1, !- Name + {2f48a111-690e-4cac-a0c4-4a7daaf03f94}, !- Controller Name + , !- Outdoor Air Equipment List Name + , !- Availability Manager List Name + , !- Mixed Air Node Name + {d5901fbe-722e-4175-810f-d57fef602118}, !- Outdoor Air Stream Node Name + {c8a3f5a9-2e0b-43b2-abb7-d71fb91d455f}, !- Relief Air Stream Node Name + ; !- Return Air Stream Node Name + +OS:Node, + {97f5f18a-aef2-498e-9178-a51afbe800f2}, !- Handle + Outboard OA Node, !- Name + , !- Inlet Port + {0a300f71-b1bc-4ad0-b33d-78538aba9f4d}; !- Outlet Port + +OS:Node, + {eaed6165-9257-4d9a-ae4f-acf7c2f2397f}, !- Handle + Relief Node, !- Name + {34c68d89-61b1-4354-9845-2bcbfa55bdde}, !- Inlet Port + ; !- Outlet Port + +OS:Node, + {90d802c8-2719-485c-a00b-a18a2e352174}, !- Handle + Node 2, !- Name + {d8090337-7cf3-4469-91e6-4cf247eb4a14}, !- Inlet Port + {d5901fbe-722e-4175-810f-d57fef602118}; !- Outlet Port + +OS:Connection, + {0a300f71-b1bc-4ad0-b33d-78538aba9f4d}, !- Handle + {97f5f18a-aef2-498e-9178-a51afbe800f2}, !- Source Object + 3, !- Outlet Port + {67e2de0d-3ea9-42c1-88b8-0a04128deac9}, !- Target Object + 12; !- Inlet Port + +OS:Connection, + {d8090337-7cf3-4469-91e6-4cf247eb4a14}, !- Handle + {67e2de0d-3ea9-42c1-88b8-0a04128deac9}, !- Source Object + 13, !- Outlet Port + {90d802c8-2719-485c-a00b-a18a2e352174}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {d5901fbe-722e-4175-810f-d57fef602118}, !- Handle + {90d802c8-2719-485c-a00b-a18a2e352174}, !- Source Object + 3, !- Outlet Port + {a5b85d9c-2fc9-4b26-aa5c-da16db98efaa}, !- Target Object + 6; !- Inlet Port + +OS:Node, + {381769e1-53aa-4267-abed-5d8adb16f251}, !- Handle + Node 3, !- Name + {c8a3f5a9-2e0b-43b2-abb7-d71fb91d455f}, !- Inlet Port + {96f29526-15b8-419d-9d22-18e2f34655b7}; !- Outlet Port + +OS:Connection, + {c8a3f5a9-2e0b-43b2-abb7-d71fb91d455f}, !- Handle + {a5b85d9c-2fc9-4b26-aa5c-da16db98efaa}, !- Source Object + 7, !- Outlet Port + {381769e1-53aa-4267-abed-5d8adb16f251}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {96f29526-15b8-419d-9d22-18e2f34655b7}, !- Handle + {381769e1-53aa-4267-abed-5d8adb16f251}, !- Source Object + 3, !- Outlet Port + {67e2de0d-3ea9-42c1-88b8-0a04128deac9}, !- Target Object + 14; !- Inlet Port + +OS:Connection, + {34c68d89-61b1-4354-9845-2bcbfa55bdde}, !- Handle + {67e2de0d-3ea9-42c1-88b8-0a04128deac9}, !- Source Object + 15, !- Outlet Port + {eaed6165-9257-4d9a-ae4f-acf7c2f2397f}, !- Target Object + 2; !- Inlet Port + diff --git a/src/osversion/test/3_8_0/test_vt_HeatExchangerAirToAirSensibleAndLatent.rb b/src/osversion/test/3_8_0/test_vt_HeatExchangerAirToAirSensibleAndLatent.rb new file mode 100644 index 0000000000..b0addc1d25 --- /dev/null +++ b/src/osversion/test/3_8_0/test_vt_HeatExchangerAirToAirSensibleAndLatent.rb @@ -0,0 +1,32 @@ +#require '/usr/local/openstudio-3.7.0/Ruby/openstudio' + +include OpenStudio::Model + +m = Model.new + +hx = HeatExchangerAirToAirSensibleAndLatent.new(m) +hx.setName("ERV") + +hx.autosizeNominalSupplyAirFlowRate + +hx.setSensibleEffectivenessat100HeatingAirFlow(0.76) +hx.setLatentEffectivenessat100HeatingAirFlow(0.68) + +hx.setSensibleEffectivenessat75HeatingAirFlow(0.81) +hx.setLatentEffectivenessat75HeatingAirFlow(0.73) + +hx.setSensibleEffectivenessat100CoolingAirFlow(0.74) +hx.setLatentEffectivenessat100CoolingAirFlow(0.67) + +hx.setSensibleEffectivenessat75CoolingAirFlow(0.80) +hx.setLatentEffectivenessat75CoolingAirFlow(0.72) + +# Field right after is the supply air inlet node +controller = ControllerOutdoorAir.new(m) +oaSystem = AirLoopHVACOutdoorAirSystem.new(m, controller) +hx.addToNode(oaSystem.outboardOANode.get) + +# Last field +hx.setEconomizerLockout(false) + +m.save('test_vt_HeatExchangerAirToAirSensibleAndLatent.osm', true) diff --git a/src/osversion/test/VersionTranslator_GTest.cpp b/src/osversion/test/VersionTranslator_GTest.cpp index 906a56e500..a0db980153 100644 --- a/src/osversion/test/VersionTranslator_GTest.cpp +++ b/src/osversion/test/VersionTranslator_GTest.cpp @@ -4022,3 +4022,95 @@ TEST_F(OSVersionFixture, update_3_6_1_to_3_7_0_HeatPumpPlantLoopEIR) { EXPECT_TRUE(hp.isEmpty(insertionIndex++)); // TimedEmpiricalDefrostHeatInputEnergyFractionCurveName } } + +TEST_F(OSVersionFixture, update_3_7_0_to_3_8_0_HeatExchangerAirToAirSensibleAndLatent) { + openstudio::path path = resourcesPath() / toPath("osversion/3_8_0/test_vt_HeatExchangerAirToAirSensibleAndLatent.osm"); + osversion::VersionTranslator vt; + boost::optional model = vt.loadModel(path); + ASSERT_TRUE(model) << "Failed to load " << path; + + openstudio::path outPath = resourcesPath() / toPath("osversion/3_8_0/test_vt_HeatExchangerAirToAirSensibleAndLatent_updated.osm"); + model->save(outPath, true); + + std::vector hxs = model->getObjectsByType("OS:HeatExchanger:AirToAir:SensibleAndLatent"); + ASSERT_EQ(1u, hxs.size()); + WorkspaceObject hx = hxs[0]; + + EXPECT_EQ("ERV", hx.getString(1).get()); // Name + EXPECT_EQ("Always On Discrete", hx.getTarget(2)->nameString()); // Availability Schedule + EXPECT_EQ("autosize", hx.getString(3).get()); // Nominal Supply Air Flow Rate + EXPECT_EQ(0.76, hx.getDouble(4).get()); // Sensible Effectiveness at 100% Heating Air Flow + EXPECT_EQ(0.68, hx.getDouble(5).get()); // Latent Effectiveness at 100% Heating Air Flow + EXPECT_EQ(0.74, hx.getDouble(6).get()); // Sensible Effectiveness at 100% Cooling Air Flow + EXPECT_EQ(0.67, hx.getDouble(7).get()); // Latent Effectiveness at 100% Cooling Air Flow + // Supply Air Inlet Node + EXPECT_FALSE(hx.isEmpty(8)); + EXPECT_EQ("Outboard OA Node", hx.getTarget(8)->getTarget(OS_ConnectionFields::SourceObject)->nameString()); + EXPECT_FALSE(hx.isEmpty(9)); // Supply Air Outlet Node + EXPECT_FALSE(hx.isEmpty(10)); // Exhaust Air Inlet Node + EXPECT_FALSE(hx.isEmpty(11)); + // Exhaust Air Outlet Node + EXPECT_EQ("Relief Node", hx.getTarget(11)->getTarget(OS_ConnectionFields::TargetObject)->nameString()); + + // Former last field + EXPECT_EQ("No", hx.getString(19).get()); // Economizer Lockout + EXPECT_EQ("ERV_SensHeatEff", + hx.getTarget(20)->nameString()); // Sensible Effectiveness of Heating Air Flow Curve Name + EXPECT_EQ("ERV_LatHeatEff", + hx.getTarget(21)->nameString()); // Latent Effectiveness of Heating Air Flow Curve Name + EXPECT_EQ("ERV_SensCoolEff", + hx.getTarget(22)->nameString()); // Sensible Effectiveness of Cooling Air Flow Curve Name + EXPECT_EQ("ERV_LatCoolEff", + hx.getTarget(23)->nameString()); // Latent Effectiveness of Cooling Air Flow Curve Name + + std::vector tableLookups = model->getObjectsByType("OS:Table:Lookup"); + ASSERT_EQ(4u, tableLookups.size()); + auto tableLookup = hx.getTarget(20).get(); + + EXPECT_EQ("ERV_SensHeatEff", tableLookup.nameString()); // Name + EXPECT_EQ("ERV_IndependentVariableList", + tableLookup.getTarget(2)->nameString()); // Independent Variable List Name + EXPECT_EQ("DivisorOnly", tableLookup.getString(3).get()); // Normalization Method + EXPECT_EQ(0.76, tableLookup.getDouble(4).get()); // Normalization Divisor + EXPECT_EQ(0.0, tableLookup.getDouble(5).get()); // Minimum Output + EXPECT_EQ(10.0, tableLookup.getDouble(6).get()); // Maximum Output + EXPECT_EQ("Dimensionless", tableLookup.getString(7).get()); // Output Unit Type + EXPECT_TRUE(tableLookup.isEmpty(8)); // External File Name + EXPECT_TRUE(tableLookup.isEmpty(9)); // External File Column Number + EXPECT_TRUE(tableLookup.isEmpty(10)); // External File Starting Row Number + ASSERT_EQ(2, tableLookup.numExtensibleGroups()); + auto eg1 = tableLookup.extensibleGroups()[0]; + EXPECT_EQ(0.81, eg1.getDouble(0).get()); // Output Value 1 + auto eg2 = tableLookup.extensibleGroups()[1]; + EXPECT_EQ(0.76, eg2.getDouble(0).get()); // Output Value 2 + + std::vector varLists = model->getObjectsByType("OS:ModelObjectList"); + ASSERT_EQ(1u, varLists.size()); + WorkspaceObject varList = varLists[0]; + + EXPECT_EQ("ERV_IndependentVariableList", varList.nameString()); // Name + ASSERT_EQ(1, varList.numExtensibleGroups()); + auto var_ = varList.extensibleGroups().front().cast().getTarget(0); // Model Object 1 + ASSERT_TRUE(var_); + EXPECT_EQ("ERV_IndependentVariable", var_->nameString()); + + std::vector vars = model->getObjectsByType("OS:Table:IndependentVariable"); + ASSERT_EQ(1u, vars.size()); + WorkspaceObject var = vars[0]; + + EXPECT_EQ("ERV_IndependentVariable", var.nameString()); // Name + EXPECT_EQ("Linear", var.getString(2).get()); // Interpolation Method + EXPECT_EQ("Linear", var.getString(3).get()); // Extrapolation Method + EXPECT_EQ(0.0, var.getDouble(4).get()); // Minimum Value + EXPECT_EQ(10.0, var.getDouble(5).get()); // Maximum Value + EXPECT_TRUE(var.isEmpty(6)); // Normalization Reference Value + EXPECT_EQ("Dimensionless", var.getString(7).get()); // Unit Type + EXPECT_TRUE(var.isEmpty(8)); // External File Name + EXPECT_TRUE(var.isEmpty(9)); // External File Column Number + EXPECT_TRUE(var.isEmpty(10)); // External File Starting Row Number + ASSERT_EQ(2, var.numExtensibleGroups()); + auto eg4 = var.extensibleGroups()[0]; + EXPECT_EQ(0.75, eg4.getDouble(0).get()); // Value 1 + auto eg5 = var.extensibleGroups()[1]; + EXPECT_EQ(1.0, eg5.getDouble(0).get()); // Value 2 +} diff --git a/src/sdd/MapHVAC.cpp b/src/sdd/MapHVAC.cpp index 9af9fc3aec..97cb6470eb 100644 --- a/src/sdd/MapHVAC.cpp +++ b/src/sdd/MapHVAC.cpp @@ -57,6 +57,7 @@ #include "../model/Curve.hpp" #include "../model/Curve_Impl.hpp" #include "../model/TableLookup.hpp" +#include "../model/TableLookup_Impl.hpp" #include "../model/TableIndependentVariable.hpp" #include "../model/Duct.hpp" #include "../model/Duct_Impl.hpp" @@ -209,12 +210,12 @@ #include "../utilities/geometry/Geometry.hpp" #include "../utilities/geometry/Point3d.hpp" #include "../utilities/geometry/BoundingBox.hpp" -#include "model/TableIndependentVariable.hpp" #include #include #include +#include namespace openstudio { namespace sdd { @@ -2715,13 +2716,6 @@ namespace sdd { hx.setSensibleEffectivenessat100HeatingAirFlow(_htgSensEff100.get()); } - // HtgSensEff75 - auto htgSensEff75Element = element.child("HtgSensEff75"); - boost::optional _htgSensEff75 = lexicalCastToDouble(htgSensEff75Element); - if (_htgSensEff75) { - hx.setSensibleEffectivenessat75HeatingAirFlow(_htgSensEff75.get()); - } - // HtgLatEff100 auto htgLatEff100Element = element.child("HtgLatEff100"); boost::optional _htgLatEff100 = lexicalCastToDouble(htgLatEff100Element); @@ -2729,13 +2723,6 @@ namespace sdd { hx.setLatentEffectivenessat100HeatingAirFlow(_htgLatEff100.get()); } - // HtgLatEff75 - auto htgLatEff75Element = element.child("HtgLatEff75"); - boost::optional _htgLatEff75 = lexicalCastToDouble(htgLatEff75Element); - if (_htgLatEff75) { - hx.setLatentEffectivenessat75HeatingAirFlow(_htgLatEff75.get()); - } - // ClgSensEff100 auto clgSensEff100Element = element.child("ClgSensEff100"); boost::optional _clgSensEff100 = lexicalCastToDouble(clgSensEff100Element); @@ -2743,13 +2730,6 @@ namespace sdd { hx.setSensibleEffectivenessat100CoolingAirFlow(_clgSensEff100.get()); } - // ClgSensEff75 - auto clgSensEff75Element = element.child("ClgSensEff75"); - boost::optional _clgSensEff75 = lexicalCastToDouble(clgSensEff75Element); - if (_clgSensEff75) { - hx.setSensibleEffectivenessat75CoolingAirFlow(_clgSensEff75.get()); - } - // ClgLatEff100 auto clgLatEff100Element = element.child("ClgLatEff100"); boost::optional _clgLatEff100 = lexicalCastToDouble(clgLatEff100Element); @@ -2757,11 +2737,102 @@ namespace sdd { hx.setLatentEffectivenessat100CoolingAirFlow(_clgLatEff100.get()); } - // ClgLatEff75 + // DEPRECATED 75% fields + auto htgSensEff75Element = element.child("HtgSensEff75"); + boost::optional _htgSensEff75 = lexicalCastToDouble(htgSensEff75Element); + + auto htgLatEff75Element = element.child("HtgLatEff75"); + boost::optional _htgLatEff75 = lexicalCastToDouble(htgLatEff75Element); + + auto clgSensEff75Element = element.child("ClgSensEff75"); + boost::optional _clgSensEff75 = lexicalCastToDouble(clgSensEff75Element); + auto clgLatEff75Element = element.child("ClgLatEff75"); boost::optional _clgLatEff75 = lexicalCastToDouble(clgLatEff75Element); - if (_clgLatEff75) { - hx.setLatentEffectivenessat75CoolingAirFlow(_clgLatEff75.get()); + + if (_htgSensEff75 || _htgLatEff75 || _clgSensEff75 || _clgLatEff75) { + + model::TableIndependentVariable var(model); + var.setName(hx.nameString() + "_IndependentVariable"); + var.setInterpolationMethod("Linear"); + var.setExtrapolationMethod("Linear"); + var.setMinimumValue(0.0); + var.setMaximumValue(10.0); + var.setUnitType("Dimensionless"); + var.addValue(0.75); + var.addValue(1.0); + + if (_htgSensEff75) { + auto val100 = _htgSensEff100.get_value_or(1.0); + + model::TableLookup table(model); + table.setName(fmt::format("{}_SensHeatEff", hx.nameString())); + table.addIndependentVariable(var); + + table.setNormalizationMethod("DivisorOnly"); + table.setNormalizationDivisor(val100); + table.setMinimumOutput(0.0); + table.setMaximumOutput(10.0); + table.setOutputUnitType("Dimensionless"); + table.addOutputValue(*_htgSensEff75); + table.addOutputValue(val100); + + hx.setSensibleEffectivenessofHeatingAirFlowCurve(table); + } + + if (_htgLatEff75) { + auto val100 = _htgLatEff100.get_value_or(1.0); + + model::TableLookup table(model); + table.setName(fmt::format("{}_LatHeatEff", hx.nameString())); + table.addIndependentVariable(var); + + table.setNormalizationMethod("DivisorOnly"); + table.setNormalizationDivisor(val100); + table.setMinimumOutput(0.0); + table.setMaximumOutput(10.0); + table.setOutputUnitType("Dimensionless"); + table.addOutputValue(*_htgLatEff75); + table.addOutputValue(val100); + + hx.setLatentEffectivenessofHeatingAirFlowCurve(table); + } + + if (_clgSensEff75) { + auto val100 = _clgSensEff100.get_value_or(1.0); + + model::TableLookup table(model); + table.setName(fmt::format("{}_SensCoolEff", hx.nameString())); + table.addIndependentVariable(var); + + table.setNormalizationMethod("DivisorOnly"); + table.setNormalizationDivisor(val100); + table.setMinimumOutput(0.0); + table.setMaximumOutput(10.0); + table.setOutputUnitType("Dimensionless"); + table.addOutputValue(*_clgSensEff75); + table.addOutputValue(val100); + + hx.setSensibleEffectivenessofCoolingAirFlowCurve(table); + } + + if (_clgLatEff75) { + auto val100 = _clgLatEff100.get_value_or(1.0); + + model::TableLookup table(model); + table.setName(fmt::format("{}_LatCoolEff", hx.nameString())); + table.addIndependentVariable(var); + + table.setNormalizationMethod("DivisorOnly"); + table.setNormalizationDivisor(val100); + table.setMinimumOutput(0.0); + table.setMaximumOutput(10.0); + table.setOutputUnitType("Dimensionless"); + table.addOutputValue(*_clgLatEff75); + table.addOutputValue(val100); + + hx.setLatentEffectivenessofCoolingAirFlowCurve(table); + } } // AuxPwr