Skip to content

V26.2.0-IOFreeze: new ZoneMRTCalculation object - #5649

Open
joseph-robertson wants to merge 27 commits into
developfrom
v26.2.0-IOFreeze-ZoneMRTCalc
Open

V26.2.0-IOFreeze: new ZoneMRTCalculation object#5649
joseph-robertson wants to merge 27 commits into
developfrom
v26.2.0-IOFreeze-ZoneMRTCalc

Conversation

@joseph-robertson

@joseph-robertson joseph-robertson commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Pull request overview

Pull Request Author

  • Model API Changes / Additions
  • Any new or modified fields have been implemented in the EnergyPlus ForwardTranslator (and ReverseTranslator as appropriate)
  • Model API methods are tested (in src/model/test)
  • EnergyPlus ForwardTranslator Tests (in src/energyplus/Test)
  • If a new object or method, added a test in NREL/OpenStudio-resources: Wrap ZoneMRTCalculation OpenStudio-resources#232
  • If needed, added VersionTranslation rules for the objects (src/osversion/VersionTranslator.cpp)
  • Verified that C# bindings built fine on Windows, partial classes used as needed, etc.
  • All new and existing tests passes
  • If methods have been deprecated, update rest of code to use the new methods

Labels:

  • If change to an IDD file, add the label IDDChange
  • If breaking existing API, add the label APIChange
  • If deemed ready, add label Pull Request - Ready for CI so that CI builds your PR

Review Checklist

This will not be exhaustively relevant to every PR.

  • Perform a Code Review on GitHub
  • Code Style, strip trailing whitespace, etc.
  • All related changes have been implemented: model changes, model tests, FT changes, FT tests, VersionTranslation, OS App
  • Labeling is ok
  • If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
  • If feature, test running new feature, try creative ways to break it
  • CI status: all green or justified

@joseph-robertson joseph-robertson self-assigned this Sep 1, 2026
@joseph-robertson joseph-robertson added Pull Request - Ready for CI This pull request if finalized and is ready for continuous integration verification prior to merge. IDDChange labels Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Results Dashboard

Summary

Metric Value
Total Tests 0
Passed 0
Failed 0
Errors 0
Skipped 0
Success Rate 0.0%
Generated 2026-09-08 10:45:47 UTC

❌ Significant Test Failures

📊 Test Run Information

Run XML File Status
- No XML files found ❌ Missing

@joseph-robertson
joseph-robertson requested a balanced review from Copilot September 1, 2026 22:20
@joseph-robertson
joseph-robertson marked this pull request as ready for review September 1, 2026 22:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Weight-sum validation, stale references, non-finite values, and partial-add failure reporting can currently produce invalid behavior.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds Model API and EnergyPlus translation support for ZoneMRTCalculation.

Changes:

  • Adds the model object, MRT weighting-factor API, and ThermalZone integration.
  • Adds forward/reverse translators and binding support.
  • Updates IDDs, build registration, and tests.
File summaries
File Description
src/model/ZoneMRTCalculation.hpp Declares the new API.
src/model/ZoneMRTCalculation.cpp Implements weighting-factor behavior.
src/model/ZoneMRTCalculation_Impl.hpp Declares implementation details.
src/model/ThermalZone.hpp Exposes MRT calculation access.
src/model/ThermalZone.cpp Implements creation and lookup.
src/model/ThermalZone_Impl.hpp Adds implementation declaration.
src/model/test/ZoneMRTCalculation_GTest.cpp Tests the model API.
src/model/ModelHVAC.i Adds C# ThermalZone access.
src/model/ModelGeometry.i Registers binding templates.
src/model/Model.cpp Registers constructors.
src/model/ConcreteModelObjects.hpp Includes the new object.
src/model/CMakeLists.txt Adds model sources and tests.
src/energyplus/Test/ZoneMRTCalculation_GTest.cpp Tests both translators.
src/energyplus/ReverseTranslator/ReverseTranslateZoneMRTCalculation.cpp Implements reverse translation.
src/energyplus/ReverseTranslator.hpp Declares reverse translation.
src/energyplus/ReverseTranslator.cpp Dispatches reverse translation.
src/energyplus/ForwardTranslator/ForwardTranslateZoneMRTCalculation.cpp Implements forward translation.
src/energyplus/ForwardTranslator.hpp Declares forward translation.
src/energyplus/ForwardTranslator.cpp Registers forward translation.
src/energyplus/CMakeLists.txt Adds translator sources and tests.
resources/model/OpenStudio.idd Defines the OpenStudio object.
resources/energyplus/ProposedEnergy+.idd Converts EnergyPlus fields to extensible groups.
Review details

Suppressed comments (1)

src/model/ZoneMRTCalculation.cpp:107

  • Removing a referenced People object clears this pointer but leaves the extensible group. A subsequent call to addMRTWeightingFactor reaches this predicate and calls .get() on an empty optional, throwing instead of adding the new factor. Treat a missing field as a non-match (and add a removal regression test).
      auto it = std::find_if(egs.begin(), egs.end(), [&](const WorkspaceExtensibleGroup& eg) {
        return eg.getField(OS_ZoneMRTCalculationExtensibleFields::PeopleName).get() == peopleHandle;
      });
  • Files reviewed: 22/22 changed files
  • Comments generated: 4
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/energyplus/ForwardTranslator/ForwardTranslateZoneMRTCalculation.cpp Outdated
Comment thread src/model/ZoneMRTCalculation.cpp Outdated
Comment thread src/model/ZoneMRTCalculation.cpp Outdated
Comment thread src/model/ZoneMRTCalculation.cpp Outdated
Comment thread src/model/People.cpp Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Thermal-zone deletion can leave an invalid ZoneMRTCalculation object that later causes assertions during access or translation.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

resources/model/OpenStudio.idd:6830

  • This field declares two conflicting \type values; all other OpenStudio object-list fields use only \type object-list (for example, lines 6808-6809 and 6837-6838). Remove the redundant alpha declaration so the IDD metadata has one unambiguous field type.
    src/model/ZoneMRTCalculation.cpp:85
  • These adjacent string literals concatenate as andthat, making the thrown clone error malformed. Preserve a space at the literal boundary.
  • Files reviewed: 25/25 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread src/model/ThermalZone.cpp
Comment on lines +2655 to +2658
ZoneMRTCalculation ThermalZone_Impl::getZoneMRTCalculation() const {
auto thisThermalZone = getObject<ThermalZone>();
std::vector<ZoneMRTCalculation> zoneMRTCalculations =
thisThermalZone.getModelObjectSources<ZoneMRTCalculation>(ZoneMRTCalculation::iddObjectType());

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'd have the same issue when deleting a Space.

Removing a Space bulk-removes its child People through ParentObject_Impl::remove(), but it does not call People_Impl::remove(). So cleanup would require Space_Impl::remove() to inspect all child People, then find and prune any ZoneMRTCalculation groups for each one. That reaches across more ownership boundaries and is less consistent with the existing bulk child-removal mechanism.

So: zone removal is direct source-object cleanup; space removal is indirect child/reference cleanup.

@joseph-robertson joseph-robertson Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This handles ThermalZone: 435380b

@jmarrec jmarrec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking pretty good. A couple of things to change in the code review

And please fill out the PR checklist, most important item of it: we need a OpenStudio-resources matching test for this new object

Comment thread resources/energyplus/ProposedEnergy+.idd
Comment on lines +6839 to +6842
\note A People object assigned directly to a Space retains its input name.
\note A People object expanded across multiple Spaces must use an expanded instance name
\note formed as "<Space Name> <People Name>"; its original input name is not accepted.
\note People instances in automatically generated remainder Spaces are not supported.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That scares me

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, not totally sure what to do here. If the model has People object that references a SpaceType (instead of a Space), then the IDF's People object references a SpaceList. So I think we'd want to support this (somehow), and the resulting IDF's ZoneMRTCalculation object would look something like (?)

ZoneMRTCalculation,
[...]
  Story 1 East Perimeter Space Baseline Model People, !- People 1 Name
  0.25,                                               !- MRT Weighting Factor 1
  Story 1 West Perimeter Space Baseline Model People, !- People 2 Name
  0.75,                                               !- MRT Weighting Factor 2

@jmarrec jmarrec Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your current implementation which enforces things at model time plus FT time is fine
More importantly this is going to be a very niche object, so if you choose to use it you can also deal with the preconditions.
For eg I don't think we need to check is assigned to a spaceType and the sp has only one space

Comment thread src/model/ZoneMRTCalculation.hpp Outdated
Comment thread src/model/ZoneMRTCalculation.hpp Outdated
Comment thread src/model/test/ZoneMRTCalculation_GTest.cpp Outdated
Comment thread src/model/ZoneMRTCalculation.cpp
Comment thread src/energyplus/ForwardTranslator/ForwardTranslateZoneMRTCalculation.cpp Outdated
Comment thread src/energyplus/ForwardTranslator/ForwardTranslateZoneMRTCalculation.cpp Outdated
Comment thread src/energyplus/ForwardTranslator/ForwardTranslateZoneMRTCalculation.cpp Outdated
Comment thread src/model/ZoneMRTCalculation.hpp Outdated
Comment on lines +81 to +97
std::vector<MRTWeightingFactor> mrtWeightingFactors() const;

unsigned int numberofMRTWeightingFactors() const;

boost::optional<unsigned> mrtWeightingFactorIndex(const People& people) const;

boost::optional<MRTWeightingFactor> getMRTWeightingFactor(unsigned groupIndex) const;

bool addMRTWeightingFactor(const MRTWeightingFactor& mrtWeightingFactor);

bool addMRTWeightingFactor(const People& people, double mrtWeightingFactor);

bool addMRTWeightingFactors(const std::vector<MRTWeightingFactor>& mrtWeightingFactors);

void removeMRTWeightingFactor(int groupIndex);

void removeAllMRTWeightingFactors();

@jmarrec jmarrec Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MRT is an accronym.

You use mrtW and MRTW here, which is an unusual way of casing.

I know mRTWeightingFactor looks weirdish, but that's the camelCase convention we're using everywhere else.

I actually rely on it sometimes when doing dynamic programming...

I suggest either:

  • changing
  • or motivating it by looking at how we handled other IDD fields with acronyms.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked Claude to look into it

In the codebase, when an acronym leads a lowerCamelCase identifier (getter/local var, not prefixed by get/set/add), the established pattern only lowercases the first letter of the acronym, e.g.:

  • dXCoil, dXHeatingCoilSizingRatio (from IDD field DX...)
  • eMSVariableName, eMSRuntimeLanguageDebugOutputLevel (from EMS...)
  • fMUFile, fMUFileName, fMUVariableName (from FMU...)
  • vFDControlType, vFDEfficiencyCurve (from VFD...)
  • fCAH, fCAuxHeat, fCStorage (from FC..., Generator:FuelCell fields)

That's 49 distinct identifiers following this rule, vs. only 3 outliers (copFunctionofTemperatureCurve and friends, which fully lowercase COP) — likely older/manually-typed exceptions rather than the intended convention. So the dominant, established rule is: lowercase only the leading letter of the acronym, keep the rest capitalized — exactly the mRTWeightingFactor you described.

ZoneMRTCalculation currently uses mrtWeightingFactor/mrtWeightingFactors/mrtWeightingFactorIndex (member functions, local vars, and the private member m_mrtWeightingFactor), which breaks that convention. The class name MRTWeightingFactor itself and the prefixed methods (addMRTWeightingFactor, getMRTWeightingFactor, numberofMRTWeightingFactors, removeMRTWeightingFactor) are already correctly cased and don't need touching — only the un-prefixed lowerCamelCase spots do.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 18cb9ea

Comment on lines +24 to +37
/** This class implements an MRT weighting factor. */
class MODEL_API MRTWeightingFactor
{
public:
MRTWeightingFactor(const People& people, double mrtWeightingFactor);

People people() const;
double mrtWeightingFactor() const;

private:
People m_people;
double m_mrtWeightingFactor;
REGISTER_LOGGER("openstudio.model.MRTWeightingFactor");
};

@jmarrec jmarrec Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add an equality operator?

If so, do we compare People only? (a people can only be listed once...)
Or on both People and factor? (which is semantically more correct/expected)

🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an operator== that compares on People AND factor. be24456

Comment thread src/model/ZoneMRTCalculation.cpp Outdated
Comment on lines +236 to +240
if (sum > 1.0) {
LOG(Error, "Cannot add " << people.briefDescription() << " to " << briefDescription() << " because the MRT Weighting Factors would sum to "
<< sum << ", which is greater than 1.");
return result;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AH! While modifying the OpenStudio-resources tests to be more comprehensive, I got bit by this floating point comparison. We need a tolerance.

https://github.com/NatLabRockies/EnergyPlus/blob/5b898844e92b3718ab91b858c77eaf8782eb56b6/src/EnergyPlus/HeatBalanceManager.cc#L2468-L2473

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/model/People.cpp Outdated
Comment thread src/model/ModelGeometry.i
MODELOBJECT_TEMPLATES(SurfacePropertyExposedFoundationPerimeter);
MODELOBJECT_TEMPLATES(ViewFactor); // Helper class defined in ZonePropertyUserViewFactorsBySurfaceName
MODELOBJECT_TEMPLATES(ZonePropertyUserViewFactorsBySurfaceName);
MODELOBJECT_TEMPLATES(MRTWeightingFactor); // Helper class defined in ZoneMRTCalculation

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have defined operator<< for that class, you need to extend str so Ruby/Python see it

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmarrec
jmarrec force-pushed the v26.2.0-IOFreeze-ZoneMRTCalc branch from 723ae70 to ed3042d Compare September 8, 2026 10:19
@jmarrec

jmarrec commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

@joseph-robertson I have updated the PR as well as the OpenStudio-resources test at NatLabRockies/OpenStudio-resources#232

Unfortunately the Ubuntu runners have a Github CLI EXPKEYSIG (I got it locally on Ubuntu 24.04 too), so we can have CI run the OS resources test with the deb installer from this PR, but I built locally and confirmed everything works fine.

Can you take a quick pass at my changes? Then we can drop both. Thank you.

@jmarrec
jmarrec self-requested a review September 8, 2026 13:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

IDDChange Pull Request - Ready for CI This pull request if finalized and is ready for continuous integration verification prior to merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants