From 2ca312b9b117e7941fbcb654fd73fc03169444c6 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 14:50:10 +0200 Subject: [PATCH 01/15] Use Wshadow-field on clang (GCC only has Wshadow which is way too noisy) --- cmake/CompilerFlags.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index ba05a693570..4e06bd661d0 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -133,6 +133,8 @@ elseif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" O target_compile_options(project_options INTERFACE $<$:-UNDEBUG>) target_compile_options(project_fp_options INTERFACE -ffp-contract=off) # Disable fused-floating point operations (default is fast) elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") + target_compile_options(project_warnings INTERFACE -Wshadow-field) # Equivalent to MSVC's C4458 (declaration of 'identifier' hides class member); narrower than -Wshadow + target_compile_options(project_warnings INTERFACE -Wno-error=shadow-field) # TODO: temporarily non-fatal to collect all instances before fixing if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0) # Suppress unused-but-set warnings until more serious ones are addressed target_compile_options(project_warnings INTERFACE -Wno-unused-but-set-parameter -Wno-unused-but-set-variable) From 0d11994312dc6faf09ce70f0217aa05fad2fdd73 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 10 Jul 2026 13:36:52 +0200 Subject: [PATCH 02/15] Fix some warnings in Windows-CalcEngine --- .../src/PerforatedCellDescription.cpp | 6 ------ .../src/PerforatedCellDescription.hpp | 12 ++++++------ .../src/Tarcog/src/EffectiveOpenness.cpp | 8 ++++---- .../src/Tarcog/src/EffectiveOpenness.hpp | 6 +++--- .../src/Tarcog/src/NonLinearSolver.hpp | 2 -- 5 files changed, 13 insertions(+), 21 deletions(-) diff --git a/third_party/Windows-CalcEngine/src/SingleLayerOptics/src/PerforatedCellDescription.cpp b/third_party/Windows-CalcEngine/src/SingleLayerOptics/src/PerforatedCellDescription.cpp index 5f4e3da20cb..e30e8e2dd55 100644 --- a/third_party/Windows-CalcEngine/src/SingleLayerOptics/src/PerforatedCellDescription.cpp +++ b/third_party/Windows-CalcEngine/src/SingleLayerOptics/src/PerforatedCellDescription.cpp @@ -32,9 +32,6 @@ namespace SingleLayerOptics const double t_Thickness, const double t_Radius) : CPerforatedCellDescription(t_x, t_y, t_Thickness), - m_x(t_x), - m_y(t_y), - m_Thickness(t_Thickness), m_Radius(t_Radius) {} @@ -106,9 +103,6 @@ namespace SingleLayerOptics const double t_XHole, const double t_YHole) : CPerforatedCellDescription(t_x, t_y, t_Thickness), - m_x(t_x), - m_y(t_y), - m_Thickness(t_Thickness), m_XHole(t_XHole), m_YHole(t_YHole) {} diff --git a/third_party/Windows-CalcEngine/src/SingleLayerOptics/src/PerforatedCellDescription.hpp b/third_party/Windows-CalcEngine/src/SingleLayerOptics/src/PerforatedCellDescription.hpp index fc8f9871c88..e0bf6cd355f 100644 --- a/third_party/Windows-CalcEngine/src/SingleLayerOptics/src/PerforatedCellDescription.hpp +++ b/third_party/Windows-CalcEngine/src/SingleLayerOptics/src/PerforatedCellDescription.hpp @@ -36,9 +36,9 @@ namespace SingleLayerOptics private: [[nodiscard]] double visibleAhole(const CBeamDirection & t_Direction) const; [[nodiscard]] double visibleAcell(const CBeamDirection & t_Direction) const; - double m_x; - double m_y; - double m_Thickness; + // double m_x; + // double m_y; + // double m_Thickness; double m_Radius; }; @@ -63,9 +63,9 @@ namespace SingleLayerOptics double TransmittanceV(const CBeamDirection & t_Direction) const; double TransmittanceH(const CBeamDirection & t_Direction) const; - double m_x; - double m_y; - double m_Thickness; + // double m_x; + // double m_y; + // double m_Thickness; double m_XHole; double m_YHole; }; diff --git a/third_party/Windows-CalcEngine/src/Tarcog/src/EffectiveOpenness.cpp b/third_party/Windows-CalcEngine/src/Tarcog/src/EffectiveOpenness.cpp index a9afce553b2..a11d16427a2 100644 --- a/third_party/Windows-CalcEngine/src/Tarcog/src/EffectiveOpenness.cpp +++ b/third_party/Windows-CalcEngine/src/Tarcog/src/EffectiveOpenness.cpp @@ -36,13 +36,13 @@ namespace EffectiveLayers double height, double thickness, const ShadeOpenness & openness, - Coefficients coefficients) : + Coefficients t_coefficients) : m_Width(width), m_Height(height), m_Thickness(thickness), m_ShadeOpenness( openness.Ah * width * height, openness.Dl, openness.Dr, openness.Dtop, openness.Dbot), - coefficients{coefficients} + coefficients{t_coefficients} {} Coefficients::Coefficients(double c1, double c2, double c3, double c4) : @@ -58,8 +58,8 @@ namespace EffectiveLayers const ShadeOpenness & openness, double slatAngle, double slatWidth, - Coefficients coefficients) : - EffectiveLayer(width, height, thickness, openness, coefficients), + Coefficients t_coefficients) : + EffectiveLayer(width, height, thickness, openness, t_coefficients), m_SlatAngleRad(slatAngle * 2.0 * ConstantsData::WCE_PI / 360.0), m_SlatWidth(slatWidth) {} diff --git a/third_party/Windows-CalcEngine/src/Tarcog/src/EffectiveOpenness.hpp b/third_party/Windows-CalcEngine/src/Tarcog/src/EffectiveOpenness.hpp index 7f99c9c7107..20b3f8af12f 100644 --- a/third_party/Windows-CalcEngine/src/Tarcog/src/EffectiveOpenness.hpp +++ b/third_party/Windows-CalcEngine/src/Tarcog/src/EffectiveOpenness.hpp @@ -53,7 +53,7 @@ namespace EffectiveLayers double height, double thickness, const ShadeOpenness & openness, - Coefficients coefficients = {0.0, 0.0, 0.0, 0.0}); + Coefficients t_coefficients = {0.0, 0.0, 0.0, 0.0}); virtual EffectiveOpenness getEffectiveOpenness() = 0; @@ -78,7 +78,7 @@ namespace EffectiveLayers const ShadeOpenness & openness, double slatAngle, double slatWidth, - Coefficients coefficients); + Coefficients t_coefficients); EffectiveOpenness getEffectiveOpenness() override; double effectiveThickness() override; @@ -171,4 +171,4 @@ namespace EffectiveLayers double effectiveThickness() override; }; -} // namespace EffectiveLayers \ No newline at end of file +} // namespace EffectiveLayers diff --git a/third_party/Windows-CalcEngine/src/Tarcog/src/NonLinearSolver.hpp b/third_party/Windows-CalcEngine/src/Tarcog/src/NonLinearSolver.hpp index 2c2d9f0488e..563b31619ce 100644 --- a/third_party/Windows-CalcEngine/src/Tarcog/src/NonLinearSolver.hpp +++ b/third_party/Windows-CalcEngine/src/Tarcog/src/NonLinearSolver.hpp @@ -4,7 +4,6 @@ #include #include -#include #include "HeatFlowBalance.hpp" #include "IGU.hpp" @@ -33,7 +32,6 @@ namespace Tarcog void estimateNewState(const std::vector & t_Solution); CIGU & m_IGU; - FenestrationCommon::CLinearSolver m_LinearSolver; CHeatFlowBalance m_QBalance; std::vector m_IGUState; double m_Tolerance; From d4ab5ae0f67d3155a80061dab3a6e58002e2c040 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 10 Jul 2026 13:39:47 +0200 Subject: [PATCH 03/15] Fix two warnings in courrier /Users/julien/Software/Others/EnergyPlus/third_party/btwxt/include/btwxt/logging.h:33:52: error: parameter 'message' shadows member inherited from type 'CourierrException' [-Werror,-Wshadow-field] 33 | explicit BtwxtException(const std::string &message, Courierr::Courierr &logger) | ^ /Users/julien/Software/Others/EnergyPlus/third_party/btwxt/vendor/courierr/include/courierr/courierr.h:66:17: note: declared here 66 | std::string message; | ^ In file included from /Users/julien/Software/Others/EnergyPlus/src/EnergyPlus/api/state.cc:49: In file included from /Users/julien/Software/Others/EnergyPlus/src/EnergyPlus/Data/CommonIncludes.hh:266: In file included from /Users/julien/Software/Others/EnergyPlus/src/EnergyPlus/SolarShading.hh:61: In file included from /Users/julien/Software/Others/EnergyPlus/third_party/penumbra/include/penumbra/penumbra.h:16: /Users/julien/Software/Others/EnergyPlus/third_party/penumbra/include/penumbra/logging.h:40:49: error: parameter 'message' shadows member inherited from type 'CourierrException' [-Werror,-Wshadow-field] 40 | explicit PenumbraException(const std::string &message, Courierr::Courierr &logger) | ^ /Users/julien/Software/Others/EnergyPlus/third_party/btwxt/vendor/courierr/include/courierr/courierr.h:66:17: note: declared here 66 | std::string message; 51ba69 --- third_party/btwxt/include/btwxt/logging.h | 6 +++--- third_party/penumbra/include/penumbra/logging.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/third_party/btwxt/include/btwxt/logging.h b/third_party/btwxt/include/btwxt/logging.h index 9a13c53bea3..32fa5f3b3b6 100644 --- a/third_party/btwxt/include/btwxt/logging.h +++ b/third_party/btwxt/include/btwxt/logging.h @@ -30,10 +30,10 @@ namespace Btwxt { class BtwxtException : public Courierr::CourierrException { public: - explicit BtwxtException(const std::string &message, Courierr::Courierr &logger) - : CourierrException(message, logger) { + explicit BtwxtException(const std::string &t_message, Courierr::Courierr &logger) + : CourierrException(t_message, logger) { } }; } -#endif // define BTWXT_LOGGING_H_ \ No newline at end of file +#endif // define BTWXT_LOGGING_H_ diff --git a/third_party/penumbra/include/penumbra/logging.h b/third_party/penumbra/include/penumbra/logging.h index 37e25f9cdd7..80d9e51445a 100644 --- a/third_party/penumbra/include/penumbra/logging.h +++ b/third_party/penumbra/include/penumbra/logging.h @@ -37,8 +37,8 @@ class PenumbraLogger : public Courierr::Courierr { class PenumbraException : public Courierr::CourierrException { public: - explicit PenumbraException(const std::string &message, Courierr::Courierr &logger) - : CourierrException(message, logger) {} + explicit PenumbraException(const std::string &t_message, Courierr::Courierr &logger) + : CourierrException(t_message, logger) {} }; class SurfaceException : public PenumbraException { @@ -53,4 +53,4 @@ class SurfaceException : public PenumbraException { }; } // namespace Penumbra -#endif // define PENUMBRA_LOGGING_H_ \ No newline at end of file +#endif // define PENUMBRA_LOGGING_H_ From 851db33b65b6ec5b0acbdd72125e60d79fd631c0 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 10 Jul 2026 14:00:10 +0200 Subject: [PATCH 04/15] Fix two Wshadow warnings anyways in BCVTB --- third_party/BCVTB/BCVTB/utilXml.c | 16 ++++++++-------- third_party/BCVTB/BCVTB/utilXml.h | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/third_party/BCVTB/BCVTB/utilXml.c b/third_party/BCVTB/BCVTB/utilXml.c index 5611469058f..fde0d9e6fa1 100644 --- a/third_party/BCVTB/BCVTB/utilXml.c +++ b/third_party/BCVTB/BCVTB/utilXml.c @@ -731,11 +731,11 @@ size_t getnumberofxmlvalues(char const* const fileName, char const* const exp) { size_t n; int ret; char* str; - int strLen = 0; + int myStrLen = 0; n = 0; str = NULL; PARSEVALUE = 0; - ret = getxmlvalues(fileName, exp, str, &n, strLen); + ret = getxmlvalues(fileName, exp, str, &n, myStrLen); if (-1 == ret) { fprintf(stderr, "Error: In getnumberofxmlvalues.\n"); return ret; @@ -767,9 +767,9 @@ size_t getnumberofxmlvalues(char const* const fileName, char const* const exp) { ///\param atrName the attribute name. ///\param nVal number of attribute values found. ///\param str string to store the found values, semicolon separated. -///\param strLen the string length allocated +///\param myStrLen the string length allocated //////////////////////////////////////////////////////////////// -int getxmlvaluesf(char const* const fileName, char const* const exp, char const* const atrName, size_t* const nVal, char* str, size_t* const strLen) { +int getxmlvaluesf(char const* const fileName, char const* const exp, char const* const atrName, size_t* const nVal, char* str, size_t* const myStrLen) { /////////////////////////////////////////////// /// This part of the code is for compatibility /// with the BCVTB version 0.2 and earlier @@ -778,7 +778,7 @@ int getxmlvaluesf(char const* const fileName, char const* const exp, char const* if (-1 == ret) return -1; ////////////////////////////////////////////// PARSEVALUE = 1; - ret = getxmlvalues(fileName, exp, str, nVal, *strLen); + ret = getxmlvalues(fileName, exp, str, nVal, *myStrLen); if (-1 == ret || *nVal > *strLen) return -1; if (strlen(str) + 2 >= *strLen) { fprintf(stderr, @@ -810,12 +810,12 @@ int getxmlvaluesf(char const* const fileName, char const* const exp, char const* ///\param exp the xPath expression. ///\param str string to store the found values, semicolon separated. ///\param nVals number of values found. -///\param strLen the string length allocated. +///\param myStrLen the string length allocated. //////////////////////////////////////////////////////////////// -int getxmlvalue(char const* const fileName, char const* const exp, char* const str, size_t* const nVals, int const strLen) { +int getxmlvalue(char const* const fileName, char const* const exp, char* const str, size_t* const nVals, int const myStrLen) { int ret; PARSEVALUE = 1; - ret = getxmlvalues(fileName, exp, str, nVals, strLen); + ret = getxmlvalues(fileName, exp, str, nVals, myStrLen); if (ret != 0) { fprintf(stderr, "Error: Error when attempting to parse file '%s'\n", fileName); diff --git a/third_party/BCVTB/BCVTB/utilXml.h b/third_party/BCVTB/BCVTB/utilXml.h index bdc267a9639..86877f36101 100644 --- a/third_party/BCVTB/BCVTB/utilXml.h +++ b/third_party/BCVTB/BCVTB/utilXml.h @@ -279,9 +279,9 @@ size_t getnumberofxmlvalues(char const* const fileName, char const* const exp); ///\param atrName the attribute name. ///\param nVal number of attribute values found. ///\param str string to store the found values, semicolon separated. -///\param strLen the string length allocated +///\param myStrLen the string length allocated //////////////////////////////////////////////////////////////// -int getxmlvaluesf(char const* const fileName, char const* const exp, char const* const atrName, size_t* const nVal, char* str, size_t* const strLen); +int getxmlvaluesf(char const* const fileName, char const* const exp, char const* const atrName, size_t* const nVal, char* str, size_t* const myStrLen); //////////////////////////////////////////////////////////////// /// This method returns one xmlvalue for a given xPath expressions. @@ -302,9 +302,9 @@ int getxmlvaluesf(char const* const fileName, char const* const exp, char const* ///\param exp the xPath expression. ///\param str string to store the found values, semicolon separated. ///\param nVals number of values found. -///\param strLen the string length allocated. +///\param myStrLen the string length allocated. //////////////////////////////////////////////////////////////// -int getxmlvalue(char const* const fileName, char const* const exp, char* const str, size_t* const nVals, int const strLen); +int getxmlvalue(char const* const fileName, char const* const exp, char* const str, size_t* const nVals, int const myStrLen); //////////////////////////////////////////////////////////////// /// This method checks the validity of the variables From 8f7f10c733a56108ad62d963fc79c9bd4bed9a5a Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 14:51:06 +0200 Subject: [PATCH 05/15] Start fixing Wshadow-field warnings --- src/EnergyPlus/ChillerElectricASHRAE205.hh | 1 - .../Coils/CoilCoolingDXCurveFitPerformance.hh | 2 -- src/EnergyPlus/FluidCoolers.hh | 6 +++--- src/EnergyPlus/LowTempRadiantSystem.hh | 11 +++++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/EnergyPlus/ChillerElectricASHRAE205.hh b/src/EnergyPlus/ChillerElectricASHRAE205.hh index ff4eaedf219..f3f6cf5c8e7 100644 --- a/src/EnergyPlus/ChillerElectricASHRAE205.hh +++ b/src/EnergyPlus/ChillerElectricASHRAE205.hh @@ -106,7 +106,6 @@ namespace ChillerElectricASHRAE205 { Real64 AmbientTemp{0}; Real64 AmbientZoneGain{0}; // Internal gain to zone from losses (W) Real64 AmbientZoneGainEnergy{0}; // Internal gain to zone from losses (J) - std::string EndUseSubcategory; // identifier use for the end use subcategory // Default Constructor ASHRAE205ChillerSpecs() = default; diff --git a/src/EnergyPlus/Coils/CoilCoolingDXCurveFitPerformance.hh b/src/EnergyPlus/Coils/CoilCoolingDXCurveFitPerformance.hh index 525e8494ba7..4f2068be77b 100644 --- a/src/EnergyPlus/Coils/CoilCoolingDXCurveFitPerformance.hh +++ b/src/EnergyPlus/Coils/CoilCoolingDXCurveFitPerformance.hh @@ -84,7 +84,6 @@ struct CoilCoolingDXCurveFitPerformanceInputSpecification struct CoilCoolingDXCurveFitPerformance : public CoilCoolingDXPerformanceBase { static constexpr std::string_view object_name = "Coil:Cooling:DX:CurveFit:Performance"; - std::string parentName; void instantiateFromInputSpec(EnergyPlusData &state, const CoilCoolingDXCurveFitPerformanceInputSpecification &input_data); @@ -248,7 +247,6 @@ struct CoilCoolingDXCurveFitPerformance : public CoilCoolingDXPerformanceBase Real64 evapCondBasinHeatSetpoint = 0.0; Sched::Schedule *evapCondBasinHeatSched = nullptr; bool oneTimeEIOHeaderWrite = true; - Real64 wasteHeatRate = 0.0; CoilCoolingDXCurveFitOperatingMode normalMode; CoilCoolingDXCurveFitOperatingMode alternateMode; // enhanced dehumidifcation or Subcool mode diff --git a/src/EnergyPlus/FluidCoolers.hh b/src/EnergyPlus/FluidCoolers.hh index f109a46a6b4..ffc71b42e34 100644 --- a/src/EnergyPlus/FluidCoolers.hh +++ b/src/EnergyPlus/FluidCoolers.hh @@ -120,7 +120,7 @@ namespace FluidCoolers { int WMFRGreaterThanMaxAvailErrCount; // Counter when water mass flow rate is greater than minimum available int WMFRGreaterThanMaxAvailErrIndex; // Index for water mass flow rate > minavail recurring message PlantLocation plantLoc; // loop topology variables - bool oneTimeInitFlag; + // bool oneTimeInitFlag; // Defined in PlantComponent.hh bool beginEnvrnInit; // Report vars @@ -155,8 +155,8 @@ namespace FluidCoolers { OutdoorAirInletNodeNum(0), HighMassFlowErrorCount(0), HighMassFlowErrorIndex(0), OutletWaterTempErrorCount(0), OutletWaterTempErrorIndex(0), SmallWaterMassFlowErrorCount(0), SmallWaterMassFlowErrorIndex(0), WMFRLessThanMinAvailErrCount(0), WMFRLessThanMinAvailErrIndex(0), WMFRGreaterThanMaxAvailErrCount(0), WMFRGreaterThanMaxAvailErrIndex(0), plantLoc{}, - oneTimeInitFlag(true), beginEnvrnInit(true), InletWaterTemp(0.0), OutletWaterTemp(0.0), WaterMassFlowRate(0.0), Qactual(0.0), - FanPower(0.0), FanEnergy(0.0), WaterTemp(0.0), AirTemp(0.0), AirHumRat(0.0), AirPress(0.0), AirWetBulb(0.0), indexInArray(0) + beginEnvrnInit(true), InletWaterTemp(0.0), OutletWaterTemp(0.0), WaterMassFlowRate(0.0), Qactual(0.0), FanPower(0.0), FanEnergy(0.0), + WaterTemp(0.0), AirTemp(0.0), AirHumRat(0.0), AirPress(0.0), AirWetBulb(0.0), indexInArray(0) { } diff --git a/src/EnergyPlus/LowTempRadiantSystem.hh b/src/EnergyPlus/LowTempRadiantSystem.hh index 58825bb9c33..20f12ca2034 100644 --- a/src/EnergyPlus/LowTempRadiantSystem.hh +++ b/src/EnergyPlus/LowTempRadiantSystem.hh @@ -401,9 +401,7 @@ namespace LowTempRadiantSystem { { // Members // This data could be shared between multiple constant flow LowTempRad Systems - std::string designName; // name of the design object - Real64 runningMeanOutdoorAirTemperatureWeightingFactor = - 0.8; // Weighting factor for running mean outdoor air temperature equation (user input) + std::string designName; // name of the design object CtrlType ConstFlowControlType = CtrlType::MAT; // Control type for the system (MAT, MRT, Op temp, ODB, OWB, // Surface Face Temp, Surface Interior Temp, Running Mean Temp // for Constant Flow systems only) @@ -419,7 +417,12 @@ namespace LowTempRadiantSystem { CondCtrlType condCtrlType = CondCtrlType::SimpleOff; // Condensation control type (initialize to simple off) Real64 CondDewPtDeltaT = 1.0; // Diff between surface temperature and dew point for cond. shut-off - ConstantFlowRadDesignData() = default; + ConstantFlowRadDesignData() : ConstantFlowRadiantSystemData() + { + // Weighting factor for running mean outdoor air temperature equation (user input): different default than base than doesn't use it (0.0) + // IDD default is 0.8, so this is set here for clarity (Could let the GetInput routine set it...) + runningMeanOutdoorAirTemperatureWeightingFactor = 0.8; + } ~ConstantFlowRadDesignData() = default; }; From 794c2f55b5c6b9342666a625ef53e88126564128 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 14:54:51 +0200 Subject: [PATCH 06/15] Avoid a shadow and wasted bytes in PlantPipingSystemsManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed `BaseThermalPropertySet Properties;` from `BaseCell`, and instead gave each of its three derived structs its own appropriately-typed `Properties` member directly: - `RadialCellInformation` → `BaseThermalPropertySet Properties;` (new, explicit) - `CartesianCell` → `BaseThermalPropertySet Properties;` (new, explicit) - `FluidCellInformation` → kept its existing `ExtendedFluidProperties Properties;` (unchanged) **Why:** `FluidCellInformation` was redeclaring `Properties` with the wider `ExtendedFluidProperties` type (adds `Viscosity`/`Prandtl`) to shadow the inherited `BaseThermalPropertySet Properties` from `BaseCell` — needed so that bulk-assignments like `cell.PipeCellData.Fluid.Properties = thisCircuit->CurFluidPropertySet;` copy the full extended struct instead of object-slicing it. This triggered a `-Wshadow-field` warning, and — since C++ field-hiding isn't virtual dispatch — meant every `FluidCellInformation` instance carried a second, entirely dead `BaseThermalPropertySet` subobject inherited from `BaseCell` that was never read or written. Since `BaseCell` itself is never instantiated or referenced directly (only used as a base for these three structs), moving `Properties` down into each derived struct removes the shadowing entirely and eliminates the wasted subobject, with no behavior change — `RadialCellInformation` and `CartesianCell` still get the same `BaseThermalPropertySet Properties` they had before, just declared locally instead of inherited. --- src/EnergyPlus/PlantPipingSystemsManager.hh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EnergyPlus/PlantPipingSystemsManager.hh b/src/EnergyPlus/PlantPipingSystemsManager.hh index eb8950c4230..61100e7598c 100644 --- a/src/EnergyPlus/PlantPipingSystemsManager.hh +++ b/src/EnergyPlus/PlantPipingSystemsManager.hh @@ -220,7 +220,6 @@ namespace PlantPipingSystemsManager { Real64 Temperature_PrevIteration = 0.0; // C Real64 Temperature_PrevTimeStep = 0.0; // C Real64 Beta = 0.0; // K/W - BaseThermalPropertySet Properties; // Default Constructor BaseCell() = default; @@ -247,6 +246,7 @@ namespace PlantPipingSystemsManager { Real64 RadialCentroid = 0.0; Real64 InnerRadius = 0.0; Real64 OuterRadius = 0.0; + BaseThermalPropertySet Properties; // Default Constructor RadialCellInformation() = default; @@ -463,6 +463,7 @@ namespace PlantPipingSystemsManager { CellType cellType = CellType::Invalid; std::map NeighborInfo; CartesianPipeCellInformation PipeCellData; + BaseThermalPropertySet Properties; // Default Constructor CartesianCell() = default; From 00c76d73f5c1601ea7d788dfbf4f9f9b4e3ef391 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 15:24:34 +0200 Subject: [PATCH 07/15] Wshadow revealed a big inheritance mistake in SteamBaseboardRadiator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So there’s a ZoneHVAC:Baseboard:RadiantConvective:Steam and a ZoneHVAC:Baseboard:RadiantConvective:Steam:Design objects The C++ `SteamBaseboardParams` instance has an `int` index to find the `SteamBaseboardDesignData`... But the `SteamBaseboardDesignData` inherits from `SteamBaseboardParams`, so it carries EVERY field from SteamBaseboardParams, so about 656 bytes for no reason! It shouldn't inherit at all! --- src/EnergyPlus/SteamBaseboardRadiator.hh | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/EnergyPlus/SteamBaseboardRadiator.hh b/src/EnergyPlus/SteamBaseboardRadiator.hh index 48da0b211ce..db5ead86879 100644 --- a/src/EnergyPlus/SteamBaseboardRadiator.hh +++ b/src/EnergyPlus/SteamBaseboardRadiator.hh @@ -93,9 +93,7 @@ namespace SteamBaseboardRadiator { Real64 SteamOutletPress; // Pressure of steam at the outlet of the heater [Pa] Real64 SteamInletQuality; // Quality of steam at the inlet of the heater [Pa] Real64 SteamOutletQuality; // Quality of steam at the outlet of the heater [Pa] - Real64 FracRadiant; // User defined fraction for radiant heat addition Real64 FracConvect; // Fraction for convective heat addition - Real64 FracDistribPerson; // Fraction for radiant heat incident on people Array1D FracDistribToSurf; Real64 TotPower; // Convective system impact rate that the heater actually meets [W] Real64 Power; // Maximum heating rate [W] @@ -127,16 +125,15 @@ namespace SteamBaseboardRadiator { : EquipType(DataPlant::PlantEquipmentType::Invalid), DesignObjectPtr(0), ZonePtr(0), SteamInletNode(0), SteamOutletNode(0), TotSurfToDistrib(0), ControlCompTypeNum(0), CompErrIndex(0), DegOfSubcooling(0.0), SteamMassFlowRate(0.0), SteamMassFlowRateMax(0.0), SteamVolFlowRateMax(0.0), SteamOutletTemp(0.0), SteamInletTemp(0.0), SteamInletEnthalpy(0.0), SteamOutletEnthalpy(0.0), - SteamInletPress(0.0), SteamOutletPress(0.0), SteamInletQuality(0.0), SteamOutletQuality(0.0), FracRadiant(0.0), FracConvect(0.0), - FracDistribPerson(0.0), TotPower(0.0), Power(0.0), ConvPower(0.0), RadPower(0.0), TotEnergy(0.0), Energy(0.0), ConvEnergy(0.0), - RadEnergy(0.0), plantLoc{}, BBLoadReSimIndex(0), BBMassFlowReSimIndex(0), BBInletTempFlowReSimIndex(0), QBBSteamRadSource(0.0), - QBBSteamRadSrcAvg(0.0), ZeroBBSteamSourceSumHATsurf(0.0), LastQBBSteamRadSrc(0.0), LastSysTimeElapsed(0.0), LastTimeStepSys(0.0), - ScaledHeatingCapacity(0.0) + SteamInletPress(0.0), SteamOutletPress(0.0), SteamInletQuality(0.0), SteamOutletQuality(0.0), FracConvect(0.0), TotPower(0.0), + Power(0.0), ConvPower(0.0), RadPower(0.0), TotEnergy(0.0), Energy(0.0), ConvEnergy(0.0), RadEnergy(0.0), plantLoc{}, + BBLoadReSimIndex(0), BBMassFlowReSimIndex(0), BBInletTempFlowReSimIndex(0), QBBSteamRadSource(0.0), QBBSteamRadSrcAvg(0.0), + ZeroBBSteamSourceSumHATsurf(0.0), LastQBBSteamRadSrc(0.0), LastSysTimeElapsed(0.0), LastTimeStepSys(0.0), ScaledHeatingCapacity(0.0) { } }; - struct SteamBaseboardDesignData : SteamBaseboardParams + struct SteamBaseboardDesignData { // Members std::string designName; From 45843906af3bc2eb6412ee3324ec0112c9cbec65 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 15:29:07 +0200 Subject: [PATCH 08/15] HWBaseboardRadiator.hh: Same as SteamBaseboardRadiator: should NOT be inheriting Here HWBaseboardParams::HeatingCapMethod/ScaledHeatingCapacity are genuinely used as per-instance cached copies (set once from the design object, read every timestep), so those stayed untouched --- src/EnergyPlus/HWBaseboardRadiator.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EnergyPlus/HWBaseboardRadiator.hh b/src/EnergyPlus/HWBaseboardRadiator.hh index 4f39d0b9dcf..66b29cbd75d 100644 --- a/src/EnergyPlus/HWBaseboardRadiator.hh +++ b/src/EnergyPlus/HWBaseboardRadiator.hh @@ -129,7 +129,7 @@ namespace HWBaseboardRadiator { Real64 LastQBBRadSrc = 0.0; // Need to keep the last value in case we are still iterating }; - struct HWBaseboardDesignData : HWBaseboardParams + struct HWBaseboardDesignData { // Members std::string designName; From 763c45463c02ef20e437b87209f033569847a235 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 15:35:23 +0200 Subject: [PATCH 09/15] straightforward fixes in PlantLoopHeatPumpEIR.hh: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed four pure-duplicate member redeclarations that shadowed identical inherited fields for no reason — same name, same type, same default, no divergent usage found anywhere in the `.cc`: - `EIRPlantLoopHeatPump::oneTimeInitFlag` (line 209) — exact duplicate of `PlantComponent::oneTimeInitFlag` (`bool`, default `true`). Deleted; `this->oneTimeInitFlag` now resolves to the inherited one, same behavior. - `EIRFuelFiredHeatPump::flowMode` — exact duplicate of `EIRPlantLoopHeatPump::flowMode` (`DataPlant::FlowMode`, default `Invalid`). Deleted. - `EIRFuelFiredHeatPump::capModFTErrorIndex`, `eirModFTErrorIndex`, `eirModFPLRErrorIndex` — exact duplicates of the same-named `int` error-index members on `EIRPlantLoopHeatPump` (all default `0`). Deleted. In all four cases the derived class had no custom constructor initializing these differently, and every usage site accessed them polymorphically through `this->` — so removing the redeclaration doesn't change behavior, just stops the derived object from carrying (and the compiler from having to reason about) two separately-named-but-identical copies of the same state. --- src/EnergyPlus/PlantLoopHeatPumpEIR.hh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/EnergyPlus/PlantLoopHeatPumpEIR.hh b/src/EnergyPlus/PlantLoopHeatPumpEIR.hh index 9a61aaca336..30d33f96667 100644 --- a/src/EnergyPlus/PlantLoopHeatPumpEIR.hh +++ b/src/EnergyPlus/PlantLoopHeatPumpEIR.hh @@ -206,7 +206,6 @@ namespace EIRPlantLoopHeatPumps { int recurringConcurrentOperationWarningIndex = 0; // logic flags - bool oneTimeInitFlag = true; bool envrnInit = true; // recurrent warning messages index integers @@ -388,7 +387,6 @@ namespace EIRPlantLoopHeatPumps { // New additions for GAHP only Constant::eFuel fuelType = Constant::eFuel::Invalid; // Fuel type assignment std::string endUseSubcat; - DataPlant::FlowMode flowMode = DataPlant::FlowMode::Invalid; Real64 desSupplyTemp = 60.0; Real64 desTempLift = 11.1; OATempCurveVar oaTempCurveInputVar = OATempCurveVar::DryBulb; @@ -417,9 +415,6 @@ namespace EIRPlantLoopHeatPumps { Real64 loadSideVolumeFlowRate = 0.0; Real64 fuelRate = 0.0; // Unit in W Real64 fuelEnergy = 0.0; // Unit in J - int capModFTErrorIndex = 0; - int eirModFTErrorIndex = 0; - int eirModFPLRErrorIndex = 0; int eirDefrostFTErrorIndex = 0; int eirAuxElecFTErrorIndex = 0; int eirAuxElecFPLRErrorIndex = 0; From 85bbbbc1660726eb9727c32cae852dd49a169450 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 15:46:14 +0200 Subject: [PATCH 10/15] Rename the shadowed xxxFuncYYYCurveIndex -> xxxFuncYYYCurveIndices when it goes to an array for HeatPumpAirToWater The base class xxxFuncYYYCurveIndex still exists but it's left untouched at int = 0, so trying to access curves(int) with it will throw when NDEBUG not defined, and having three unused ints beats creating a new derived class... --- src/EnergyPlus/PlantLoopHeatPumpEIR.cc | 40 ++++++------ src/EnergyPlus/PlantLoopHeatPumpEIR.hh | 6 +- .../unit/PlantLoopHeatPumpEIR.unit.cc | 64 +++++++++---------- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/EnergyPlus/PlantLoopHeatPumpEIR.cc b/src/EnergyPlus/PlantLoopHeatPumpEIR.cc index 65609c5c3dc..6330c5c164b 100644 --- a/src/EnergyPlus/PlantLoopHeatPumpEIR.cc +++ b/src/EnergyPlus/PlantLoopHeatPumpEIR.cc @@ -666,7 +666,7 @@ void HeatPumpAirToWater::calcPowerUsage(EnergyPlusData &state, Real64 availableC int localSpeedLevel = 0; for (int i = 0; i < this->numSpeeds; i++) { capacityModifierFuncTempHigh = - Curve::CurveValue(state, this->capFuncTempCurveIndex[i], loadSideOutletSetpointTemp, this->sourceSideInletTemp); + Curve::CurveValue(state, this->capFuncTempCurveIndices[i], loadSideOutletSetpointTemp, this->sourceSideInletTemp); capacityHigh = this->ratedCapacity[i] * capacityModifierFuncTempHigh; localSpeedLevel = i; if (std::fabs(currentLoadNthUnit) <= capacityHigh) { @@ -680,14 +680,14 @@ void HeatPumpAirToWater::calcPowerUsage(EnergyPlusData &state, Real64 availableC Real64 eirModifierFuncPLRLow = 1.0; if (localSpeedLevel > 0) { eirModifierFuncTempLow = - Curve::CurveValue(state, this->powerRatioFuncTempCurveIndex[localSpeedLevel - 1], this->loadSideOutletTemp, this->sourceSideInletTemp); - eirModifierFuncPLRLow = Curve::CurveValue(state, this->powerRatioFuncPLRCurveIndex[localSpeedLevel - 1], this->partLoadRatio); + Curve::CurveValue(state, this->powerRatioFuncTempCurveIndices[localSpeedLevel - 1], this->loadSideOutletTemp, this->sourceSideInletTemp); + eirModifierFuncPLRLow = Curve::CurveValue(state, this->powerRatioFuncPLRCurveIndices[localSpeedLevel - 1], this->partLoadRatio); this->eirModCurveCheck(state, eirModifierFuncTempLow); this->eirModFPLRCurveCheck(state, eirModifierFuncPLRLow); } Real64 eirModifierFuncTempHigh = - Curve::CurveValue(state, this->powerRatioFuncTempCurveIndex[localSpeedLevel], this->loadSideOutletTemp, this->sourceSideInletTemp); - Real64 eirModifierFuncPLRHigh = Curve::CurveValue(state, this->powerRatioFuncPLRCurveIndex[localSpeedLevel], this->partLoadRatio); + Curve::CurveValue(state, this->powerRatioFuncTempCurveIndices[localSpeedLevel], this->loadSideOutletTemp, this->sourceSideInletTemp); + Real64 eirModifierFuncPLRHigh = Curve::CurveValue(state, this->powerRatioFuncPLRCurveIndices[localSpeedLevel], this->partLoadRatio); // check curves value and resets to zero if negative this->eirModCurveCheck(state, eirModifierFuncTempHigh); this->eirModFPLRCurveCheck(state, eirModifierFuncPLRHigh); @@ -4153,8 +4153,8 @@ void HeatPumpAirToWater::processInputForEIRPLHP(EnergyPlusData &state) } thisAWHP.ratedCOP[i] = state.dataInputProcessing->inputProcessor->getRealFieldValue( fields, schemaProps, std::format("rated_cop_for_{}_at_speed_{}", modeKeyWord, i + 1)); - thisAWHP.capFuncTempCurveIndex[i] = Curve::GetCurveIndex(state, capFtName); - if (thisAWHP.capFuncTempCurveIndex[i] == 0) { + thisAWHP.capFuncTempCurveIndices[i] = Curve::GetCurveIndex(state, capFtName); + if (thisAWHP.capFuncTempCurveIndices[i] == 0) { ShowSevereError( state, std::format("Invalid curve name for HeatPump:AirToWater (name={}; entered curve name: {}", thisAWHP.name, capFtName)); @@ -4171,8 +4171,8 @@ void HeatPumpAirToWater::processInputForEIRPLHP(EnergyPlusData &state) } std::string const eirFtName = Util::makeUPPER(fields.at(eirFtFieldName).get()); - thisAWHP.powerRatioFuncTempCurveIndex[i] = Curve::GetCurveIndex(state, eirFtName); - if (thisAWHP.powerRatioFuncTempCurveIndex[i] == 0) { + thisAWHP.powerRatioFuncTempCurveIndices[i] = Curve::GetCurveIndex(state, eirFtName); + if (thisAWHP.powerRatioFuncTempCurveIndices[i] == 0) { ShowSevereError( state, std::format("Invalid curve name for HeatPump:AirToWater (name={}; entered curve name: {}", thisAWHP.name, eirFtName)); @@ -4188,8 +4188,8 @@ void HeatPumpAirToWater::processInputForEIRPLHP(EnergyPlusData &state) errorsFound = true; } std::string const eirFplrName = Util::makeUPPER(fields.at(eirFplrFieldName).get()); - thisAWHP.powerRatioFuncPLRCurveIndex[i] = Curve::GetCurveIndex(state, eirFplrName); - if (thisAWHP.powerRatioFuncPLRCurveIndex[i] == 0) { + thisAWHP.powerRatioFuncPLRCurveIndices[i] = Curve::GetCurveIndex(state, eirFplrName); + if (thisAWHP.powerRatioFuncPLRCurveIndices[i] == 0) { ShowSevereError( state, std::format("Invalid curve name for HeatPump:AirToWater (name={}; entered curve name: {}", thisAWHP.name, eirFplrName)); @@ -4213,8 +4213,8 @@ void HeatPumpAirToWater::processInputForEIRPLHP(EnergyPlusData &state) fields, schemaProps, std::format("rated_{}_capacity_in_booster_mode", modeKeyWord)); thisAWHP.ratedCOP[speedLevelBooster] = state.dataInputProcessing->inputProcessor->getRealFieldValue( fields, schemaProps, std::format("rated_{}_cop_in_booster_mode", modeKeyWord)); - thisAWHP.capFuncTempCurveIndex[speedLevelBooster] = Curve::GetCurveIndex(state, capFtName); - if (thisAWHP.capFuncTempCurveIndex[speedLevelBooster] == 0) { + thisAWHP.capFuncTempCurveIndices[speedLevelBooster] = Curve::GetCurveIndex(state, capFtName); + if (thisAWHP.capFuncTempCurveIndices[speedLevelBooster] == 0) { ShowSevereError( state, std::format("Invalid curve name for HeatPump:AirToWater (name={}; entered curve name: {}", thisAWHP.name, capFtName)); @@ -4230,8 +4230,8 @@ void HeatPumpAirToWater::processInputForEIRPLHP(EnergyPlusData &state) } std::string const eirFtName = Util::makeUPPER(fields.at(eirFtFieldName).get()); - thisAWHP.powerRatioFuncTempCurveIndex[speedLevelBooster] = Curve::GetCurveIndex(state, eirFtName); - if (thisAWHP.powerRatioFuncTempCurveIndex[speedLevelBooster] == 0) { + thisAWHP.powerRatioFuncTempCurveIndices[speedLevelBooster] = Curve::GetCurveIndex(state, eirFtName); + if (thisAWHP.powerRatioFuncTempCurveIndices[speedLevelBooster] == 0) { ShowSevereError( state, std::format("Invalid curve name for HeatPump:AirToWater (name={}; entered curve name: {}", thisAWHP.name, eirFtName)); @@ -4246,8 +4246,8 @@ void HeatPumpAirToWater::processInputForEIRPLHP(EnergyPlusData &state) errorsFound = true; } std::string const eirFplrName = Util::makeUPPER(fields.at(eirFplrFieldName).get()); - thisAWHP.powerRatioFuncPLRCurveIndex[speedLevelBooster] = Curve::GetCurveIndex(state, eirFplrName); - if (thisAWHP.powerRatioFuncPLRCurveIndex[speedLevelBooster] == 0) { + thisAWHP.powerRatioFuncPLRCurveIndices[speedLevelBooster] = Curve::GetCurveIndex(state, eirFplrName); + if (thisAWHP.powerRatioFuncPLRCurveIndices[speedLevelBooster] == 0) { ShowSevereError( state, std::format("Invalid curve name for HeatPump:AirToWater (name={}; entered curve name: {}", thisAWHP.name, eirFplrName)); @@ -4548,7 +4548,7 @@ void HeatPumpAirToWater::calcOpMode(EnergyPlus::EnergyPlusData &state, Real64 cu if (this->companionHeatPumpCoil == nullptr) { this->operatingMode = 1; if (this->OperationModeEMSOverrideOn) { - auto curveIndex = this->capFuncTempCurveIndex[this->numSpeeds - 1]; + auto curveIndex = this->capFuncTempCurveIndices[this->numSpeeds - 1]; auto capacityModifierFuncTemp = Curve::CurveValue(state, curveIndex, this->loadSideOutletTemp, this->sourceSideInletTemp); auto availableCapacityOneUnit = this->referenceCapacityOneUnit * capacityModifierFuncTemp; this->operatingMode = ceil(fabs(currentLoad) / availableCapacityOneUnit); @@ -4567,7 +4567,7 @@ void HeatPumpAirToWater::calcOpMode(EnergyPlus::EnergyPlusData &state, Real64 cu auto &this_loop_side(this_loop.LoopSide(LoopSideNum)); auto &this_component = this_loop_side.Branch(BranchNum).Comp(CompNum); auto companionLoad = this_component.MyLoad; - auto curveIndex = this->capFuncTempCurveIndex[this->numSpeeds - 1]; + auto curveIndex = this->capFuncTempCurveIndices[this->numSpeeds - 1]; auto capacityModifierFuncTemp = Curve::CurveValue(state, curveIndex, this->loadSideOutletTemp, this->sourceSideInletTemp); auto availableCapacityOneUnit = this->referenceCapacityOneUnit * capacityModifierFuncTemp; auto &companionCoil = this->companionHeatPumpCoil; @@ -4736,7 +4736,7 @@ void HeatPumpAirToWater::doPhysics(EnergyPlusData &state, Real64 currentLoad) Real64 localPartLoadRatio = 0.0; Real64 availableCapacity; - this->calcAvailableCapacity(state, currentLoad, this->capFuncTempCurveIndex[this->numSpeeds - 1], availableCapacity, localPartLoadRatio); + this->calcAvailableCapacity(state, currentLoad, this->capFuncTempCurveIndices[this->numSpeeds - 1], availableCapacity, localPartLoadRatio); if (this->waterTempExceeded) { // turn off the equipment if water temp exceeded operation limits this->loadSideMassFlowRate = 0.0; this->sourceSideMassFlowRate = 0.0; diff --git a/src/EnergyPlus/PlantLoopHeatPumpEIR.hh b/src/EnergyPlus/PlantLoopHeatPumpEIR.hh index 30d33f96667..e725f726725 100644 --- a/src/EnergyPlus/PlantLoopHeatPumpEIR.hh +++ b/src/EnergyPlus/PlantLoopHeatPumpEIR.hh @@ -483,9 +483,9 @@ namespace EIRPlantLoopHeatPumps { // adding 1 to account for booster mode curves std::array ratedCapacity = {}; std::array ratedCOP = {}; - std::array capFuncTempCurveIndex = {}; - std::array powerRatioFuncTempCurveIndex = {}; - std::array powerRatioFuncPLRCurveIndex = {}; + std::array capFuncTempCurveIndices = {}; + std::array powerRatioFuncTempCurveIndices = {}; + std::array powerRatioFuncPLRCurveIndices = {}; // 0-indexing, if it's fixed speed, it's integer; if it's variable speed, it's continuous Real64 speedLevel = 0.0; // 1-indexing Real64 speedRatio = 0.0; diff --git a/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc b/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc index 744ade1376e..4703b60474c 100644 --- a/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc +++ b/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc @@ -1004,19 +1004,19 @@ TEST_F(EnergyPlusFixture, processInputForEIRPLHP_AWHP) EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].referenceCapacity, 500); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].ratedCapacity[0], 120); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].ratedCOP[0], 4); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].capFuncTempCurveIndex[0], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncTempCurveIndex[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncPLRCurveIndex[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].capFuncTempCurveIndices[0], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncTempCurveIndices[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncPLRCurveIndices[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].ratedCapacity[1], 240); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].ratedCOP[1], 3.5); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].capFuncTempCurveIndex[1], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncTempCurveIndex[1], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncPLRCurveIndex[1], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].capFuncTempCurveIndices[1], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncTempCurveIndices[1], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncPLRCurveIndices[1], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].ratedCapacity[2], 500); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].ratedCOP[2], 2.0); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].capFuncTempCurveIndex[2], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncTempCurveIndex[2], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncPLRCurveIndex[2], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].capFuncTempCurveIndices[2], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncTempCurveIndices[2], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[0].powerRatioFuncPLRCurveIndices[2], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); EXPECT_ENUM_EQ(state->dataHeatPumpAirToWater->heatPumps[0].operatingModeControlMethod, HeatPumpAirToWater::OperatingModeControlMethod::Load); EXPECT_ENUM_EQ(state->dataHeatPumpAirToWater->heatPumps[0].operatingModeControlOptionMultipleUnit, HeatPumpAirToWater::OperatingModeControlOptionMultipleUnit::SingleMode); @@ -1055,19 +1055,19 @@ TEST_F(EnergyPlusFixture, processInputForEIRPLHP_AWHP) EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].referenceCapacity, 50000); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].ratedCapacity[0], 100); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].ratedCOP[0], 3); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].capFuncTempCurveIndex[0], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncTempCurveIndex[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncPLRCurveIndex[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].capFuncTempCurveIndices[0], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncTempCurveIndices[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncPLRCurveIndices[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].ratedCapacity[1], 200); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].ratedCOP[1], 3.5); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].capFuncTempCurveIndex[1], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncTempCurveIndex[1], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncPLRCurveIndex[1], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].capFuncTempCurveIndices[1], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncTempCurveIndices[1], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncPLRCurveIndices[1], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].ratedCapacity[2], 50000); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].ratedCOP[2], 2.5); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].capFuncTempCurveIndex[2], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncTempCurveIndex[2], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncPLRCurveIndex[2], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].capFuncTempCurveIndices[2], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncTempCurveIndices[2], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[1].powerRatioFuncPLRCurveIndices[2], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); EXPECT_ENUM_EQ(state->dataHeatPumpAirToWater->heatPumps[1].operatingModeControlMethod, HeatPumpAirToWater::OperatingModeControlMethod::Load); EXPECT_ENUM_EQ(state->dataHeatPumpAirToWater->heatPumps[1].operatingModeControlOptionMultipleUnit, HeatPumpAirToWater::OperatingModeControlOptionMultipleUnit::SingleMode); @@ -1101,9 +1101,9 @@ TEST_F(EnergyPlusFixture, processInputForEIRPLHP_AWHP) EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[2].referenceCapacity, -99999); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[2].ratedCapacity[0], -99999); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[2].ratedCOP[0], 3.0); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[2].capFuncTempCurveIndex[0], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[2].powerRatioFuncTempCurveIndex[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[2].powerRatioFuncPLRCurveIndex[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[2].capFuncTempCurveIndices[0], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[2].powerRatioFuncTempCurveIndices[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[2].powerRatioFuncPLRCurveIndices[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); EXPECT_ENUM_EQ(state->dataHeatPumpAirToWater->heatPumps[2].operatingModeControlMethod, HeatPumpAirToWater::OperatingModeControlMethod::Load); EXPECT_ENUM_EQ(state->dataHeatPumpAirToWater->heatPumps[2].operatingModeControlOptionMultipleUnit, HeatPumpAirToWater::OperatingModeControlOptionMultipleUnit::SingleMode); @@ -1140,9 +1140,9 @@ TEST_F(EnergyPlusFixture, processInputForEIRPLHP_AWHP) EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[3].referenceCapacity, -99999); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[3].ratedCapacity[0], -99999); EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[3].ratedCOP[0], 3.0); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[3].capFuncTempCurveIndex[0], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[3].powerRatioFuncTempCurveIndex[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); - EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[3].powerRatioFuncPLRCurveIndex[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[3].capFuncTempCurveIndices[0], Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[3].powerRatioFuncTempCurveIndices[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP")); + EXPECT_EQ(state->dataHeatPumpAirToWater->heatPumps[3].powerRatioFuncPLRCurveIndices[0], Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR")); EXPECT_ENUM_EQ(state->dataHeatPumpAirToWater->heatPumps[3].operatingModeControlMethod, HeatPumpAirToWater::OperatingModeControlMethod::Load); EXPECT_ENUM_EQ(state->dataHeatPumpAirToWater->heatPumps[3].operatingModeControlOptionMultipleUnit, HeatPumpAirToWater::OperatingModeControlOptionMultipleUnit::SingleMode); @@ -1293,14 +1293,14 @@ TEST_F(EnergyPlusFixture, calcPowerUsage_AWHP) thisAWHP.numSpeeds = 2; thisAWHP.ratedCapacity[0] = 600; thisAWHP.ratedCOP[0] = 1; - thisAWHP.capFuncTempCurveIndex[0] = Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP"); - thisAWHP.powerRatioFuncTempCurveIndex[0] = Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP"); - thisAWHP.powerRatioFuncPLRCurveIndex[0] = Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR"); + thisAWHP.capFuncTempCurveIndices[0] = Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP"); + thisAWHP.powerRatioFuncTempCurveIndices[0] = Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP"); + thisAWHP.powerRatioFuncPLRCurveIndices[0] = Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR"); thisAWHP.ratedCapacity[1] = 1200; thisAWHP.ratedCOP[1] = 1; - thisAWHP.capFuncTempCurveIndex[1] = Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP"); - thisAWHP.powerRatioFuncTempCurveIndex[1] = Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP"); - thisAWHP.powerRatioFuncPLRCurveIndex[1] = Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR"); + thisAWHP.capFuncTempCurveIndices[1] = Curve::GetCurveIndex(*state, "CAPCURVEFUNCTEMP"); + thisAWHP.powerRatioFuncTempCurveIndices[1] = Curve::GetCurveIndex(*state, "EIRCURVEFUNCTEMP"); + thisAWHP.powerRatioFuncPLRCurveIndices[1] = Curve::GetCurveIndex(*state, "EIRCURVEFUNCPLR"); thisAWHP.heatPumpMultiplier = 2; thisAWHP.cyclingRatio = 1.0; Real64 availableCapacityBeforeMultiplier = thisAWHP.ratedCapacity[1]; @@ -1418,10 +1418,10 @@ TEST_F(EnergyPlusFixture, calcOpMode_AWHP) PlantUtilities::SetPlantLocationLinks(*state, companionAWHP.loadSidePlantLoc); companionAWHP.OperationModeEMSOverrideOn = false; - thisAWHP.capFuncTempCurveIndex[0] = 1; + thisAWHP.capFuncTempCurveIndices[0] = 1; thisAWHP.loadSideOutletTemp = 65; thisAWHP.sourceSideInletTemp = 20; - companionAWHP.capFuncTempCurveIndex[0] = 1; + companionAWHP.capFuncTempCurveIndices[0] = 1; companionAWHP.loadSideOutletTemp = 65; companionAWHP.sourceSideInletTemp = 20; From 1826117dafdf932a0b69b648513c883cb3c7cb8d Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 16:07:21 +0200 Subject: [PATCH 11/15] I need a unique oneTimeInitFlag actually here, it does things after the PlantComponent one --- src/EnergyPlus/PlantLoopHeatPumpEIR.cc | 8 ++++---- src/EnergyPlus/PlantLoopHeatPumpEIR.hh | 1 + tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/EnergyPlus/PlantLoopHeatPumpEIR.cc b/src/EnergyPlus/PlantLoopHeatPumpEIR.cc index 6330c5c164b..ba0d9f1e6f7 100644 --- a/src/EnergyPlus/PlantLoopHeatPumpEIR.cc +++ b/src/EnergyPlus/PlantLoopHeatPumpEIR.cc @@ -2332,7 +2332,7 @@ void EIRPlantLoopHeatPump::oneTimeInit(EnergyPlusData &state) // This function does all the one-time initialization constexpr std::string_view routineName = "EIRPlantLoopHeatPump : oneTimeInit"; // + __FUNCTION__; - if (this->oneTimeInitFlag) { + if (this->oneTimeInitFlagPLHP) { bool errFlag = false; std::string suffix; if (this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpAirToWaterHeating) { @@ -2705,7 +2705,7 @@ void EIRPlantLoopHeatPump::oneTimeInit(EnergyPlusData &state) if (errFlag) { ShowFatalError(state, std::format("{}: Program terminated due to previous condition(s).", routineName)); } - this->oneTimeInitFlag = false; + this->oneTimeInitFlagPLHP = false; } } @@ -4303,7 +4303,7 @@ void EIRFuelFiredHeatPump::oneTimeInit(EnergyPlusData &state) // This function does all the one-time initialization constexpr std::string_view routineName = "EIRFuelFiredHeatPump : oneTimeInit"; // + __FUNCTION__; - if (this->oneTimeInitFlag) { + if (this->oneTimeInitFlagPLHP) { bool errFlag = false; // setup output variables @@ -4489,7 +4489,7 @@ void EIRFuelFiredHeatPump::oneTimeInit(EnergyPlusData &state) if (errFlag) { ShowFatalError(state, std::format("{}: Program terminated due to previous condition(s).", routineName)); } - this->oneTimeInitFlag = false; + this->oneTimeInitFlagPLHP = false; } } diff --git a/src/EnergyPlus/PlantLoopHeatPumpEIR.hh b/src/EnergyPlus/PlantLoopHeatPumpEIR.hh index e725f726725..747a1b7fe86 100644 --- a/src/EnergyPlus/PlantLoopHeatPumpEIR.hh +++ b/src/EnergyPlus/PlantLoopHeatPumpEIR.hh @@ -206,6 +206,7 @@ namespace EIRPlantLoopHeatPumps { int recurringConcurrentOperationWarningIndex = 0; // logic flags + bool oneTimeInitFlagPLHP = true; bool envrnInit = true; // recurrent warning messages index integers diff --git a/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc b/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc index 4703b60474c..8a06466a06c 100644 --- a/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc +++ b/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc @@ -2019,7 +2019,7 @@ TEST_F(EnergyPlusFixture, EIRPLHP_Initialization_SetpointMissing) state->dataLoopNodes->Node(thisHeatingPLHP->loadSideNodes.outlet).TempSetPointLo = Node::SensedNodeFlagValue; // reset the flag to force re-running oneTimeInit - thisHeatingPLHP->oneTimeInitFlag = true; + thisHeatingPLHP->oneTimeInitFlagPLHP = true; thisHeatingPLHP->SetpointSetToLoopErrDone = false; thisHeatingPLHP->onInitLoopEquip(*state, myLocation); From 2ac5bf654b0819e0c5433f658c6a4d4dd8ae6ed0 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 16:32:41 +0200 Subject: [PATCH 12/15] Last shadow issue: companionHeatPumpCoil redefined as a different pointer type --- src/EnergyPlus/PlantLoopHeatPumpEIR.cc | 37 ++++++++++++++------------ src/EnergyPlus/PlantLoopHeatPumpEIR.hh | 6 ++++- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/EnergyPlus/PlantLoopHeatPumpEIR.cc b/src/EnergyPlus/PlantLoopHeatPumpEIR.cc index ba0d9f1e6f7..2e683b767e6 100644 --- a/src/EnergyPlus/PlantLoopHeatPumpEIR.cc +++ b/src/EnergyPlus/PlantLoopHeatPumpEIR.cc @@ -4570,33 +4570,36 @@ void HeatPumpAirToWater::calcOpMode(EnergyPlus::EnergyPlusData &state, Real64 cu auto curveIndex = this->capFuncTempCurveIndices[this->numSpeeds - 1]; auto capacityModifierFuncTemp = Curve::CurveValue(state, curveIndex, this->loadSideOutletTemp, this->sourceSideInletTemp); auto availableCapacityOneUnit = this->referenceCapacityOneUnit * capacityModifierFuncTemp; - auto &companionCoil = this->companionHeatPumpCoil; + + // This is safe because we know companionHeatPumpCoil is a HeatPumpAirToWater, so we can static_cast it + auto &companionCoil = static_cast(*this->companionHeatPumpCoil); + auto companionCapacityModifierFuncTemp = - Curve::CurveValue(state, curveIndex, companionCoil->loadSideOutletTemp, companionCoil->sourceSideInletTemp); - auto companionAvailableCapacityOneUnit = companionCoil->referenceCapacityOneUnit * companionCapacityModifierFuncTemp; + Curve::CurveValue(state, curveIndex, companionCoil.loadSideOutletTemp, companionCoil.sourceSideInletTemp); + auto companionAvailableCapacityOneUnit = companionCoil.referenceCapacityOneUnit * companionCapacityModifierFuncTemp; if (this->OperationModeEMSOverrideOn) { if (this->OperationModeEMSOverrideValue > 0) { this->operatingMode = min(this->heatPumpMultiplier, this->OperationModeEMSOverrideValue); - this->companionHeatPumpCoil->operatingMode = 0; + companionCoil.operatingMode = 0; } } else if (this->operatingModeControlMethod == OperatingModeControlMethod::ScheduledModes) { auto numUnitsOn = static_cast(this->operationModeControlSche->getCurrentVal()); if (numUnitsOn > 0) { this->operatingMode = min(this->heatPumpMultiplier, numUnitsOn); - this->companionHeatPumpCoil->operatingMode = 0; + companionCoil.operatingMode = 0; } else { this->operatingMode = 0; - this->companionHeatPumpCoil->operatingMode = min(this->companionHeatPumpCoil->heatPumpMultiplier, -numUnitsOn); + companionCoil.operatingMode = min(companionCoil.heatPumpMultiplier, -numUnitsOn); } } else { if (modeCalcMethod == OperatingModeControlOptionMultipleUnit::SingleMode) { // all HP unit either all in heating or all in cooling mode if (fabs(currentLoad) < fabs(companionLoad)) { this->operatingMode = 0; - this->companionHeatPumpCoil->operatingMode = ceil(fabs(companionLoad) / companionAvailableCapacityOneUnit); + companionCoil.operatingMode = ceil(fabs(companionLoad) / companionAvailableCapacityOneUnit); } else { this->operatingMode = ceil(fabs(currentLoad) / availableCapacityOneUnit); - this->companionHeatPumpCoil->operatingMode = 0; + companionCoil.operatingMode = 0; } } else { Real64 coolingLoad = 0.0; @@ -4696,20 +4699,20 @@ void HeatPumpAirToWater::calcOpMode(EnergyPlus::EnergyPlusData &state, Real64 cu } if (this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpAirToWaterHeating) { this->operatingMode = numHeatingUnit; - this->companionHeatPumpCoil->operatingMode = numCoolingUnit; + companionCoil.operatingMode = numCoolingUnit; } else { this->operatingMode = numCoolingUnit; - this->companionHeatPumpCoil->operatingMode = numHeatingUnit; + companionCoil.operatingMode = numHeatingUnit; } } this->operatingMode = min(this->heatPumpMultiplier, this->operatingMode); - companionCoil->operatingMode = min(companionCoil->heatPumpMultiplier, companionCoil->operatingMode); - if (this->companionHeatPumpCoil->operatingMode == 0) { - this->companionHeatPumpCoil->loadSideHeatTransfer = 0.0; - this->companionHeatPumpCoil->sourceSideHeatTransfer = 0.0; - this->companionHeatPumpCoil->loadSideMassFlowRate = 0.0; - this->companionHeatPumpCoil->sourceSideMassFlowRate = 0.0; - this->companionHeatPumpCoil->speedLevel = 0.0; + companionCoil.operatingMode = min(companionCoil.heatPumpMultiplier, companionCoil.operatingMode); + if (companionCoil.operatingMode == 0) { + companionCoil.loadSideHeatTransfer = 0.0; + companionCoil.sourceSideHeatTransfer = 0.0; + companionCoil.loadSideMassFlowRate = 0.0; + companionCoil.sourceSideMassFlowRate = 0.0; + companionCoil.speedLevel = 0.0; } } } diff --git a/src/EnergyPlus/PlantLoopHeatPumpEIR.hh b/src/EnergyPlus/PlantLoopHeatPumpEIR.hh index 747a1b7fe86..b438c9b542c 100644 --- a/src/EnergyPlus/PlantLoopHeatPumpEIR.hh +++ b/src/EnergyPlus/PlantLoopHeatPumpEIR.hh @@ -459,7 +459,11 @@ namespace EIRPlantLoopHeatPumps { }; // additional variables - HeatPumpAirToWater *companionHeatPumpCoil = nullptr; + // Base has EIRPlantLoopHeatPump *companionHeatPumpCoil = nullptr; + // In a our casz we KNOW it's a HeatPumpAirToWater because we assign in pairUpCompanionCoils, + // so we can safely static_cast when needed (in calcOpMode) + // HeatPumpAirToWater *companionHeatPumpCoil = nullptr; + std::string availSchedName; // availability schedule Sched::Schedule *availSched = nullptr; // availability schedule OperatingModeControlMethod operatingModeControlMethod = OperatingModeControlMethod::Load; From 77e7c35bae03568f3ed5844750c1b00c74051542 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 16:37:37 +0200 Subject: [PATCH 13/15] Error on Wshadow-field now --- cmake/CompilerFlags.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index 4e06bd661d0..c47e2f92327 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -134,7 +134,6 @@ elseif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" O target_compile_options(project_fp_options INTERFACE -ffp-contract=off) # Disable fused-floating point operations (default is fast) elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") target_compile_options(project_warnings INTERFACE -Wshadow-field) # Equivalent to MSVC's C4458 (declaration of 'identifier' hides class member); narrower than -Wshadow - target_compile_options(project_warnings INTERFACE -Wno-error=shadow-field) # TODO: temporarily non-fatal to collect all instances before fixing if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0) # Suppress unused-but-set warnings until more serious ones are addressed target_compile_options(project_warnings INTERFACE -Wno-unused-but-set-parameter -Wno-unused-but-set-variable) From a9bfd7a67da6a5d08e2d8a751b8661eae671e9e8 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 17:19:11 +0200 Subject: [PATCH 14/15] EnergyPlusFixture functions shouldn't take EnergyPlusData& state when there's a EnergyPlusData* state member --- .../unit/ChillerElectricEIR.unit.cc | 1 - .../unit/Fixtures/EnergyPlusFixture.cc | 26 +++++++++---------- .../unit/Fixtures/EnergyPlusFixture.hh | 6 ++--- tst/EnergyPlus/unit/api/datatransfer.unit.cc | 6 ++--- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/tst/EnergyPlus/unit/ChillerElectricEIR.unit.cc b/tst/EnergyPlus/unit/ChillerElectricEIR.unit.cc index d232017fda6..6626f05bc86 100644 --- a/tst/EnergyPlus/unit/ChillerElectricEIR.unit.cc +++ b/tst/EnergyPlus/unit/ChillerElectricEIR.unit.cc @@ -522,7 +522,6 @@ TEST_F(EnergyPlusFixture, ChillerElectricEIR_EvaporativelyCooled_Calculate) // set load and run flag bool RunFlag(true); Real64 MyLoad(-18000.0); - openOutputFiles(*state); state->dataPlnt->PlantLoop(1).LoopDemandCalcScheme = DataPlant::LoopDemandCalcScheme::SingleSetPoint; state->dataLoopNodes->Node(thisEIRChiller.EvapOutletNodeNum).TempSetPoint = 6.67; diff --git a/tst/EnergyPlus/unit/Fixtures/EnergyPlusFixture.cc b/tst/EnergyPlus/unit/Fixtures/EnergyPlusFixture.cc index 48eb890a8b5..8752b296443 100644 --- a/tst/EnergyPlus/unit/Fixtures/EnergyPlusFixture.cc +++ b/tst/EnergyPlus/unit/Fixtures/EnergyPlusFixture.cc @@ -79,19 +79,19 @@ namespace EnergyPlus { // state->dataInputProcessing->inputProcessor = InputProcessor::factory(); //} -void EnergyPlusFixture::openOutputFiles(EnergyPlusData &t_state) +void EnergyPlusFixture::openOutputFiles() { - t_state.files.eio.open_as_stringstream(); - t_state.files.mtr.open_as_stringstream(); - t_state.files.eso.open_as_stringstream(); - t_state.files.audit.open_as_stringstream(); - t_state.files.bnd.open_as_stringstream(); - t_state.files.debug.open_as_stringstream(); - t_state.files.mtd.open_as_stringstream(); - t_state.files.edd.open_as_stringstream(); - t_state.files.zsz.open_as_stringstream(); - t_state.files.spsz.open_as_stringstream(); - t_state.files.ssz.open_as_stringstream(); + this->state->files.eio.open_as_stringstream(); + this->state->files.mtr.open_as_stringstream(); + this->state->files.eso.open_as_stringstream(); + this->state->files.audit.open_as_stringstream(); + this->state->files.bnd.open_as_stringstream(); + this->state->files.debug.open_as_stringstream(); + this->state->files.mtd.open_as_stringstream(); + this->state->files.edd.open_as_stringstream(); + this->state->files.zsz.open_as_stringstream(); + this->state->files.spsz.open_as_stringstream(); + this->state->files.ssz.open_as_stringstream(); } void EnergyPlusFixture::SetUp() @@ -104,7 +104,7 @@ void EnergyPlusFixture::SetUp() show_message(); - openOutputFiles(*state); + openOutputFiles(); this->err_stream = new std::ostringstream; diff --git a/tst/EnergyPlus/unit/Fixtures/EnergyPlusFixture.hh b/tst/EnergyPlus/unit/Fixtures/EnergyPlusFixture.hh index c48653e6932..c22f7714dd0 100644 --- a/tst/EnergyPlus/unit/Fixtures/EnergyPlusFixture.hh +++ b/tst/EnergyPlus/unit/Fixtures/EnergyPlusFixture.hh @@ -273,9 +273,6 @@ protected: bool process_json(nlohmann::json const &epJSON, bool use_assertions = true); - // Opens output files as stringstreams - void openOutputFiles(EnergyPlusData &t_state); - // A worker function that keeps trailing spaces in multiline raw string literals void replace_pipes_with_spaces(std::string &stringLiteral) { @@ -296,6 +293,9 @@ public: EnergyPlusData *state; private: + // Opens output files as stringstreams + void openOutputFiles(); + bool common_process_json(bool use_assertions); friend class InputProcessorFixture; diff --git a/tst/EnergyPlus/unit/api/datatransfer.unit.cc b/tst/EnergyPlus/unit/api/datatransfer.unit.cc index f1b00a1c0ff..a81203422ea 100644 --- a/tst/EnergyPlus/unit/api/datatransfer.unit.cc +++ b/tst/EnergyPlus/unit/api/datatransfer.unit.cc @@ -256,9 +256,9 @@ class DataExchangeAPIUnitTestFixture : public EnergyPlusFixture } } - static void addPluginGlobal(EnergyPlus::EnergyPlusData &state, std::string const &varName) + void addPluginGlobal(std::string const &varName) { - state.dataPluginManager->pluginManager->addGlobalVariable(state, varName); + this->state->dataPluginManager->pluginManager->addGlobalVariable(*this->state, varName); } void addTrendWithNewGlobal(std::string const &newGlobalVarName, std::string const &trendName, int numTrendValues) const @@ -294,7 +294,7 @@ TEST_F(DataExchangeAPIUnitTestFixture, DataTransfer_TestListAllDataInCSV) this->setupActuatorsOnceAllAreRequested(); this->preRequestInternalVariable("Floor Area", "Zone 1", 6.02e23); this->setupInternalVariablesOnceAllAreRequested(); - this->addPluginGlobal(*state, "Plugin_Global_Var_Name"); + this->addPluginGlobal("Plugin_Global_Var_Name"); this->addTrendWithNewGlobal("NewGlobalVarHere", "Trend 1", 3); char *charCsvDataFull = listAllAPIDataCSV((void *)this->state); std::string csvData = std::string(charCsvDataFull); From ae83cceaf9dd2d42df8e1d50828c8d9e3c65f49c Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 7 Jul 2026 18:00:22 +0200 Subject: [PATCH 15/15] Avoid a regression in HeatPumpAirToWater, but I think there are bugs in there Fix regression in HeatPumpAirToWater sizing from companionHeatPumpCoil rename The Wshadow-field fix in 4f15f0b9c28bb8e4469e03baca80107ea6368cd6 removed HeatPumpAirToWater's own `companionHeatPumpCoil` shadow member and had its pairUpCompanionCoils() assign into the base EIRPlantLoopHeatPump::companionHeatPumpCoil instead. That member is also read by EIRPlantLoopHeatPump::sizeLoadSide() (and other base sizing methods), whose companion-based sizing branch was written for, and only type-checks against, the plain PlantLoopHeatPump:EIR Heating/Cooling pair (DataPlant::PlantEquipmentType::HeatPumpEIRHeating/Cooling) -- it was never adapted for HeatPumpAirToWater. Before the rename, this branch was structurally unreachable for AWHP objects (the base member always stayed null for them); after the rename it started firing, changing autosized "Rated Water Volume Flow Rate in Heating Mode" for PlantLoopHeatPump_EIR_AirSource_and_AWHP.eio from 0.005 to 0.018 m3/s. Fixing it: Restore a separate, non-shadowing member (companionAWHPCoil) used only by `HeatPumpAirToWater::pairUpCompanionCoils()`/`calcOpMode()`, leaving the base member's null-for-AWHP behavior intact, matching pre-fix sizing results. Needs further investigation (separate, pre-existing issue, not caused by this branch). `HeatPumpAirToWater::sizeLoadSide()` is not virtual, and its only would-be caller (EIRPlantLoopHeatPump::onInitLoopEquip) invokes `this->sizeLoadSide(state)` from within the base class's own scope, so that call always statically resolves to `EIRPlantLoopHeatPump::sizeLoadSide`, never the derived override. Confirmed no production or test code calls `sizeLoadSide()` through a HeatPumpAirToWater*-typed pointer either, so `HeatPumpAirToWater::sizeLoadSide()` (and its referenceCapacityOneUnit recompute) is effictively dead code today. Left a TODO comment at the definition; This likely needs a real fix (e.g. making sizeLoadSide virtual, or overriding onInitLoopEquip in HeatPumpAirToWater) but that's a behavior (and diff-producing) change out of scope for this PR. --- src/EnergyPlus/PlantLoopHeatPumpEIR.cc | 21 +++++++++++-------- src/EnergyPlus/PlantLoopHeatPumpEIR.hh | 11 ++++++---- .../unit/PlantLoopHeatPumpEIR.unit.cc | 4 ++-- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/EnergyPlus/PlantLoopHeatPumpEIR.cc b/src/EnergyPlus/PlantLoopHeatPumpEIR.cc index 2e683b767e6..1c26c10a3a9 100644 --- a/src/EnergyPlus/PlantLoopHeatPumpEIR.cc +++ b/src/EnergyPlus/PlantLoopHeatPumpEIR.cc @@ -2835,6 +2835,10 @@ void HeatPumpAirToWater::oneTimeInit(EnergyPlusData &state) this->oneTimeInitFlagAWHP = false; } +// TODO: sizeLoadSide() is not virtual, and the only production call site (EIRPlantLoopHeatPump::onInitLoopEquip, +// via `this->sizeLoadSide(state);`) is compiled in the base class's own scope, so it always statically resolves to +// EIRPlantLoopHeatPump::sizeLoadSide. This override is therefore unreachable dead code today; the +// referenceCapacityOneUnit recompute below never runs. Pre-existing issue, unrelated to the Wshadow-field cleanup. void HeatPumpAirToWater::sizeLoadSide(EnergyPlusData &state) { EIRPlantLoopHeatPump::sizeLoadSide(state); @@ -3351,7 +3355,7 @@ void HeatPumpAirToWater::pairUpCompanionCoils(EnergyPlusData &state) std::string potentialCompanionName = Util::makeUPPER(potentialCompanionCoil.name); if (potentialCompanionName == targetCompanionName) { if (thisCoilType != potentialCompanionType) { - thisHP.companionHeatPumpCoil = &potentialCompanionCoil; + thisHP.companionAWHPCoil = &potentialCompanionCoil; break; } } @@ -4545,7 +4549,7 @@ Real64 EIRFuelFiredHeatPump::getDynamicMaxCapacity(EnergyPlusData &state) void HeatPumpAirToWater::calcOpMode(EnergyPlus::EnergyPlusData &state, Real64 currentLoad, OperatingModeControlOptionMultipleUnit modeCalcMethod) { - if (this->companionHeatPumpCoil == nullptr) { + if (this->companionAWHPCoil == nullptr) { this->operatingMode = 1; if (this->OperationModeEMSOverrideOn) { auto curveIndex = this->capFuncTempCurveIndices[this->numSpeeds - 1]; @@ -4559,10 +4563,12 @@ void HeatPumpAirToWater::calcOpMode(EnergyPlus::EnergyPlusData &state, Real64 cu } } } else { - auto LoopNum = this->companionHeatPumpCoil->loadSidePlantLoc.loopNum; - auto LoopSideNum = this->companionHeatPumpCoil->loadSidePlantLoc.loopSideNum; - auto BranchNum = this->companionHeatPumpCoil->loadSidePlantLoc.branchNum; - auto CompNum = this->companionHeatPumpCoil->loadSidePlantLoc.compNum; + auto &companionCoil = *this->companionAWHPCoil; + + auto LoopNum = companionCoil.loadSidePlantLoc.loopNum; + auto LoopSideNum = companionCoil.loadSidePlantLoc.loopSideNum; + auto BranchNum = companionCoil.loadSidePlantLoc.branchNum; + auto CompNum = companionCoil.loadSidePlantLoc.compNum; auto &this_loop(state.dataPlnt->PlantLoop(LoopNum)); auto &this_loop_side(this_loop.LoopSide(LoopSideNum)); auto &this_component = this_loop_side.Branch(BranchNum).Comp(CompNum); @@ -4571,9 +4577,6 @@ void HeatPumpAirToWater::calcOpMode(EnergyPlus::EnergyPlusData &state, Real64 cu auto capacityModifierFuncTemp = Curve::CurveValue(state, curveIndex, this->loadSideOutletTemp, this->sourceSideInletTemp); auto availableCapacityOneUnit = this->referenceCapacityOneUnit * capacityModifierFuncTemp; - // This is safe because we know companionHeatPumpCoil is a HeatPumpAirToWater, so we can static_cast it - auto &companionCoil = static_cast(*this->companionHeatPumpCoil); - auto companionCapacityModifierFuncTemp = Curve::CurveValue(state, curveIndex, companionCoil.loadSideOutletTemp, companionCoil.sourceSideInletTemp); auto companionAvailableCapacityOneUnit = companionCoil.referenceCapacityOneUnit * companionCapacityModifierFuncTemp; diff --git a/src/EnergyPlus/PlantLoopHeatPumpEIR.hh b/src/EnergyPlus/PlantLoopHeatPumpEIR.hh index b438c9b542c..a11d62ca942 100644 --- a/src/EnergyPlus/PlantLoopHeatPumpEIR.hh +++ b/src/EnergyPlus/PlantLoopHeatPumpEIR.hh @@ -459,10 +459,13 @@ namespace EIRPlantLoopHeatPumps { }; // additional variables - // Base has EIRPlantLoopHeatPump *companionHeatPumpCoil = nullptr; - // In a our casz we KNOW it's a HeatPumpAirToWater because we assign in pairUpCompanionCoils, - // so we can safely static_cast when needed (in calcOpMode) - // HeatPumpAirToWater *companionHeatPumpCoil = nullptr; + // Deliberately NOT named companionHeatPumpCoil: the base class's own EIRPlantLoopHeatPump::companionHeatPumpCoil + // must stay null for HeatPumpAirToWater objects, because EIRPlantLoopHeatPump::sizeLoadSide() (and other base + // sizing methods) branch on it being non-null to size off a companion coil using logic that was written for, + // and only checks for, the plain PlantLoopHeatPump:EIR:Heating/Cooling pair (DataPlant::PlantEquipmentType:: + // HeatPumpEIRHeating/Cooling), not HeatPumpAirToWater. This member is used instead by + // HeatPumpAirToWater::pairUpCompanionCoils() and HeatPumpAirToWater::calcOpMode(). + HeatPumpAirToWater *companionAWHPCoil = nullptr; std::string availSchedName; // availability schedule Sched::Schedule *availSched = nullptr; // availability schedule diff --git a/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc b/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc index 8a06466a06c..72e5de12a6a 100644 --- a/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc +++ b/tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc @@ -1384,8 +1384,8 @@ TEST_F(EnergyPlusFixture, calcOpMode_AWHP) state->init_state(*state); auto thisAWHP = HeatPumpAirToWater(); auto companionAWHP = HeatPumpAirToWater(); - thisAWHP.companionHeatPumpCoil = &companionAWHP; - companionAWHP.companionHeatPumpCoil = &thisAWHP; + thisAWHP.companionAWHPCoil = &companionAWHP; + companionAWHP.companionAWHPCoil = &thisAWHP; thisAWHP.heatPumpMultiplier = 6; companionAWHP.heatPumpMultiplier = 6; thisAWHP.referenceCapacityOneUnit = 100;