Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Feature Runaround Heat Recovery Loop #8520

Merged
merged 23 commits into from
Aug 19, 2021

Conversation

rraustad
Copy link
Contributor

@rraustad rraustad commented Feb 8, 2021

Pull request overview

  • New Feature to use water coils to transfer energy between air streams
  • Two water coils in a closed loop transfer energy between air streams.

Fixes #8966 through code clean up.

NOTE: ENHANCEMENTS MUST FOLLOW A SUBMISSION PROCESS INCLUDING A FEATURE PROPOSAL AND DESIGN DOCUMENT PRIOR TO SUBMITTING CODE

Pull Request Author

Add to this list or remove from it as applicable. This is a simple templated set of guidelines.

  • Title of PR should be user-synopsis style (clearly understandable in a standalone changelog context)
  • Label the PR with at least one of: Defect, Refactoring, NewFeature, Performance, and/or DoNoPublish
  • Pull requests that impact EnergyPlus code must also include unit tests to cover enhancement or defect repair
  • Author should provide a "walkthrough" of relevant code changes using a GitHub code review comment process
  • If any diffs are expected, author must demonstrate they are justified using plots and descriptions
  • [ ] If changes fix a defect, the fix should be demonstrated in plots and descriptions
  • [ ] If any defect files are updated to a more recent version, upload new versions here or on DevSupport
  • If IDD requires transition, transition source, rules, ExpandObjects, and IDFs must be updated, and add IDDChange label
  • [ ] If structural output changes, add to output rules file and add OutputChange label
  • If adding/removing any LaTeX docs or figures, update that document's CMakeLists file dependencies

Reviewer

This will not be exhaustively relevant to every PR.

  • Perform a Code Review on GitHub
  • If branch is behind develop, merge develop and build locally to check for side effects of the merge
  • 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
  • Check that performance is not impacted (CI Linux results include performance check)
  • Run Unit Test(s) locally
  • Check any new function arguments for performance impacts
  • Verify IDF naming conventions and styles, memos and notes and defaults
  • If new idf included, locally check the err file and other outputs

@rraustad rraustad added the NewFeature Includes code to add a new feature to EnergyPlus label Feb 8, 2021
@rraustad rraustad added this to the EnergyPlus Future milestone Feb 8, 2021
@rraustad rraustad self-assigned this Feb 8, 2021
1. Connect 2 water cooling coils in a typical plant configuration. With one coil on the demand side of the plant loop while the other is a supply side component. This would allow alternate configurations if desired. For example to allow a boiler, chiller, evap cooler, etc. on the supply side which maintains a certain temperature to the supply side coil. Although I can't think of a reason to do this, it seems like a very flexible way to achieve the goal for a run-around coil application. A user could create a plant loop and then add two coils and a pump.

**Pro:** This approach may require minimal changes to the IDD (the PlantLoop field for Plant Equipment Operation Scheme Name is required). Would provide flexibility in configuration. Pipe losses could be modeled.
**Con:** The coil model would use ControlcompOutput as the solution algorithm. The air-side and water-side calculations would be disassociated the same as water coils on a branch are currently modeled.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why would it need to use ControlCompOutput? Seems like a versatile coil controller that can switch between heating and cooling is the main thing to do here and it could use root solver.

Plant loop approach can also provide autosizing, support for different glycol mixtures, different pumping arrangements, pump heat to fluid modeling, and ability to combine multiple air handlers.

![RunaroundCoilLoop](RunaroundCoilHXLoop.png)
## *Figure 1. Run around coil loop schematic.* ##

Figure 2 shows an example run-around coil design for winter and summer operation. During the heating season (Inset A), heat extracted from the exhaust air stream (EA)
Copy link
Contributor

Choose a reason for hiding this comment

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

Exhaust air stream is interesting. If there is scope would be interesting to be able to put a coil in the outlet of each zone exhaust fan.

Copy link
Contributor

Choose a reason for hiding this comment

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

I have a related new feature task for "Dedicated Airstreams to Model General Exhaust Fans" so it should be possible to design that to work with this.

**Pro:** This approach may require minimal changes to the IDD (the PlantLoop field for Plant Equipment Operation Scheme Name is required). Would provide flexibility in configuration. Pipe losses could be modeled.
**Con:** The coil model would use ControlcompOutput as the solution algorithm. The air-side and water-side calculations would be disassociated the same as water coils on a branch are currently modeled.

I'm not yet sure if objects other than the PlantLoop are even needed for a loop with 2 coils and a pump. Without a plant component (e.g., boiler or chiller) would the other typical plant objects shown here even be needed?
Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect some kind of operation scheme will be needed, probably Uncontrolled or ComponentSetpoint

@nrel-bot-3
Copy link

@rraustad @lgentile it has been 28 days since this pull request was last updated.

5 similar comments
@nrel-bot
Copy link

nrel-bot commented Apr 8, 2021

@rraustad @lgentile it has been 28 days since this pull request was last updated.

@nrel-bot-3
Copy link

@rraustad @lgentile it has been 28 days since this pull request was last updated.

@nrel-bot
Copy link

nrel-bot commented Jun 3, 2021

@rraustad @lgentile it has been 28 days since this pull request was last updated.

@nrel-bot
Copy link

nrel-bot commented Jul 1, 2021

@rraustad @lgentile it has been 28 days since this pull request was last updated.

@nrel-bot-3
Copy link

@rraustad @lgentile it has been 28 days since this pull request was last updated.

@rraustad rraustad added the IDDChange Code changes impact the IDD file (cannot be merged after IO freeze) label Aug 2, 2021
@rraustad rraustad changed the title NFP runaround heat recovery loop New Feature Runaround Heat Recovery Loop Aug 4, 2021
@rraustad
Copy link
Contributor Author

rraustad commented Aug 4, 2021

I think the best performance review of this model is to compare the heat exchange of the two water coils to ensure they are equal and opposite in magnitude. The new example file, with a water cooling coil at the OA mixer's OA inlet and another at the relief air outlet, shows this characteristic over the annual simulation and also during a three week winter period. HR COOLING COIL 1 (blue) is the coil in the outdoor air stream and is heating the incoming outdoor air while the other coil is cooling the exhaust air.

image

@@ -287,9 +286,6 @@ namespace UnitarySystems {
int m_HeatRecoveryOutletNodeNum;
int m_DesignSpecMSHPIndex;
Real64 m_NoLoadAirFlowRateRatio;
Real64 m_IdleMassFlowRate;
Real64 m_IdleVolumeAirRate; // idle air flow rate [m3/s]
Real64 m_IdleSpeedRatio;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have wanted to get rid of these for a while now. When a new developer comes in they create their own new model variables instead of using existing, when the existing would work just as well. Running into the memory issue I had gave me the incentive. Idle flow rate is the same as NoLoad or NoCoolHeat variables so I just substituted and eliminated these.

@@ -195,7 +195,6 @@ namespace UnitarySystems {

UnitarySysInputSpec original_input_specs;
int m_UnitarySysNum;
int m_unitarySystemType_Num;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another variable that wasn't used anywhere.

} else {
this->enableHRLoop = false;
}
}
Copy link
Contributor Author

@rraustad rraustad Aug 4, 2021

Choose a reason for hiding this comment

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

In Init the model checks the limits and either sets temperatureOffsetControlStatus to 0 or 1.

this->m_IdleVolumeAirRate = this->m_MaxCoolAirVolFlow * state.dataUnitarySystems->designSpecMSHP[MSHPIndex].noLoadAirFlowRateRatio;
this->m_IdleMassFlowRate = this->m_IdleVolumeAirRate * state.dataEnvrn->StdRhoAir;
this->m_IdleSpeedRatio = this->m_IdleVolumeAirRate / this->m_DesignFanVolFlowRate;
if (MSHPIndex > -1) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note the change from 0 to -1 here. That was a mistake from the get go. designSpecMSHP is 0 based.

@@ -3218,7 +3252,7 @@ namespace UnitarySystems {
}

// Early calls to ATMixer don't have enough info to pass GetInput. Need to get the data next time through.
if (sysNum == -1 || !state.dataZoneEquip->ZoneEquipInputsFilled) {
if (sysNum == -1 && !state.dataZoneEquip->ZoneEquipInputsFilled) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

!state.dataZoneEquip->ZoneEquipInputsFilled means it is too early for zone equipment or maybe even air loop equipment with a control zone that needs zone node data. The old logic said to return anytime a new instance of the UnitarySystem exists when if all the data is available data gathering should continue. I think sysNum == -1 isn't even needed now but too chicken to remove it.

@@ -3521,7 +3555,7 @@ namespace UnitarySystems {
}

// check if the UnitarySystem is connected to an outside air system
if (!AirLoopFound && state.dataSize->CurOASysNum > 0) {
if (!AirLoopFound && state.dataAirLoop->NumOASystems > 0) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we are going to look through the OA system components then it does not matter if this model is called from the OA system or not, the end result is if the UnitarySystem resides there, not that it was called from there.

// set water-side economizer flag
thisSys.m_waterSideEconomizerFlag = true;

thisSys.processInputSpec(state, input_specs, sysNum, errorsFound, ZoneEquipment, ZoneOAUnitNum);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

New CoilSystem:Cooling:Water inputs are processed normally in processInputsSpec and then inputs specific to the heat recovery model are processed after this point.

@rraustad
Copy link
Contributor Author

Ah ha. In develop branch, in function setOnOffMassFlowRate, I put a break point at all the lines with MaxNoCoolHeatAirMassFlow. These break points should never get hit for this multi-speed coil file. So this coil model (Coil:Cooling:DX) is using the wrong no load condition air flow rate. I suspect that the variable m_MultiOrVarSpeedHeatCoil never got set for this new model when number of speeds > 1. Now that there is no longer m_IdleMassFlowRate variable this logic will get easier.

Coil:Cooling:DX:CurveFit:OperatingMode,
  Sys 3 Heat Pump Air Source Cooling Coil Operating Mode,  !- Name
  4,                       !- Nominal Speed Number
  Sys 3 Heat Pump Air Source Cooling Coil Speed 1 Performance,  !- Speed 1 Name
  Sys 3 Heat Pump Air Source Cooling Coil Speed 2 Performance,  !- Speed 2 Name
  Sys 3 Heat Pump Air Source Cooling Coil Speed 3 Performance,  !- Speed 3 Name
  Sys 3 Heat Pump Air Source Cooling Coil Speed 4 Performance;  !- Speed 4 Name

image

@rraustad
Copy link
Contributor Author

Example of correction to results with this branch. Sys 2 has a blank for No Load Supply Air Flow Ratio, which defaults to 1. This means the no load air flow rate should be at the maximum flow rate. In develop, the flow rate would operate at the MaxNoCoolHeatAirMassFlowRate, not the m_IdleMassFlowRate. These are the numbers from the develop branch debugger:

this->Name = Sys 2 Furnace DX Cool Unitary System
this->m_MaxNoCoolHeatAirVolFlow = 0.0637
this->m_IdleVolumeAirRate = 0.1912

UnitarySystemPerformance:Multispeed,
  Sys 2 Furnace DX Cool Unitary System MultiSpeed Performance,  !- Name
  1,                       !- Number of Speeds for Heating
  3,                       !- Number of Speeds for Cooling
  No,                      !- Single Mode Operation
  ,                        !- No Load Supply Air Flow Rate Ratio

Coil:Cooling:DX:CurveFit:OperatingMode,
  Sys 2 Furnace DX Cool Cooling Coil Operating Mode,  !- Name
  3,                       !- Nominal Speed Number
  Sys 2 Furnace DX Cool Cooling Coil Speed 1 Performance,  !- Speed 1 Name
  Sys 2 Furnace DX Cool Cooling Coil Speed 2 Performance,  !- Speed 2 Name
  Sys 2 Furnace DX Cool Cooling Coil Speed 3 Performance;  !- Speed 3 Name

In fact, in develop the no load air flow rate was actually operating at the 2nd speed cooling air flow rate (0-based index issue?). Additionally, since this difference was at a no load condition, this operation did not significantly affect other output reports in this file and was easily overlooked as being an issue since an air flow report was not included, except that the html file showed diffs in mech vent numbers.

In this branch:
this->m_MaxNoCoolHeatAirVolFlow = 0.1912

image

@rraustad
Copy link
Contributor Author

Big table diffs in UnitarySystem_FurnaceWithDXSystemRHControl - table rows switched

image

@@ -49491,87 +49491,6 @@ Coil:Cooling:Water:DetailedGeometry,
\note higher than the coil design outlet air temperature, then the design inlet water temperature
\note value is reset to coil design outlet air temperature minus 5.0 DeltaC.

CoilSystem:Cooling:Water,
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure what happened when this was merged in. This is somewhat nit-picking, but this object should stay where it is in the idd.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I saw some discussion of moving this CoilSystem object next to CoilSystem:Cooling:DX and moved my version. Then I saw that was a docs discussion and didn't move it back. I'll do that shortly.

@@ -49499,6 +49499,7 @@ CoilSystem:Cooling:Water,
\min-fields 10
A1, \field Name
\required-field
\reference WaterCoilSystemName
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I assume this should not be here?

Copy link
Contributor

Choose a reason for hiding this comment

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

Correct

@rraustad
Copy link
Contributor Author

Really? Now it's the UsingEnergyPlusForCompliance doc that fails. Did someone tape a sign on my back?

@rraustad
Copy link
Contributor Author

@mjwitte I logic'd these reports out of the new example file. The CoilSystem:Cooling:DX didn't report anything before hence the previous logic, now the new example file does and I missed the subtle change here. Why not just report these out for the parent since the coil doesn't report all of these (as a direct line item). This branch included.

-    if (this->m_OKToPrintSizing && this->UnitType != "CoilSystem:Cooling:DX") PrintFlag = true;
+    if (this->m_OKToPrintSizing && this->m_IsUnitarySystem) PrintFlag = true;

- Component Sizing Information, CoilSystem:Cooling:Water, UNITARY-FREE-COOLING, Design Size Cooling Supply Air Flow Rate [m3/s], 2.61869
- Component Sizing Information, CoilSystem:Cooling:Water, UNITARY-FREE-COOLING, User-Specified No Load Supply Air Flow Rate [m3/s], 0.00000
- Component Sizing Information, CoilSystem:Cooling:Water, UNITARY-FREE-COOLING, Design Size Nominal Cooling Capacity [W], 56622.67387

@rraustad
Copy link
Contributor Author

Opted for 0 diffs and we will address this in the near future.

@mjwitte
Copy link
Contributor

mjwitte commented Aug 13, 2021

I didn't pay close attention to the sizing outputs when Coilsystem:Cooling:Water went in. The wrapper doesn't size anything (same as CoilSystem:Cooling:DX), so they shouldn't be reporting any sizing results.

@rraustad
Copy link
Contributor Author

I am up to date with all comments up to this point.

@Myoldmopar
Copy link
Member

Tracking my way through the conversation, it looks like this has been scrutinized pretty heavily and comments addressed thoroughly, and CI is reasonably happy. I will take a look at the changes now and get it building locally with latest develop. Anything else I should know as I review?

@rraustad
Copy link
Contributor Author

No, good to go after review. Diff's have been explained and justified.

@Myoldmopar
Copy link
Member

Pulled develop in, all tests passing and regressions locally are still inline with what CI last showed. Doing a final look over the code changes but I suspect this will merge shortly.

@rraustad
Copy link
Contributor Author

I pulled develop and ran the new example file again, everything looks as expected with symmetry about the x-axis on water coil total capacity.

image

Copy link
Member

@Myoldmopar Myoldmopar left a comment

Choose a reason for hiding this comment

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

No problems here, this is good to go.


if (present(heatRecoveryCoil)) {
state.dataWaterCoils->WaterCoil(CoilNum).heatRecoveryCoil = heatRecoveryCoil;
}
Copy link
Member

Choose a reason for hiding this comment

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

Another optional isn't great, but it would be a big effort to modify now and not worth holding anything up.

@Myoldmopar
Copy link
Member

Thanks @rraustad and everyone who reviewed!

@Myoldmopar Myoldmopar merged commit 97aef96 into develop Aug 19, 2021
@Myoldmopar Myoldmopar deleted the NFP-runaround-heat-recovery-loop branch August 19, 2021 19:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
IDDChange Code changes impact the IDD file (cannot be merged after IO freeze) NewFeature Includes code to add a new feature to EnergyPlus
Projects
None yet
Development

Successfully merging this pull request may close these issues.

UnitarySystem using Coil:Cooling:DX with multiple speeds operates at incorrect no load air flow rate
10 participants