Coverage for backend/ahuora-builder/src/ahuora_builder/custom/custom_heat_exchanger.py: 83%

101 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-07-22 05:22 +0000

1 

2 

3# Import Pyomo libraries 

4from pyomo.environ import ( 

5 Block, 

6 Var, 

7 Param, 

8 log, 

9 Reference, 

10 PositiveReals, 

11 ExternalFunction, 

12 units as pyunits, 

13 check_optimal_termination, 

14 value, 

15) 

16from pyomo.common.config import ConfigBlock, ConfigValue, In 

17from pyomo.core.base.component import Component 

18 

19# Import IDAES cores 

20from idaes.core import ( 

21 declare_process_block_class, 

22 UnitModelBlockData, 

23) 

24 

25import idaes.logger as idaeslog 

26from idaes.core.util.functions import functions_lib 

27from idaes.core.util.tables import create_stream_table_dataframe 

28from idaes.models.unit_models.heater import ( 

29 _make_heater_config_block, 

30 _make_heater_control_volume, 

31) 

32 

33from idaes.core.util.misc import add_object_reference 

34from idaes.core.util import scaling as iscale 

35from idaes.core.solvers import get_solver 

36from idaes.core.util.exceptions import ConfigurationError, InitializationError 

37from idaes.core.initialization import SingleControlVolumeUnitInitializer 

38from idaes.models.unit_models.heat_exchanger import HX0DInitializer, _make_heat_exchanger_config, HeatExchangerData, delta_temperature_underwood_callback 

39from .inverted import add_inverted, initialise_inverted 

40_log = idaeslog.getLogger(__name__) 

41 

42 

43@declare_process_block_class("CustomHeatExchanger", doc="Simple 0D heat exchanger model.") 

44class CustomHeatExchangerData(HeatExchangerData): 

45 

46 CONFIG = HeatExchangerData.CONFIG() 

47 CONFIG.pop("delta_temperature_callback") 

48 CONFIG.declare( 

49 "delta_temperature_callback", 

50 ConfigValue( 

51 default=delta_temperature_underwood_callback, 

52 description="Callback for for temperature difference calculations", 

53 ), 

54 ) 

55 

56 def build(self,*args,**kwargs) -> None: 

57 """ 

58 Begin building model. 

59 """ 

60 super().build(*args,**kwargs) 

61 # Add an inverted DeltaP 

62 add_inverted(self.hot_side, "deltaP") 

63 add_inverted(self.cold_side, "deltaP") 

64 

65 def initialize_build( 

66 self, 

67 state_args_1=None, 

68 state_args_2=None, 

69 outlvl=idaeslog.NOTSET, 

70 solver=None, 

71 optarg=None, 

72 duty=None, 

73 ): 

74 """ 

75 Heat exchanger initialization method. 

76 

77 Args: 

78 state_args_1 : a dict of arguments to be passed to the property 

79 initialization for the hot side (see documentation of the specific 

80 property package) (default = {}). 

81 state_args_2 : a dict of arguments to be passed to the property 

82 initialization for the cold side (see documentation of the specific 

83 property package) (default = {}). 

84 outlvl : sets output level of initialization routine 

85 optarg : solver options dictionary object (default=None, use 

86 default solver options) 

87 solver : str indicating which solver to use during 

88 initialization (default = None, use default solver) 

89 duty : an initial guess for the amount of heat transferred. This 

90 should be a tuple in the form (value, units), (default 

91 = (1000 J/s)) 

92 

93 Returns: 

94 None 

95 

96 """ 

97 # So, when solving with a correct area, there can be problems 

98 # That's because if the area's even slightly too large, it becomes infeasible 

99 if not self.area.fixed: 

100 self.area.value = self.area.value * 0.8 

101 

102 initialise_inverted(self.hot_side, "deltaP") 

103 initialise_inverted(self.cold_side, "deltaP") 

104 

105 # Set solver options 

106 init_log = idaeslog.getInitLogger(self.name, outlvl, tag="unit") 

107 solve_log = idaeslog.getSolveLogger(self.name, outlvl, tag="unit") 

108 

109 # Create solver 

110 opt = get_solver(solver, optarg) 

111 

112 flags1 = self.hot_side.initialize( 

113 outlvl=outlvl, optarg=optarg, solver=solver, state_args=state_args_1 

114 ) 

115 

116 

117 init_log.info_high("Initialization Step 1a (hot side) Complete.") 

118 

119 flags2 = self.cold_side.initialize( 

120 outlvl=outlvl, optarg=optarg, solver=solver, state_args=state_args_2 

121 ) 

122 init_log.info_high("Initialization Step 1b (cold side) Complete.") 

123 # --------------------------------------------------------------------- 

124 # Solve unit without heat transfer equation 

125 self.heat_transfer_equation.deactivate() 

126 # Deactivate any additional constraints added to constrain outlet temperature/vapor fraction etc during initialisation. 

127 if hasattr( self.cold_side.properties_out, "_deactivate_additional_constraints"): 127 ↛ 129line 127 didn't jump to line 129 because the condition on line 127 was always true

128 self.cold_side.properties_out._deactivate_additional_constraints() 

129 if hasattr( self.hot_side.properties_out, "_deactivate_additional_constraints"): 129 ↛ 133line 129 didn't jump to line 133 because the condition on line 129 was always true

130 self.hot_side.properties_out._deactivate_additional_constraints() 

131 

132 # Get side 1 and side 2 heat units, and convert duty as needed 

133 s1_units = self.hot_side.heat.get_units() 

134 s2_units = self.cold_side.heat.get_units() 

135 

136 # Check to see if heat duty is fixed 

137 # WE will assume that if the first point is fixed, it is fixed at all points 

138 if not self.cold_side.heat[self.flowsheet().time.first()].fixed: 138 ↛ 166line 138 didn't jump to line 166 because the condition on line 138 was always true

139 cs_fixed = False 

140 if duty is None: 140 ↛ 155line 140 didn't jump to line 155 because the condition on line 140 was always true

141 # Assume 1000 J/s and check for unitless properties 

142 if s1_units is None and s2_units is None: 142 ↛ 144line 142 didn't jump to line 144 because the condition on line 142 was never true

143 # Backwards compatibility for unitless properties 

144 s1_duty = -1000 

145 s2_duty = 1000 

146 else: 

147 s1_duty = pyunits.convert_value( 

148 -1000, from_units=pyunits.W, to_units=s1_units 

149 ) 

150 s2_duty = pyunits.convert_value( 

151 1000, from_units=pyunits.W, to_units=s2_units 

152 ) 

153 else: 

154 # Duty provided with explicit units 

155 s1_duty = -pyunits.convert_value( 

156 duty[0], from_units=duty[1], to_units=s1_units 

157 ) 

158 s2_duty = pyunits.convert_value( 

159 duty[0], from_units=duty[1], to_units=s2_units 

160 ) 

161 

162 self.cold_side.heat.fix(s2_duty) 

163 for i in self.hot_side.heat: 

164 self.hot_side.heat[i].value = s1_duty 

165 else: 

166 cs_fixed = True 

167 for i in self.hot_side.heat: 

168 self.hot_side.heat[i].set_value(self.cold_side.heat[i]) 

169 with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: 

170 res = opt.solve(self, tee=slc.tee) 

171 init_log.info_high("Initialization Step 2 {}.".format(idaeslog.condition(res))) 

172 if not cs_fixed: 172 ↛ 176line 172 didn't jump to line 176 because the condition on line 172 was always true

173 self.cold_side.heat.unfix() 

174 

175 

176 if hasattr( self.cold_side.properties_out, "_reactivate_additional_constraints"): 176 ↛ 178line 176 didn't jump to line 178 because the condition on line 176 was always true

177 self.cold_side.properties_out._reactivate_additional_constraints() 

178 if hasattr( self.hot_side.properties_out, "_reactivate_additional_constraints"): 178 ↛ 180line 178 didn't jump to line 180 because the condition on line 178 was always true

179 self.hot_side.properties_out._reactivate_additional_constraints() 

180 self.heat_transfer_equation.activate() 

181 

182 # --------------------------------------------------------------------- 

183 # Solve unit 

184 with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc: 

185 res = opt.solve(self, tee=slc.tee) 

186 init_log.info_high("Initialization Step 3 {}.".format(idaeslog.condition(res))) 

187 # --------------------------------------------------------------------- 

188 

189 # Release Inlet state 

190 self.hot_side.release_state(flags1, outlvl=outlvl) 

191 self.cold_side.release_state(flags2, outlvl=outlvl) 

192 

193 init_log.info("Initialization Completed, {}".format(idaeslog.condition(res))) 

194 

195 if not check_optimal_termination(res): 

196 raise InitializationError( 

197 f"{self.name} failed to initialize successfully. Please check " 

198 f"the output logs for more information." 

199 ) 

200 

201 

202 def diagnose(self) -> list[tuple[Component, str]]: 

203 """ 

204 Test a few common issues with the heat exchanger model and provide hints to the user. 

205 returns a list with the variable the it is most relevant to and a message describing the issue 

206 """ 

207 # if flow rates are drastically different and enthalpy rates are drastically different, 

208 # this might be a problem. 

209 problems = [] 

210 mass_flow_difference = value(self.hot_side.properties_in[0].flow_mass)/value(self.cold_side.properties_in[0].flow_mass) 

211 if mass_flow_difference > 100: 

212 problems.append( 

213 ( 

214 self.hot_side.properties_in[0].flow_mass, 

215 f"Mass flow rate on hot side is {mass_flow_difference:.2f} times higher than cold side. This may cause convergence issues. Consider adjusting the model or providing better initial guesses.", 

216 ) 

217 ) 

218 elif mass_flow_difference < 0.01: 218 ↛ 219line 218 didn't jump to line 219 because the condition on line 218 was never true

219 problems.append( 

220 ( 

221 self.cold_side.properties_in[0].flow_mass, 

222 f"Mass flow rate on cold side is {1/mass_flow_difference:.2f} times higher than hot side. This may cause convergence issues. Consider adjusting the model or providing better initial guesses.", 

223 ) 

224 ) 

225 hsi_temp = value(self.hot_side.properties_in[0].temperature) or 0 

226 csi_temp = value(self.cold_side.properties_in[0].temperature) or 0 

227 hso_temp = value(self.hot_side.properties_out[0].temperature) or 0 

228 cso_temp = value(self.cold_side.properties_out[0].temperature) or 0 

229 if hsi_temp < csi_temp: 

230 # switch hot and cold side temps so hot side is always hotter. 

231 hsi_temp, csi_temp = csi_temp, hsi_temp 

232 hso_temp, cso_temp = cso_temp, hso_temp 

233 

234 if hsi_temp - cso_temp < 1e-1: 

235 problems.append( 

236 ( 

237 self.overall_heat_transfer_coefficient, 

238 f"The heat exchanger has used all the heat available in the hot side. Temperature difference between HS inlet and CS outlet is ({hsi_temp - cso_temp:.2f} K). There needs to be a temperature difference to drive heat transfer. Perhaps there is insufficient energy in one of the streams.", 

239 ) 

240 ) 

241 elif hso_temp - csi_temp < 1e-1: 241 ↛ 242line 241 didn't jump to line 242 because the condition on line 241 was never true

242 problems.append( 

243 ( 

244 self.overall_heat_transfer_coefficient, 

245 f"The heat exchanger has used all the cooling available in the cold side. Temperature difference between HS outlet and CS inlet is ({hso_temp - csi_temp:.2f} K). There needs to be a temperature difference to drive heat transfer. Perhaps there is insufficient cooling in the cold side or too much heat in the hot side.", 

246 ) 

247 ) 

248 return problems 

249 

250 

251 @staticmethod 

252 def ahuora_metadata(): 

253 from ahuora_unit_ops.json_config import ( 

254 JsonAdapterArgConfig, 

255 JsonFrontendConfig, 

256 JsonGraphicObjectConfig, 

257 JsonIdaesAdapterConfig, 

258 JsonPortAdapterConfig, 

259 JsonPortConfig, 

260 JsonPortMapEntryConfig, 

261 JsonPropertyConfig, 

262 JsonPropertySetGroupConfig, 

263 JsonUnitOpConfig, 

264 JsonVariantConfig, 

265 ) 

266 

267 return ( 

268JsonUnitOpConfig( 

269 key='heat_exchanger', 

270 objectType='heatExchanger', 

271 enumMember='HeatExchanger', 

272 displayType='Heat Exchanger', 

273 displayName='Heat Exchanger', 

274 categoryPath=['chemical', 'heating_and_cooling'], 

275 ports={ 

276 'coldInlet': JsonPortConfig( 

277 displayName='Cold Inlet', 

278 type='inlet', 

279 streamType='stream', 

280 many=False, 

281 default=1, 

282 minimum=1, 

283 makeStream=True, 

284 streamOffset=1, 

285 streamName='CS', 

286 ), 

287 'hotInlet': JsonPortConfig( 

288 displayName='Hot Inlet', 

289 type='inlet', 

290 streamType='stream', 

291 many=False, 

292 default=1, 

293 minimum=1, 

294 makeStream=True, 

295 streamOffset=1, 

296 streamName='HS', 

297 ), 

298 'coldOutlet': JsonPortConfig( 

299 displayName='Cold Outlet', 

300 type='outlet', 

301 streamType='stream', 

302 many=False, 

303 default=1, 

304 minimum=1, 

305 makeStream=True, 

306 streamOffset=1, 

307 streamName='CS', 

308 ), 

309 'hotOutlet': JsonPortConfig( 

310 displayName='Hot Outlet', 

311 type='outlet', 

312 streamType='stream', 

313 many=False, 

314 default=1, 

315 minimum=1, 

316 makeStream=True, 

317 streamOffset=1, 

318 streamName='HS', 

319 ), 

320 }, 

321 propertyPackagePorts={ 

322 'Cold Side': ['coldInlet', 'coldOutlet'], 

323 'Hot Side': ['hotInlet', 'hotOutlet'], 

324 }, 

325 graphicObject=JsonGraphicObjectConfig( 

326 kind='unitop_graphic', 

327 ), 

328 indexSets=[], 

329 properties={ 

330 'overall_heat_transfer_coefficient': JsonPropertyConfig( 

331 propertySetGroup='default', 

332 displayName='Heat Transfer Coefficient (U)', 

333 indexSets=None, 

334 sumToOne=False, 

335 value=None, 

336 unit=None, 

337 unitType='heat_transf_coeff', 

338 description=None, 

339 type='numeric', 

340 many=False, 

341 default=1, 

342 options={}, 

343 hasTimeIndex=True, 

344 ), 

345 'area': JsonPropertyConfig( 

346 propertySetGroup='default', 

347 displayName='Heat Exchange Area', 

348 indexSets=None, 

349 sumToOne=False, 

350 value=None, 

351 unit=None, 

352 unitType='area', 

353 description=None, 

354 type='numeric', 

355 many=False, 

356 default=1, 

357 options={}, 

358 hasTimeIndex=False, 

359 ), 

360 'heat_duty': JsonPropertyConfig( 

361 propertySetGroup='default', 

362 displayName='Heat Load', 

363 indexSets=None, 

364 sumToOne=False, 

365 value=None, 

366 unit=None, 

367 unitType='heatflow', 

368 description=None, 

369 type='numeric', 

370 many=False, 

371 default=1, 

372 options={}, 

373 hasTimeIndex=True, 

374 ), 

375 'cold_side.deltaP_inverted': JsonPropertyConfig( 

376 propertySetGroup='default', 

377 displayName='Pressure Drop (Cold Side)', 

378 indexSets=None, 

379 sumToOne=False, 

380 value=0.0, 

381 unit=None, 

382 unitType='pressure', 

383 description=None, 

384 type='numeric', 

385 many=False, 

386 default=1, 

387 options={}, 

388 hasTimeIndex=True, 

389 ), 

390 'hot_side.deltaP_inverted': JsonPropertyConfig( 

391 propertySetGroup='default', 

392 displayName='Pressure Drop (Hot Side)', 

393 indexSets=None, 

394 sumToOne=False, 

395 value=0.0, 

396 unit=None, 

397 unitType='pressure', 

398 description=None, 

399 type='numeric', 

400 many=False, 

401 default=1, 

402 options={}, 

403 hasTimeIndex=True, 

404 ), 

405 }, 

406 propertySetGroups={ 

407 'default': JsonPropertySetGroupConfig( 

408 type='stateVars', 

409 displayName='Properties', 

410 stateVars=[ 

411 'overall_heat_transfer_coefficient', 

412 'area', 

413 'hot_side.deltaP_inverted', 

414 'cold_side.deltaP_inverted', 

415 ], 

416 toggle=None, 

417 ), 

418 }, 

419 keyProperties=['heat_duty', 'logMeanTemperatureDifference', 'minimumTemperatureDifference'], 

420 splitterFractionName=None, 

421 idaesAdapter=JsonIdaesAdapterConfig( 

422 constructor='ahuora_builder.custom.custom_heat_exchanger.CustomHeatExchanger', 

423 args={ 

424 'hot_side': JsonAdapterArgConfig( 

425 kind='dict', 

426 args={ 

427 'property_package': JsonAdapterArgConfig( 

428 kind='property_package', 

429 label='Hot Side', 

430 ), 

431 'has_pressure_change': JsonAdapterArgConfig( 

432 kind='constant', 

433 value=True, 

434 ), 

435 }, 

436 ), 

437 'cold_side': JsonAdapterArgConfig( 

438 kind='dict', 

439 args={ 

440 'property_package': JsonAdapterArgConfig( 

441 kind='property_package', 

442 label='Cold Side', 

443 ), 

444 'has_pressure_change': JsonAdapterArgConfig( 

445 kind='constant', 

446 value=True, 

447 ), 

448 }, 

449 ), 

450 'dynamic': JsonAdapterArgConfig( 

451 kind='constant', 

452 value=False, 

453 ), 

454 }, 

455 ports=JsonPortAdapterConfig( 

456 kind='port_map', 

457 mapping={ 

458 'cold_side_inlet': JsonPortMapEntryConfig( 

459 port='coldInlet', 

460 inlet=True, 

461 ), 

462 'hot_side_inlet': JsonPortMapEntryConfig( 

463 port='hotInlet', 

464 inlet=True, 

465 ), 

466 'cold_side_outlet': JsonPortMapEntryConfig( 

467 port='coldOutlet', 

468 inlet=False, 

469 ), 

470 'hot_side_outlet': JsonPortMapEntryConfig( 

471 port='hotOutlet', 

472 inlet=False, 

473 ), 

474 }, 

475 ), 

476 properties=None, 

477 ), 

478 frontend=JsonFrontendConfig( 

479 showInPanel=True, 

480 variant=JsonVariantConfig( 

481 familyKey='heat_exchanger', 

482 label='Heat Exchanger', 

483 selectorLabel='Heat Exchanger Type', 

484 default=True, 

485 order=0, 

486 preservePorts=True, 

487 preserveGraphic=True, 

488 ), 

489 ), 

490 ), 

491JsonUnitOpConfig( 

492 key='heat_exchanger_ntu', 

493 objectType='heat_exchanger_ntu', 

494 enumMember='NTUHeatExchanger', 

495 displayType='NTU Heat Exchanger', 

496 displayName='NTU Heat Exchanger', 

497 categoryPath=['chemical', 'heating_and_cooling'], 

498 ports={ 

499 'coldInlet': JsonPortConfig( 

500 displayName='Cold Inlet', 

501 type='inlet', 

502 streamType='stream', 

503 many=False, 

504 default=1, 

505 minimum=1, 

506 makeStream=True, 

507 streamOffset=1, 

508 streamName='CS', 

509 ), 

510 'hotInlet': JsonPortConfig( 

511 displayName='Hot Inlet', 

512 type='inlet', 

513 streamType='stream', 

514 many=False, 

515 default=1, 

516 minimum=1, 

517 makeStream=True, 

518 streamOffset=1, 

519 streamName='HS', 

520 ), 

521 'coldOutlet': JsonPortConfig( 

522 displayName='Cold Outlet', 

523 type='outlet', 

524 streamType='stream', 

525 many=False, 

526 default=1, 

527 minimum=1, 

528 makeStream=True, 

529 streamOffset=1, 

530 streamName='CS', 

531 ), 

532 'hotOutlet': JsonPortConfig( 

533 displayName='Hot Outlet', 

534 type='outlet', 

535 streamType='stream', 

536 many=False, 

537 default=1, 

538 minimum=1, 

539 makeStream=True, 

540 streamOffset=1, 

541 streamName='HS', 

542 ), 

543 }, 

544 propertyPackagePorts={ 

545 'Cold Side': ['coldInlet', 'coldOutlet'], 

546 'Hot Side': ['hotInlet', 'hotOutlet'], 

547 }, 

548 graphicObject=JsonGraphicObjectConfig( 

549 kind='unitop_graphic', 

550 ), 

551 indexSets=[], 

552 properties={ 

553 'heat_duty': JsonPropertyConfig( 

554 propertySetGroup='default', 

555 displayName='Heat Load', 

556 indexSets=None, 

557 sumToOne=False, 

558 value=None, 

559 unit=None, 

560 unitType='heatflow', 

561 description=None, 

562 type='numeric', 

563 many=False, 

564 default=1, 

565 options={}, 

566 hasTimeIndex=True, 

567 ), 

568 'effectiveness': JsonPropertyConfig( 

569 propertySetGroup='default', 

570 displayName='Effectiveness', 

571 indexSets=None, 

572 sumToOne=False, 

573 value=None, 

574 unit=None, 

575 unitType='ratio', 

576 description=None, 

577 type='numeric', 

578 many=False, 

579 default=1, 

580 options={}, 

581 hasTimeIndex=True, 

582 ), 

583 'cold_side.deltaP_inverted': JsonPropertyConfig( 

584 propertySetGroup='default', 

585 displayName='Pressure Drop (Cold Side)', 

586 indexSets=None, 

587 sumToOne=False, 

588 value=0.0, 

589 unit=None, 

590 unitType='pressure', 

591 description=None, 

592 type='numeric', 

593 many=False, 

594 default=1, 

595 options={}, 

596 hasTimeIndex=True, 

597 ), 

598 'hot_side.deltaP_inverted': JsonPropertyConfig( 

599 propertySetGroup='default', 

600 displayName='Pressure Drop (Hot Side)', 

601 indexSets=None, 

602 sumToOne=False, 

603 value=0.0, 

604 unit=None, 

605 unitType='pressure', 

606 description=None, 

607 type='numeric', 

608 many=False, 

609 default=1, 

610 options={}, 

611 hasTimeIndex=True, 

612 ), 

613 }, 

614 propertySetGroups={ 

615 'default': JsonPropertySetGroupConfig( 

616 type='stateVars', 

617 displayName='Properties', 

618 stateVars=[ 

619 'heat_transfer_coefficient', 

620 'area', 

621 'effectiveness', 

622 'cold_side.deltaP_inverted', 

623 'hot_side.deltaP_inverted', 

624 ], 

625 toggle=None, 

626 ), 

627 }, 

628 keyProperties=['heat_duty', 'logMeanTemperatureDifference', 'minimumTemperatureDifference'], 

629 splitterFractionName=None, 

630 idaesAdapter=JsonIdaesAdapterConfig( 

631 constructor='ahuora_builder.custom.SimpleEffectivenessHX_DH.HeatExchangerEffectiveness', 

632 args={ 

633 'hot_side': JsonAdapterArgConfig( 

634 kind='dict', 

635 args={ 

636 'property_package': JsonAdapterArgConfig( 

637 kind='property_package', 

638 label='Hot Side', 

639 ), 

640 'has_pressure_change': JsonAdapterArgConfig( 

641 kind='constant', 

642 value=True, 

643 ), 

644 }, 

645 ), 

646 'cold_side': JsonAdapterArgConfig( 

647 kind='dict', 

648 args={ 

649 'property_package': JsonAdapterArgConfig( 

650 kind='property_package', 

651 label='Cold Side', 

652 ), 

653 'has_pressure_change': JsonAdapterArgConfig( 

654 kind='constant', 

655 value=True, 

656 ), 

657 }, 

658 ), 

659 'dynamic': JsonAdapterArgConfig( 

660 kind='constant', 

661 value=False, 

662 ), 

663 }, 

664 ports=JsonPortAdapterConfig( 

665 kind='port_map', 

666 mapping={ 

667 'cold_side_inlet': JsonPortMapEntryConfig( 

668 port='coldInlet', 

669 inlet=True, 

670 ), 

671 'hot_side_inlet': JsonPortMapEntryConfig( 

672 port='hotInlet', 

673 inlet=True, 

674 ), 

675 'cold_side_outlet': JsonPortMapEntryConfig( 

676 port='coldOutlet', 

677 inlet=False, 

678 ), 

679 'hot_side_outlet': JsonPortMapEntryConfig( 

680 port='hotOutlet', 

681 inlet=False, 

682 ), 

683 }, 

684 ), 

685 properties=None, 

686 ), 

687 frontend=JsonFrontendConfig( 

688 showInPanel=False, 

689 variant=JsonVariantConfig( 

690 familyKey='heat_exchanger', 

691 label='NTU Heat Exchanger', 

692 selectorLabel='Heat Exchanger Type', 

693 default=False, 

694 order=10, 

695 preservePorts=True, 

696 preserveGraphic=True, 

697 ), 

698 ), 

699 ), 

700JsonUnitOpConfig( 

701 key='heat_exchanger_lc', 

702 objectType='heat_exchanger_lc', 

703 enumMember='LumpedCapacitanceHeatExchanger', 

704 displayType='Lumped Capacitance Heat Exchanger', 

705 displayName='Lumped Capacitance Heat Exchanger', 

706 categoryPath=['chemical', 'heating_and_cooling'], 

707 ports={ 

708 'coldInlet': JsonPortConfig( 

709 displayName='Cold Inlet', 

710 type='inlet', 

711 streamType='stream', 

712 many=False, 

713 default=1, 

714 minimum=1, 

715 makeStream=True, 

716 streamOffset=1, 

717 streamName='CS', 

718 ), 

719 'hotInlet': JsonPortConfig( 

720 displayName='Hot Inlet', 

721 type='inlet', 

722 streamType='stream', 

723 many=False, 

724 default=1, 

725 minimum=1, 

726 makeStream=True, 

727 streamOffset=1, 

728 streamName='HS', 

729 ), 

730 'coldOutlet': JsonPortConfig( 

731 displayName='Cold Outlet', 

732 type='outlet', 

733 streamType='stream', 

734 many=False, 

735 default=1, 

736 minimum=1, 

737 makeStream=True, 

738 streamOffset=1, 

739 streamName='CS', 

740 ), 

741 'hotOutlet': JsonPortConfig( 

742 displayName='Hot Outlet', 

743 type='outlet', 

744 streamType='stream', 

745 many=False, 

746 default=1, 

747 minimum=1, 

748 makeStream=True, 

749 streamOffset=1, 

750 streamName='HS', 

751 ), 

752 }, 

753 propertyPackagePorts={ 

754 'Cold Side': ['coldInlet', 'coldOutlet'], 

755 'Hot Side': ['hotInlet', 'hotOutlet'], 

756 }, 

757 graphicObject=JsonGraphicObjectConfig( 

758 kind='unitop_graphic', 

759 ), 

760 indexSets=[], 

761 properties={ 

762 'ua_cold_side': JsonPropertyConfig( 

763 propertySetGroup='default', 

764 displayName='Heat Transfer Coefficient (Cold Side)', 

765 indexSets=None, 

766 sumToOne=False, 

767 value=0.0, 

768 unit=None, 

769 unitType='heat_transf_coeff', 

770 description=None, 

771 type='numeric', 

772 many=False, 

773 default=1, 

774 options={}, 

775 hasTimeIndex=True, 

776 ), 

777 'ua_hot_side': JsonPropertyConfig( 

778 propertySetGroup='default', 

779 displayName='Heat Transfer Coefficient (Hot Side)', 

780 indexSets=None, 

781 sumToOne=False, 

782 value=0.0, 

783 unit=None, 

784 unitType='heat_transf_coeff', 

785 description=None, 

786 type='numeric', 

787 many=False, 

788 default=1, 

789 options={}, 

790 hasTimeIndex=True, 

791 ), 

792 'temperature_wall': JsonPropertyConfig( 

793 propertySetGroup='default', 

794 displayName='Average Wall Temperature', 

795 indexSets=None, 

796 sumToOne=False, 

797 value=None, 

798 unit=None, 

799 unitType='temperature', 

800 description=None, 

801 type='numeric', 

802 many=False, 

803 default=1, 

804 options={}, 

805 hasTimeIndex=True, 

806 ), 

807 'heat_duty': JsonPropertyConfig( 

808 propertySetGroup='default', 

809 displayName='Heat Load', 

810 indexSets=None, 

811 sumToOne=False, 

812 value=None, 

813 unit=None, 

814 unitType='heatflow', 

815 description=None, 

816 type='numeric', 

817 many=False, 

818 default=1, 

819 options={}, 

820 hasTimeIndex=True, 

821 ), 

822 }, 

823 propertySetGroups={ 

824 'default': JsonPropertySetGroupConfig( 

825 type='stateVars', 

826 displayName='Properties', 

827 stateVars=['ua_cold_side', 'ua_hot_side', 'temperature_wall'], 

828 toggle=None, 

829 ), 

830 }, 

831 keyProperties=['ua_cold_side', 'ua_hot_side', 'temperature_wall'], 

832 splitterFractionName=None, 

833 idaesAdapter=JsonIdaesAdapterConfig( 

834 constructor='idaes.models.unit_models.heat_exchanger_lc.HeatExchangerLumpedCapacitance', 

835 args={ 

836 'hot_side': JsonAdapterArgConfig( 

837 kind='dict', 

838 args={ 

839 'property_package': JsonAdapterArgConfig( 

840 kind='property_package', 

841 label='Hot Side', 

842 ), 

843 'has_pressure_change': JsonAdapterArgConfig( 

844 kind='constant', 

845 value=False, 

846 ), 

847 }, 

848 ), 

849 'cold_side': JsonAdapterArgConfig( 

850 kind='dict', 

851 args={ 

852 'property_package': JsonAdapterArgConfig( 

853 kind='property_package', 

854 label='Cold Side', 

855 ), 

856 'has_pressure_change': JsonAdapterArgConfig( 

857 kind='constant', 

858 value=False, 

859 ), 

860 }, 

861 ), 

862 'dynamic_heat_balance': JsonAdapterArgConfig( 

863 kind='constant', 

864 value=False, 

865 ), 

866 }, 

867 ports=JsonPortAdapterConfig( 

868 kind='port_map', 

869 mapping={ 

870 'cold_side_inlet': JsonPortMapEntryConfig( 

871 port='coldInlet', 

872 inlet=True, 

873 ), 

874 'hot_side_inlet': JsonPortMapEntryConfig( 

875 port='hotInlet', 

876 inlet=True, 

877 ), 

878 'cold_side_outlet': JsonPortMapEntryConfig( 

879 port='coldOutlet', 

880 inlet=False, 

881 ), 

882 'hot_side_outlet': JsonPortMapEntryConfig( 

883 port='hotOutlet', 

884 inlet=False, 

885 ), 

886 }, 

887 ), 

888 properties=None, 

889 ), 

890 frontend=JsonFrontendConfig( 

891 showInPanel=False, 

892 variant=JsonVariantConfig( 

893 familyKey='heat_exchanger', 

894 label='Lumped Capacitance Heat Exchanger', 

895 selectorLabel='Heat Exchanger Type', 

896 default=False, 

897 order=20, 

898 preservePorts=True, 

899 preserveGraphic=True, 

900 ), 

901 ), 

902 ), 

903JsonUnitOpConfig( 

904 key='plate_heat_exchanger', 

905 objectType='plate_heat_exchanger', 

906 enumMember='PlateHeatExchanger', 

907 displayType='Plate Heat Exchanger', 

908 displayName='Plate Heat Exchanger', 

909 categoryPath=['chemical', 'heating_and_cooling'], 

910 ports={ 

911 'coldInlet': JsonPortConfig( 

912 displayName='Cold Inlet', 

913 type='inlet', 

914 streamType='stream', 

915 many=False, 

916 default=1, 

917 minimum=1, 

918 makeStream=True, 

919 streamOffset=1, 

920 streamName='CS', 

921 ), 

922 'hotInlet': JsonPortConfig( 

923 displayName='Hot Inlet', 

924 type='inlet', 

925 streamType='stream', 

926 many=False, 

927 default=1, 

928 minimum=1, 

929 makeStream=True, 

930 streamOffset=1, 

931 streamName='HS', 

932 ), 

933 'coldOutlet': JsonPortConfig( 

934 displayName='Cold Outlet', 

935 type='outlet', 

936 streamType='stream', 

937 many=False, 

938 default=1, 

939 minimum=1, 

940 makeStream=True, 

941 streamOffset=1, 

942 streamName='CS', 

943 ), 

944 'hotOutlet': JsonPortConfig( 

945 displayName='Hot Outlet', 

946 type='outlet', 

947 streamType='stream', 

948 many=False, 

949 default=1, 

950 minimum=1, 

951 makeStream=True, 

952 streamOffset=1, 

953 streamName='HS', 

954 ), 

955 }, 

956 propertyPackagePorts={ 

957 'Cold Side': ['coldInlet', 'coldOutlet'], 

958 'Hot Side': ['hotInlet', 'hotOutlet'], 

959 }, 

960 graphicObject=JsonGraphicObjectConfig( 

961 kind='unitop_graphic', 

962 ), 

963 indexSets=[], 

964 properties={ 

965 'area': JsonPropertyConfig( 

966 propertySetGroup='default', 

967 displayName='Heat Exchange Area', 

968 indexSets=None, 

969 sumToOne=False, 

970 value=None, 

971 unit=None, 

972 unitType='area', 

973 description=None, 

974 type='numeric', 

975 many=False, 

976 default=1, 

977 options={}, 

978 hasTimeIndex=False, 

979 ), 

980 'plate_length': JsonPropertyConfig( 

981 propertySetGroup='default', 

982 displayName='Plate Length', 

983 indexSets=None, 

984 sumToOne=False, 

985 value=None, 

986 unit=None, 

987 unitType='distance', 

988 description=None, 

989 type='numeric', 

990 many=False, 

991 default=1, 

992 options={}, 

993 hasTimeIndex=True, 

994 ), 

995 'plate_width': JsonPropertyConfig( 

996 propertySetGroup='default', 

997 displayName='Plate Width', 

998 indexSets=None, 

999 sumToOne=False, 

1000 value=None, 

1001 unit=None, 

1002 unitType='distance', 

1003 description=None, 

1004 type='numeric', 

1005 many=False, 

1006 default=1, 

1007 options={}, 

1008 hasTimeIndex=True, 

1009 ), 

1010 'plate_thickness': JsonPropertyConfig( 

1011 propertySetGroup='default', 

1012 displayName='Plate Thickness', 

1013 indexSets=None, 

1014 sumToOne=False, 

1015 value=None, 

1016 unit=None, 

1017 unitType='distance', 

1018 description=None, 

1019 type='numeric', 

1020 many=False, 

1021 default=1, 

1022 options={}, 

1023 hasTimeIndex=True, 

1024 ), 

1025 'plate_pact_length': JsonPropertyConfig( 

1026 propertySetGroup='default', 

1027 displayName='Compressed Plate Pact Length', 

1028 indexSets=None, 

1029 sumToOne=False, 

1030 value=None, 

1031 unit=None, 

1032 unitType='distance', 

1033 description=None, 

1034 type='numeric', 

1035 many=False, 

1036 default=1, 

1037 options={}, 

1038 hasTimeIndex=True, 

1039 ), 

1040 'port_diameter': JsonPropertyConfig( 

1041 propertySetGroup='default', 

1042 displayName='Port Diameter', 

1043 indexSets=None, 

1044 sumToOne=False, 

1045 value=None, 

1046 unit=None, 

1047 unitType='diameter', 

1048 description=None, 

1049 type='numeric', 

1050 many=False, 

1051 default=1, 

1052 options={}, 

1053 hasTimeIndex=True, 

1054 ), 

1055 'plate_therm_cond': JsonPropertyConfig( 

1056 propertySetGroup='default', 

1057 displayName='Plate Thermal Conductivity', 

1058 indexSets=None, 

1059 sumToOne=False, 

1060 value=None, 

1061 unit=None, 

1062 unitType='thermalConductivity', 

1063 description=None, 

1064 type='numeric', 

1065 many=False, 

1066 default=1, 

1067 options={}, 

1068 hasTimeIndex=True, 

1069 ), 

1070 }, 

1071 propertySetGroups={ 

1072 'default': JsonPropertySetGroupConfig( 

1073 type='stateVars', 

1074 displayName='Properties', 

1075 stateVars=[ 

1076 'area', 

1077 'plate_length', 

1078 'plate_width', 

1079 'plate_thickness', 

1080 'plate_pact_length', 

1081 'port_diameter', 

1082 'plate_therm_cond', 

1083 ], 

1084 toggle=None, 

1085 ), 

1086 }, 

1087 keyProperties=['port_diameter', 'plate_therm_cond'], 

1088 splitterFractionName=None, 

1089 idaesAdapter=JsonIdaesAdapterConfig( 

1090 constructor='idaes.models_extra.column_models.plate_heat_exchanger.PlateHeatExchanger', 

1091 args={ 

1092 'hot_side': JsonAdapterArgConfig( 

1093 kind='dict', 

1094 args={ 

1095 'property_package': JsonAdapterArgConfig( 

1096 kind='property_package', 

1097 label='Hot Side', 

1098 ), 

1099 'has_pressure_change': JsonAdapterArgConfig( 

1100 kind='constant', 

1101 value=True, 

1102 ), 

1103 }, 

1104 ), 

1105 'cold_side': JsonAdapterArgConfig( 

1106 kind='dict', 

1107 args={ 

1108 'property_package': JsonAdapterArgConfig( 

1109 kind='property_package', 

1110 label='Cold Side', 

1111 ), 

1112 'has_pressure_change': JsonAdapterArgConfig( 

1113 kind='constant', 

1114 value=True, 

1115 ), 

1116 }, 

1117 ), 

1118 'dynamic': JsonAdapterArgConfig( 

1119 kind='constant', 

1120 value=False, 

1121 ), 

1122 }, 

1123 ports=JsonPortAdapterConfig( 

1124 kind='port_map', 

1125 mapping={ 

1126 'cold_side_inlet': JsonPortMapEntryConfig( 

1127 port='coldInlet', 

1128 inlet=True, 

1129 ), 

1130 'hot_side_inlet': JsonPortMapEntryConfig( 

1131 port='hotInlet', 

1132 inlet=True, 

1133 ), 

1134 'cold_side_outlet': JsonPortMapEntryConfig( 

1135 port='coldOutlet', 

1136 inlet=False, 

1137 ), 

1138 'hot_side_outlet': JsonPortMapEntryConfig( 

1139 port='hotOutlet', 

1140 inlet=False, 

1141 ), 

1142 }, 

1143 ), 

1144 properties=None, 

1145 ), 

1146 frontend=JsonFrontendConfig( 

1147 showInPanel=False, 

1148 variant=JsonVariantConfig( 

1149 familyKey='heat_exchanger', 

1150 label='Plate Heat Exchanger', 

1151 selectorLabel='Heat Exchanger Type', 

1152 default=False, 

1153 order=30, 

1154 preservePorts=True, 

1155 preserveGraphic=True, 

1156 ), 

1157 ), 

1158 ), 

1159 )