diff --git a/README.md b/README.md index 7c3e96118d94483969d5be33ed5767e22cf7e90b..570a8b93cb7b0fa71a9ce4e8363eb280ea5ac08d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,9 @@ The library provides basic models necessary to model adsorption energy systems. ### Dependencies -Regarding non-adsorption specific models, the library partly depends on the [TIL Suite](https://www.tlk-thermo.com/index.php/de/softwareprodukte/til-suite) and the [TIL Media Suite](https://www.tlk-thermo.com/index.php/de/softwareprodukte/tilmedia-suite): +This library was mainly developed using Dymola. Additionally, it was checked that most models also work with OpenModelica. + +Regarding non-adsorption specific models, the library depends on the Modelica Standard Library. The comercial libraries [TIL Suite](https://www.tlk-thermo.com/index.php/de/softwareprodukte/til-suite) and [TIL Media Suite](https://www.tlk-thermo.com/index.php/de/softwareprodukte/tilmedia-suite) are not used within this branch: *TIL Suite is suitable for the stationary and transient simulation of freely configurable thermodynamic systems. Thanks to the substance property library, TILMedia – a component of the TIL Suite – system simulations can be performed extremely quickly and accurately.* @@ -27,12 +29,17 @@ TIL and TILMedia are commercial libraries provided by [TLK-Thermo GmbH](https:// ### Version -The current version 0.1.0 is a pre-release. +The current version 0.2.0 is a pre-release. ### How to cite SorpLib Please cite **SorpLib** as follows: +- Mirko Engelpracht, Patrik Postweiler, Daniel Rezo, Niklas von der Assen. + SorpLib: An open-source Modelica library for dynamic modelling and optimization of adsorption-based process and energy systems. + In: RWTH Git respository, Institute of Technical Thermodynamics (LTT), RWTH Aachen University, 2025. + [link](https://git.rwth-aachen.de/ltt/SorpLib/-/tree/SorpLib_V3_OpenModelica) + - Uwe Bau, Franz Lanzerath, Manuel Gräber, Heike Schreiber, Niklas Thielen, André Bardow. Adsorption energy systems library - Modeling adsorption based chillers, heat pumps, thermal storages and desiccant systems. In: H. Tummescheit und K.-E. Årzén, Hg. Proceedings of the 10th International Modelica Conference. Linköping: Modelica Association, 2014, S. 875-883. ISBN 9789175193809. diff --git a/SorpLib/Applications/AdsorptionChillers/ChillerTwoBed1.mo b/SorpLib/Applications/AdsorptionChillers/ChillerTwoBed1.mo deleted file mode 100644 index 68b04f0d897dc422627e2d992b17f11b7b1b776b..0000000000000000000000000000000000000000 --- a/SorpLib/Applications/AdsorptionChillers/ChillerTwoBed1.mo +++ /dev/null @@ -1,380 +0,0 @@ -within SorpLib.Applications.AdsorptionChillers; -model ChillerTwoBed1 - - Components.EvpCond.EvpCond evaporator( - nports=2, - enableHeatPort=false, - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - enableCasing=true, - nCells=10, - freeVolume(displayUnit="l") = 0.003, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Copper, - massCasing=1, - redeclare model WallMaterial_casing = TILMedia.SolidTypes.TILMedia_Steel, - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - includeDefaultSummary=true, - generateEventsAtFlowReversal=false, - kports=1, - redeclare model VLESideHeatTransferModel = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=3000), - redeclare model HeatTransferModel_InternalCoupling = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=50), - redeclare record TubeGeometry = - Components.EvpCond.Geometry.EvpLanzerath2014 (length=3), - TInitial=283.15, - hx_TInitialCell1=283.15, - hx_TInitialCelln=283.15, - hx_TInitialWall=283.15, - TInitialCasing=283.15) - annotation (Placement(transformation(extent={{-15,-76},{15,-64}}))); - - Components.EvpCond.EvpCond condenser( - nports=2, - enableHeatPort=false, - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - enableCasing=true, - nCells=10, - freeVolume(displayUnit="l") = 0.002, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Copper, - massCasing=1, - redeclare model WallMaterial_casing = TILMedia.SolidTypes.TILMedia_Steel, - redeclare model HeatTransferModel_InternalCoupling = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=30), - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.Schmidt, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - includeDefaultSummary=true, - generateEventsAtFlowReversal=false, - kports=1, - redeclare model VLESideHeatTransferModel = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=3000), - redeclare record TubeGeometry = - Components.EvpCond.Geometry.CondLanzerath2014 (length=4.5), - TInitial=303.15, - hx_TInitialCell1=303.15, - hx_TInitialCelln=303.15, - hx_TInitialWall=303.15, - TInitialCasing=303.15) - annotation (Placement(transformation(extent={{-16,76},{16,64}}))); - - Components.ClosedAdsorber.Adsorber adsorber2( - enableHeatPort=false, - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - enableCasing=true, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Aluminum, - redeclare record TubeGeometry = - Components.ClosedAdsorber.Geometry.Adsorber_Finned_Tubes_Alu, - nCells=10, - massCasing=2, - redeclare model WallMaterial_casing = TILMedia.SolidTypes.TILMedia_Steel, - redeclare model AdsorbentAdsorbateModel = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model HeatTransferModel_HX = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=150), - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - includeDefaultSummary=true, - generateEventsAtFlowReversal=false, - xInitial=0.1, - massAdsorbent=2, - redeclare model HeatTransferModel_InternalCoupling = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=6), - TInitial=363.15, - hx_TInitialCell1=363.15, - hx_TInitialCelln=363.15, - hx_TInitialWall=363.15, - TInitialCasing=363.15) - annotation (Placement(transformation(extent={{26,-10},{52,10}}))); - - Components.ClosedAdsorber.Adsorber adsorber1( - enableHeatPort=false, - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - enableCasing=true, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Aluminum, - redeclare record TubeGeometry = - Components.ClosedAdsorber.Geometry.Adsorber_Finned_Tubes_Alu, - nCells=10, - massCasing=2, - redeclare model WallMaterial_casing = TILMedia.SolidTypes.TILMedia_Steel, - redeclare model AdsorbentAdsorbateModel = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model HeatTransferModel_HX = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=150), - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - includeDefaultSummary=true, - xInitial=0.1, - massAdsorbent=2, - redeclare model HeatTransferModel_InternalCoupling = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=6), - TInitial=303.15, - hx_TInitialCell1=303.15, - hx_TInitialCelln=303.15, - hx_TInitialWall=303.15, - TInitialCasing=303.15) - annotation (Placement(transformation(extent={{-24,-10},{-50,10}}))); - - Components.MassTransfer.MassTransferDiffusionFlow massTransfer_ads1_evp( - isFlap=true, - vleFluidType=sim.vleFluidType1, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model MassTransfer_flow = - Components.MassTransfer.Record.FlowCoefficients.FlowRes_Lanzerath_ads, - inputChoice="dx", - redeclare model MassTransfer_diffusion_dx = - Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_SilicaGel - (m_ads=2)) annotation (Placement(transformation( - extent={{-10,-6},{10,6}}, - rotation=90, - origin={-37,-30}))); - - Components.MassTransfer.MassTransferDiffusionFlow massTransfer_ads2_evp( - isFlap=true, - openingDirection=true, - vleFluidType=sim.vleFluidType1, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model MassTransfer_flow = - Components.MassTransfer.Record.FlowCoefficients.FlowRes_Lanzerath_ads, - inputChoice="dx", - redeclare model MassTransfer_diffusion_dx = - Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_SilicaGel - (m_ads=2)) annotation (Placement(transformation( - extent={{-10,-6},{10,6}}, - rotation=90, - origin={38,-30}))); - - Components.MassTransfer.MassTransferDiffusionFlow massTransfer_ads1_cond( - isFlap=true, - openingDirection=false, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model MassTransfer_flow = - Components.MassTransfer.Record.FlowCoefficients.FlowRes_Lanzerath_des, - inputChoice="dx", - vleFluidType=sim.vleFluidType1, - redeclare model MassTransfer_diffusion_dx = - Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_SilicaGel - (m_ads=2)) annotation (Placement(transformation( - extent={{-10,-6},{10,6}}, - rotation=270, - origin={-38,30}))); - - Components.MassTransfer.MassTransferDiffusionFlow massTransfer_ads2_cond( - isFlap=true, - openingDirection=false, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model MassTransfer_flow = - Components.MassTransfer.Record.FlowCoefficients.FlowRes_Lanzerath_des, - inputChoice="dx", - vleFluidType=sim.vleFluidType1, - redeclare model MassTransfer_diffusion_dx = - Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_SilicaGel - (m_ads=2)) annotation (Placement(transformation( - extent={{-10,-6},{10,6}}, - rotation=270, - origin={38,32}))); - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1, redeclare - TILMedia.LiquidTypes.TILMedia_Water liquidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryAds2B(boundaryType="p") - annotation (Placement(transformation(extent={{64,2},{72,22}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryAds2A( - use_temperatureInput=true, - boundaryType="V_flow", - V_flowFixed(displayUnit="l/min") = -0.00016666666666667) - annotation (Placement(transformation(extent={{72,-22},{64,-2}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryAds1A( - use_temperatureInput=true, - boundaryType="V_flow", - V_flowFixed(displayUnit="l/min") = -0.00016666666666667) - annotation (Placement(transformation(extent={{-72,-22},{-64,-2}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryAds1B(boundaryType="p") - annotation (Placement(transformation(extent={{-72,2},{-64,22}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryEvpA( - boundaryType="V_flow", - V_flowFixed(displayUnit="l/min") = -0.00016666666666667, - TFixed=283.15) - annotation (Placement(transformation(extent={{-30,-82},{-22,-62}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryEvpB(boundaryType="p") - annotation (Placement(transformation(extent={{23,-82},{31,-62}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryCondA( - boundaryType="V_flow", - use_massFlowRateInput=false, - V_flowFixed(displayUnit="l/min") = -0.00016666666666667, - TFixed=303.15) - annotation (Placement(transformation(extent={{-34,62},{-26,82}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryCondB(boundaryType="p") - annotation (Placement(transformation(extent={{25,62},{33,82}}))); - Components.Valves.VLE_Valves.ValveConstantFillingLevel valve_returnflow( - vleFluidType=sim.vleFluidType1, - kp=0.1, - ls=0.1, - l=condenser.volume.l_relative) annotation (Placement(transformation( - extent={{-10,-6},{10,6}}, - rotation=90, - origin={-94,-2}))); - Modelica.Blocks.Sources.Pulse pulse( - amplitude=60, - offset=303.15, - period=1000) - annotation (Placement(transformation(extent={{-84,-17},{-78,-11}}))); - Modelica.Blocks.Sources.Pulse pulse1( - amplitude=-60, - offset=363.15, - period=1000) annotation (Placement(transformation( - extent={{-3,-3},{3,3}}, - rotation=180, - origin={81,-14}))); - - /*******************Summary**********************/ -public - final inner parameter Boolean includeDefaultSummary=true - "include default entries in summary" - annotation (Dialog(tab="Advanced", group="Summary")); - -protected - record Summary - extends TIL.Internals.ClassTypes.Record; - Modelica.SIunits.Pressure p_ad_1 if include; - Real x_ad_1 if include; - Modelica.SIunits.Temperature T_ad_1 if include; - Modelica.SIunits.Pressure p_ad_2 if include; - Real x_ad_2 if include; - Modelica.SIunits.Temperature T_ad_2 if include; - Modelica.SIunits.EnthalpyFlowRate H_flow_evaporator if include; - Modelica.SIunits.EnthalpyFlowRate H_flow_condenser if include; - Modelica.SIunits.EnthalpyFlowRate H_flow_adsorber1 if include; - Modelica.SIunits.EnthalpyFlowRate H_flow_adsorber2 if include; - - protected - outer parameter Boolean includeDefaultSummary; - parameter Boolean include=includeDefaultSummary; - - end Summary; - - replaceable record SummaryClass = Summary; - -public - SummaryClass summary( - p_ad_1=adsorber1.adsorbent.p, - x_ad_1=adsorber1.adsorbent.x, - T_ad_1=adsorber1.adsorbent.T, - p_ad_2=adsorber2.adsorbent.p, - x_ad_2=adsorber2.adsorbent.x, - T_ad_2=adsorber2.adsorbent.T, - H_flow_evaporator = evaporator.summary.DeltaH_flow_liq, - H_flow_condenser = condenser.summary.DeltaH_flow_liq, - H_flow_adsorber1 = adsorber1.summary.DeltaH_flow_liq, - H_flow_adsorber2 = adsorber2.summary.DeltaH_flow_liq) annotation (Placement(transformation(extent={{77,-97}, - {97,-77}}, rotation=0))); -equation - connect(massTransfer_ads2_evp.vlePortB, adsorber2.vlePortB) annotation (Line( - points={{38,-20.8},{38,-20.8},{38,-7},{39.2,-7}}, - color={153,204,0}, - thickness=0.5)); - connect(adsorber1.vlePortB, massTransfer_ads1_evp.vlePortB) annotation (Line( - points={{-37.2,-7},{-37,-7},{-37,-20.8}}, - color={153,204,0}, - thickness=0.5)); - connect(adsorber1.vlePortA, massTransfer_ads1_cond.vlePortB) annotation (Line( - points={{-37.2,7.4},{-38,7.4},{-38,20.8}}, - color={153,204,0}, - thickness=0.5)); - connect(adsorber2.vlePortA, massTransfer_ads2_cond.vlePortB) annotation (Line( - points={{39.2,7.4},{38,7.4},{38,22.8}}, - color={153,204,0}, - thickness=0.5)); - connect(massTransfer_ads1_cond.vlePortA, condenser.vlePort_vapour[1]) - annotation (Line( - points={{-38,39.1},{-38,39.1},{-38,50},{0,50},{0,65.05}}, - color={153,204,0}, - thickness=0.5)); - connect(condenser.vlePort_vapour[2], massTransfer_ads2_cond.vlePortA) - annotation (Line( - points={{0,63.55},{0,63.55},{0,50},{38,50},{38,41.1}}, - color={153,204,0}, - thickness=0.5)); - connect(massTransfer_ads2_evp.vlePortA, evaporator.vlePort_vapour[1]) - annotation (Line( - points={{38,-39.1},{38,-52},{0,-52},{0,-65.05}}, - color={153,204,0}, - thickness=0.5)); - connect(evaporator.vlePort_vapour[2], massTransfer_ads1_evp.vlePortA) - annotation (Line( - points={{0,-63.55},{0,-52},{-37,-52},{-37,-39.1}}, - color={153,204,0}, - thickness=0.5)); - connect(liquidBoundaryAds2A.port, adsorber2.liquidPortA) annotation (Line( - points={{68,-12},{60,-12},{60,-4.2},{53,-4.2}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryAds2B.port, adsorber2.liquidPortB) annotation (Line( - points={{68,12},{60,12},{60,4},{53,4}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryAds1A.port, adsorber1.liquidPortA) annotation (Line( - points={{-68,-12},{-60,-12},{-60,-4.2},{-51,-4.2}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryAds1B.port, adsorber1.liquidPortB) annotation (Line( - points={{-68,12},{-60,12},{-60,4},{-51,4}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryEvpA.port, evaporator.liquidPortA) annotation (Line( - points={{-26,-72},{-15,-72},{-15,-71.5}}, - color={0,170,238}, - thickness=0.5)); - connect(evaporator.liquidPortB, liquidBoundaryEvpB.port) annotation (Line( - points={{15,-71.5},{20.5,-71.5},{20.5,-72},{27,-72}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryCondA.port, condenser.liquidPortA) annotation (Line( - points={{-30,72},{-16,72},{-16,71.5}}, - color={0,170,238}, - thickness=0.5)); - connect(condenser.liquidPortB, liquidBoundaryCondB.port) annotation (Line( - points={{16,71.5},{22,71.5},{22,72},{29,72}}, - color={0,170,238}, - thickness=0.5)); - connect(valve_returnflow.portB, condenser.vlePort_liquid[1]) annotation (Line( - points={{-94,6},{-94,6},{-94,80},{-94,90},{-94,92},{0,92},{0,75.7}}, - color={153,204,0}, - thickness=0.5)); - connect(valve_returnflow.portA, evaporator.vlePort_liquid[1]) annotation ( - Line( - points={{-94,-10},{-94,-10},{-94,-82},{-94,-94},{0,-94},{0,-75.7}}, - color={153,204,0}, - thickness=0.5)); - connect(pulse.y, liquidBoundaryAds1A.T_in) annotation (Line(points={{-77.7,-14}, - {-77.7,-14},{-72,-14}}, color={0,0,127})); - connect(liquidBoundaryAds2A.T_in, pulse1.y) - annotation (Line(points={{72,-14},{77.7,-14}}, color={0,0,127})); - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false)), - experiment(StopTime=10000, Interval=1)); -end ChillerTwoBed1; diff --git a/SorpLib/Applications/AdsorptionChillers/ChillerTwoBed2.mo b/SorpLib/Applications/AdsorptionChillers/ChillerTwoBed2.mo deleted file mode 100644 index e5c88d0b9e0ed99915e3f5206548a712cb4e22f0..0000000000000000000000000000000000000000 --- a/SorpLib/Applications/AdsorptionChillers/ChillerTwoBed2.mo +++ /dev/null @@ -1,324 +0,0 @@ -within SorpLib.Applications.AdsorptionChillers; -model ChillerTwoBed2 - - Components.EvpCond.EvpCond evpCond1( - nports=1, - enableHeatPort=false, - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - enableCasing=true, - nCells=10, - freeVolume(displayUnit="l") = 0.003, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Copper, - massCasing=1, - redeclare model WallMaterial_casing = TILMedia.SolidTypes.TILMedia_Steel, - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - includeDefaultSummary=true, - generateEventsAtFlowReversal=false, - redeclare model VLESideHeatTransferModel = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=3000), - redeclare model HeatTransferModel_InternalCoupling = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=50), - redeclare record TubeGeometry = - Components.EvpCond.Geometry.EvpLanzerath2014 (length=3), - TInitial=283.15, - hx_TInitialCell1=283.15, - hx_TInitialCelln=283.15, - hx_TInitialWall=283.15, - TInitialCasing=283.15) - annotation (Placement(transformation(extent={{-52,-40},{-22,-28}}))); - - Components.ClosedAdsorber.Adsorber adsorber2( - enableHeatPort=false, - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - enableCasing=true, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Aluminum, - redeclare record TubeGeometry = - Components.ClosedAdsorber.Geometry.Adsorber_Finned_Tubes_Alu, - nCells=10, - massCasing=2, - redeclare model WallMaterial_casing = TILMedia.SolidTypes.TILMedia_Steel, - redeclare model AdsorbentAdsorbateModel = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model HeatTransferModel_HX = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=150), - redeclare model HeatTransferModel_InternalCoupling = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=6), - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - includeDefaultSummary=true, - generateEventsAtFlowReversal=false, - xInitial=0.1, - massAdsorbent=2, - TInitial=363.15, - hx_TInitialCell1=363.15, - hx_TInitialCelln=363.15, - hx_TInitialWall=363.15, - TInitialCasing=363.15) - annotation (Placement(transformation(extent={{26,14},{52,34}}))); - - Components.ClosedAdsorber.Adsorber adsorber1( - enableHeatPort=false, - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - enableCasing=true, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Aluminum, - redeclare record TubeGeometry = - Components.ClosedAdsorber.Geometry.Adsorber_Finned_Tubes_Alu, - nCells=10, - massCasing=2, - redeclare model WallMaterial_casing = TILMedia.SolidTypes.TILMedia_Steel, - redeclare model AdsorbentAdsorbateModel = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model HeatTransferModel_HX = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=150), - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - includeDefaultSummary=true, - xInitial=0.1, - massAdsorbent=2, - redeclare model HeatTransferModel_InternalCoupling = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=6), - TInitial=303.15, - hx_TInitialCell1=303.15, - hx_TInitialCelln=303.15, - hx_TInitialWall=303.15, - TInitialCasing=303.15) - annotation (Placement(transformation(extent={{-24,14},{-50,34}}))); - - Components.MassTransfer.MassTransferDiffusionFlow massTransfer_ads1_evp( - vleFluidType=sim.vleFluidType1, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model MassTransfer_flow = - Components.MassTransfer.Record.FlowCoefficients.FlowRes_Lanzerath_ads, - inputChoice="dx", - redeclare model MassTransfer_diffusion_dx = - Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_SilicaGel - (m_ads=2), - isFlap=false) annotation (Placement(transformation( - extent={{-10,-6},{10,6}}, - rotation=90, - origin={-37,-6}))); - - Components.MassTransfer.MassTransferDiffusionFlow massTransfer_ads2_evp( - vleFluidType=sim.vleFluidType1, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model MassTransfer_flow = - Components.MassTransfer.Record.FlowCoefficients.FlowRes_Lanzerath_ads, - inputChoice="dx", - redeclare model MassTransfer_diffusion_dx = - Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_SilicaGel - (m_ads=2), - isFlap=false) annotation (Placement(transformation( - extent={{-10,-6},{10,6}}, - rotation=90, - origin={38,-6}))); - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1, redeclare - TILMedia.LiquidTypes.TILMedia_Water liquidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryAds2B(boundaryType="p") - annotation (Placement(transformation(extent={{64,26},{72,46}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryAds2A( - use_temperatureInput=true, - boundaryType="V_flow", - V_flowFixed(displayUnit="l/min") = -0.00016666666666667) - annotation (Placement(transformation(extent={{72,2},{64,22}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryAds1A( - use_temperatureInput=true, - boundaryType="V_flow", - V_flowFixed(displayUnit="l/min") = -0.00016666666666667) - annotation (Placement(transformation(extent={{-72,2},{-64,22}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryAds1B(boundaryType="p") - annotation (Placement(transformation(extent={{-72,26},{-64,46}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryEvpCond1A( - boundaryType="V_flow", - V_flowFixed(displayUnit="l/min") = -0.00016666666666667, - use_temperatureInput=true) - annotation (Placement(transformation(extent={{-67,-46},{-59,-26}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryEvpCond1B(boundaryType= - "p") annotation (Placement(transformation(extent={{-14,-46},{-6,-26}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryEvpCond2A( - boundaryType="V_flow", - use_massFlowRateInput=false, - V_flowFixed(displayUnit="l/min") = -0.00016666666666667, - use_temperatureInput=true) - annotation (Placement(transformation(extent={{5,-46},{13,-26}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryEvpCond2B(boundaryType= - "p") annotation (Placement(transformation(extent={{63,-45},{71,-25}}))); - Modelica.Blocks.Sources.Pulse pulse( - amplitude=60, - offset=303.15, - period=1000) - annotation (Placement(transformation(extent={{-84,7},{-78,13}}))); - Modelica.Blocks.Sources.Pulse pulse1( - amplitude=-60, - offset=363.15, - period=1000) annotation (Placement(transformation( - extent={{-3,-3},{3,3}}, - rotation=180, - origin={81,10}))); - Modelica.Blocks.Sources.Pulse pulse2( - period=1000, - amplitude=20, - offset=283.15) - annotation (Placement(transformation(extent={{-80,-41},{-74,-35}}))); - Modelica.Blocks.Sources.Pulse pulse3( - period=1000, - amplitude=-20, - offset=303.15) - annotation (Placement(transformation(extent={{-6,-41},{0,-35}}))); - Components.EvpCond.EvpCond evpCond2( - nports=1, - enableHeatPort=false, - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - enableCasing=true, - nCells=10, - freeVolume(displayUnit="l") = 0.003, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Copper, - massCasing=1, - redeclare model WallMaterial_casing = TILMedia.SolidTypes.TILMedia_Steel, - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - includeDefaultSummary=true, - generateEventsAtFlowReversal=false, - redeclare model VLESideHeatTransferModel = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=3000), - redeclare model HeatTransferModel_InternalCoupling = - Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=50), - redeclare record TubeGeometry = - Components.EvpCond.Geometry.EvpLanzerath2014 (length=3), - TInitial=283.15, - hx_TInitialCell1=283.15, - hx_TInitialCelln=283.15, - hx_TInitialWall=283.15, - TInitialCasing=283.15) - annotation (Placement(transformation(extent={{23,-40},{53,-28}}))); - - /*******************Summary**********************/ -public - final inner parameter Boolean includeDefaultSummary=true - "include default entries in summary" - annotation (Dialog(tab="Advanced", group="Summary")); - -protected - record Summary - extends TIL.Internals.ClassTypes.Record; - Modelica.SIunits.Pressure p_ad_1 if include; - Real x_ad_1 if include; - Modelica.SIunits.Temperature T_ad_1 if include; - Modelica.SIunits.Pressure p_ad_2 if include; - Real x_ad_2 if include; - Modelica.SIunits.Temperature T_ad_2 if include; - Modelica.SIunits.EnthalpyFlowRate H_flow_evpcond1 if include; - Modelica.SIunits.EnthalpyFlowRate H_flow_evpcond2 if include; - Modelica.SIunits.EnthalpyFlowRate H_flow_adsorber1 if include; - Modelica.SIunits.EnthalpyFlowRate H_flow_adsorber2 if include; - - protected - outer parameter Boolean includeDefaultSummary; - parameter Boolean include=includeDefaultSummary; - - end Summary; - - replaceable record SummaryClass = Summary; - -public - SummaryClass summary( - p_ad_1=adsorber1.adsorbent.p, - x_ad_1=adsorber1.adsorbent.x, - T_ad_1=adsorber1.adsorbent.T, - p_ad_2=adsorber2.adsorbent.p, - x_ad_2=adsorber2.adsorbent.x, - T_ad_2=adsorber2.adsorbent.T, - H_flow_evpcond1 = evpCond1.summary.DeltaH_flow_liq, - H_flow_evpcond2 = evpCond2.summary.DeltaH_flow_liq, - H_flow_adsorber1 = adsorber1.summary.DeltaH_flow_liq, - H_flow_adsorber2 = adsorber2.summary.DeltaH_flow_liq) annotation (Placement(transformation(extent={{77,-97}, - {97,-77}}, rotation=0))); - -equation - connect(massTransfer_ads2_evp.vlePortB, adsorber2.vlePortB) annotation (Line( - points={{38,3.2},{38,3.2},{38,17},{39.2,17}}, - color={153,204,0}, - thickness=0.5)); - connect(adsorber1.vlePortB, massTransfer_ads1_evp.vlePortB) annotation (Line( - points={{-37.2,17},{-37,17},{-37,3.2}}, - color={153,204,0}, - thickness=0.5)); - connect(evpCond1.vlePort_vapour[1], massTransfer_ads1_evp.vlePortA) - annotation (Line( - points={{-37,-28.3},{-37,-16},{-37,-15.1}}, - color={153,204,0}, - thickness=0.5)); - connect(liquidBoundaryAds2A.port, adsorber2.liquidPortA) annotation (Line( - points={{68,12},{60,12},{60,19.8},{53,19.8}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryAds2B.port, adsorber2.liquidPortB) annotation (Line( - points={{68,36},{60,36},{60,28},{53,28}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryAds1A.port, adsorber1.liquidPortA) annotation (Line( - points={{-68,12},{-60,12},{-60,19.8},{-51,19.8}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryAds1B.port, adsorber1.liquidPortB) annotation (Line( - points={{-68,36},{-60,36},{-60,28},{-51,28}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryEvpCond1A.port, evpCond1.liquidPortA) annotation (Line( - points={{-63,-36},{-52,-36},{-52,-35.5}}, - color={0,170,238}, - thickness=0.5)); - connect(evpCond1.liquidPortB, liquidBoundaryEvpCond1B.port) annotation (Line( - points={{-22,-35.5},{-16.5,-35.5},{-16.5,-36},{-10,-36}}, - color={0,170,238}, - thickness=0.5)); - connect(pulse.y, liquidBoundaryAds1A.T_in) annotation (Line(points={{-77.7,10}, - {-77.7,10},{-72,10}}, color={0,0,127})); - connect(liquidBoundaryAds2A.T_in, pulse1.y) - annotation (Line(points={{72,10},{77.7,10}}, color={0,0,127})); - connect(pulse2.y, liquidBoundaryEvpCond1A.T_in) - annotation (Line(points={{-73.7,-38},{-67,-38}}, color={0,0,127})); - connect(evpCond2.liquidPortB, liquidBoundaryEvpCond2B.port) annotation (Line( - points={{53,-35.5},{62,-35.5},{62,-35},{67,-35}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryEvpCond2A.port, evpCond2.liquidPortA) annotation (Line( - points={{9,-36},{23,-36},{23,-35.5}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryEvpCond2A.T_in, pulse3.y) - annotation (Line(points={{5,-38},{0.3,-38}}, color={0,0,127})); - connect(massTransfer_ads2_evp.vlePortA, evpCond2.vlePort_vapour[1]) - annotation (Line( - points={{38,-15.1},{38,-15.1},{38,-28.3}}, - color={153,204,0}, - thickness=0.5)); - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false)), - experiment(StopTime=10000, Interval=1)); -end ChillerTwoBed2; diff --git a/SorpLib/Applications/AdsorptionChillers/package.mo b/SorpLib/Applications/AdsorptionChillers/package.mo deleted file mode 100644 index 4ac2cfaf522ac008ebdc211f46edf74d8fef80ba..0000000000000000000000000000000000000000 --- a/SorpLib/Applications/AdsorptionChillers/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Applications; -package AdsorptionChillers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - -end AdsorptionChillers; diff --git a/SorpLib/Applications/AdsorptionChillers/package.order b/SorpLib/Applications/AdsorptionChillers/package.order deleted file mode 100644 index 8eb2e6bc9bf1ecdd4e44c769c5cbd591b102a7bd..0000000000000000000000000000000000000000 --- a/SorpLib/Applications/AdsorptionChillers/package.order +++ /dev/null @@ -1,2 +0,0 @@ -ChillerTwoBed1 -ChillerTwoBed2 diff --git a/SorpLib/Applications/DesiccantSystem/DesiccantSystem.mo b/SorpLib/Applications/DesiccantSystem/DesiccantSystem.mo deleted file mode 100644 index 639c3d937cb303ad0d04ca2307f3946be18f4b63..0000000000000000000000000000000000000000 --- a/SorpLib/Applications/DesiccantSystem/DesiccantSystem.mo +++ /dev/null @@ -1,141 +0,0 @@ -within SorpLib.Applications.DesiccantSystem; -model DesiccantSystem - - Components.OpenAdsorber.OpenAdsorber openAdsorber( - nCells=5, - redeclare model PressureDropModel = - Components.Cells.Gas.PressureDropCorrelations.ZeroPressureDrop, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model WallMaterial = TILMedia.SolidTypes.TILMedia_Steel, - redeclare model HeatTransfer_gasWall = - Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.HeatTransfer.PackedBedWall_Kast1988, - xInitial=0.2, - HydraulicMassFlowPosition="gas port A", - redeclare Components.OpenAdsorber.Geometry.CylindricAdsorber - adsorberGeometry( - psi=0.34, - bulkDensity=750, - particleDiameter=0.002, - innerDiameter=0.25, - outerDiameter=0.27, - length=0.1), - redeclare model HeatTransfer_gasAdsorbent = - Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.HeatTransfer.PackedBedGas_Kast1988, - redeclare model MassTransfer_diffusion_dp = - Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.MassTransfer.PackedBedGas_Kast1988, - generateEventsAtFlowReversal=false, - TInitialGas=303.15, - pInitial=100000, - TInitialAdsorbent=303.15, - TInitialWall=303.15) - annotation (Placement(transformation(extent={{-22,-14},{2,14}}))); - - Components.HeatExchanger.HXAirAirParallelflow.HXAirAirParallelflow - hXAirAirCounterflow( - nCells=5, - redeclare Components.HeatExchanger.HXAirAirParallelflow.Geometry.HXGeometry - hxGeometry( - heightDuct1=0.01, - heightDuct2=0.01, - numDucts=20, - length=1, - width=0.5, - tSheet=0.003, - tCasing=0.03), - redeclare model PressureDrop1 = - Components.Cells.Gas.PressureDropCorrelations.ZeroPressureDrop, - redeclare model PressureDrop2 = - Components.Cells.Gas.PressureDropCorrelations.ZeroPressureDrop, - redeclare model WallMaterial = TILMedia.SolidTypes.TILMedia_Steel, - redeclare model HeatTransferGasWall1 = - Components.HeatExchanger.HXAirAirParallelflow.HeatAndMassTransfer.TransportPhenomena.HeatTransfer.ConstantAlpha - (constantAlpha=300), - redeclare model HeatTransferGasWall2 = - Components.HeatExchanger.HXAirAirParallelflow.HeatAndMassTransfer.TransportPhenomena.HeatTransfer.ConstantAlpha - (constantAlpha=300), - generateEventsAtFlowReversal=true, - TInitial1=293.15, - TInitial2=293.15, - TInitialWall=293.15) - annotation (Placement(transformation(extent={{36,-58},{56,-42}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryA( - boundaryType="p", - use_temperatureInput=true, - mixingRatioFixed={0.007,1}, - pFixed=200000) - annotation (Placement(transformation(extent={{-64,-10},{-56,10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundary2B(boundaryType="p", pFixed= - 200000) - annotation (Placement(transformation(extent={{-4,-90},{4,-70}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundary1B( - boundaryType="m_flow", - use_massFlowRateInput=true, - pFixed=200000) - annotation (Placement(transformation(extent={{84,-30},{76,-10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryB( - boundaryType="m_flow", - use_massFlowRateInput=true, - pFixed=200000) - annotation (Placement(transformation(extent={{84,10},{76,30}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundary2A( - boundaryType="m_flow", - m_flowFixed=-5, - pFixed=200000) - annotation (Placement(transformation(extent={{76,-90},{84,-70}}))); - Modelica.Blocks.Sources.Pulse pulse( - amplitude=60, - period=1000, - offset=298.15) - annotation (Placement(transformation(extent={{-86,-9},{-80,-3}}))); - Modelica.Blocks.Sources.Pulse pulse1( - period=1000, - amplitude=1, - offset=0) - annotation (Placement(transformation(extent={{100,19},{94,25}}))); - Modelica.Blocks.Sources.Pulse pulse2( - period=1000, - amplitude=-1, - offset=1.0001) - annotation (Placement(transformation(extent={{100,-21},{94,-15}}))); - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1, redeclare - TILMedia.GasTypes.TILMedia_MoistAir gasType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); -equation - connect(gasBoundaryB.port, openAdsorber.gasPortB) annotation (Line( - points={{80,20},{20,20},{20,0},{2.2,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gasBoundary1B.port, hXAirAirCounterflow.gasPort1B) annotation (Line( - points={{80,-20},{70,-20},{70,-45.2},{56,-45.2}}, - color={255,153,0}, - thickness=0.5)); - connect(gasBoundary2B.port, hXAirAirCounterflow.gasPort2B) annotation (Line( - points={{0,-80},{20,-80},{20,-54.6},{36,-54.6}}, - color={255,153,0}, - thickness=0.5)); - connect(gasBoundary2A.port, hXAirAirCounterflow.gasPort2A) annotation (Line( - points={{80,-80},{70,-80},{70,-54.6},{56,-54.6}}, - color={255,153,0}, - thickness=0.5)); - connect(hXAirAirCounterflow.gasPort1A, openAdsorber.gasPortB) annotation ( - Line( - points={{36,-45.2},{20,-45.2},{20,0},{2.2,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gasBoundaryA.port, openAdsorber.gasPortA) annotation (Line( - points={{-60,0},{-21.8,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gasBoundaryA.T_in, pulse.y) - annotation (Line(points={{-64,-6},{-79.7,-6}}, color={0,0,127})); - connect(gasBoundaryB.m_flow_in, pulse1.y) - annotation (Line(points={{84,22},{93.7,22}}, color={0,0,127})); - connect(gasBoundary1B.m_flow_in, pulse2.y) - annotation (Line(points={{84,-18},{93.7,-18}}, color={0,0,127})); - annotation ( - Icon(coordinateSystem(preserveAspectRatio=false)), - Diagram(coordinateSystem(preserveAspectRatio=false)), - experiment(StopTime=5000)); -end DesiccantSystem; diff --git a/SorpLib/Applications/DesiccantSystem/package.mo b/SorpLib/Applications/DesiccantSystem/package.mo deleted file mode 100644 index 925099534ff396629eec06026a42a120c89589a4..0000000000000000000000000000000000000000 --- a/SorpLib/Applications/DesiccantSystem/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Applications; -package DesiccantSystem - extends SorpLib.Internals.ClassTypes.ApplicationPackage; - -end DesiccantSystem; diff --git a/SorpLib/Applications/DesiccantSystem/package.order b/SorpLib/Applications/DesiccantSystem/package.order deleted file mode 100644 index ff3a19dd45dbbdbdea1321a17671d2fef3cb377b..0000000000000000000000000000000000000000 --- a/SorpLib/Applications/DesiccantSystem/package.order +++ /dev/null @@ -1 +0,0 @@ -DesiccantSystem diff --git a/SorpLib/Applications/package.mo b/SorpLib/Applications/package.mo deleted file mode 100644 index 657f9b5304226f9411000f48cd6b7d241490cfc1..0000000000000000000000000000000000000000 --- a/SorpLib/Applications/package.mo +++ /dev/null @@ -1,7 +0,0 @@ -within SorpLib; -package Applications "Applications of adsorption energy systems" -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - -annotation (Icon(graphics)); -end Applications; diff --git a/SorpLib/Applications/package.order b/SorpLib/Applications/package.order deleted file mode 100644 index 28af93290cc8039717d0a400bbe01f288c0664f0..0000000000000000000000000000000000000000 --- a/SorpLib/Applications/package.order +++ /dev/null @@ -1,2 +0,0 @@ -AdsorptionChillers -DesiccantSystem diff --git a/SorpLib/Basics/Interfaces/BaseClasses/PartialAdsorbatePort.mo b/SorpLib/Basics/Interfaces/BaseClasses/PartialAdsorbatePort.mo new file mode 100644 index 0000000000000000000000000000000000000000..daaf2aa9058738f1205d3935480a6c070956bae0 --- /dev/null +++ b/SorpLib/Basics/Interfaces/BaseClasses/PartialAdsorbatePort.mo @@ -0,0 +1,52 @@ +within SorpLib.Basics.Interfaces.BaseClasses; +partial connector PartialAdsorbatePort + "Base model for all adsorbate ports" + + // + // Definition of parameters + // + parameter Integer no_adsorptivs = 1 + "Number of adsorptivs (i.e., components that can be adsorbed/desorbed)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of connector variables + // + Modelica.Units.SI.Pressure p + "Pressure in the adsorbate port"; + + flow Modelica.Units.SI.MassFlowRate m_flow + "Mass flow rate of the sorbent: If > 0, mass flows from the outside into the + component"; + + stream Modelica.Units.SI.SpecificEnthalpy h_outflow + "Specific enthalpy: If m_flow < 0, specific enthalpy equals specific enthalpy + close to the sorption port"; + stream SorpLib.Units.Uptake x_outflow[no_adsorptivs] + "Loadings m_adsorpt_i/m_sor: If m_flow < 0, loadings equal lpadings close to + the adsorbate port"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This connector is the base connector for all adsorbate ports. It defines the pressure +<i>p</i> as potential variable, the mass flow rate of the sorbent <i>m_flow</i> +as flow variable, and the specific enthalpy <i>h_outflow</i> as well as the loadings +<i>x_outflow</i> as stream variables. Note that the mass flow does not indicate +the total mass flow rate, but only the mass flow rate of the sorbent. The mass +flow rates of the adsorpt components are calculated as +<i>m_flow * actualStram(x_outflow)</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialAdsorbatePort; diff --git a/SorpLib/Basics/Interfaces/BaseClasses/PartialAdsorptPort.mo b/SorpLib/Basics/Interfaces/BaseClasses/PartialAdsorptPort.mo new file mode 100644 index 0000000000000000000000000000000000000000..36c035d7f1589fd798712e6bf8e0ea39e911ea0a --- /dev/null +++ b/SorpLib/Basics/Interfaces/BaseClasses/PartialAdsorptPort.mo @@ -0,0 +1,35 @@ +within SorpLib.Basics.Interfaces.BaseClasses; +partial connector PartialAdsorptPort + "Base model for all adsorpt ports" + + // + // Definition of connector variables + // + SorpLib.Units.Uptake x + "Loading"; + + flow Modelica.Units.SI.MassFlowRate m_flow + "Mass flow rate: If > 0, mass flows from the outside into the component"; + + stream Modelica.Units.SI.SpecificEnthalpy h_outflow + "Specific enthalpy: If m_flow < 0, specific enthalpy equals specific enthalpy + close to the sorption port"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This connector is the base connector for all adsorpt ports. It defines the loading +<i>x</i> as potential variable, the mass flow rate <i>m_flow</i> as flow variable, +and the specific enthalpy <i>h_outflow</i> as stream variable. +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialAdsorptPort; diff --git a/SorpLib/Basics/Interfaces/BaseClasses/PartialFluidPort.mo b/SorpLib/Basics/Interfaces/BaseClasses/PartialFluidPort.mo new file mode 100644 index 0000000000000000000000000000000000000000..42ed971407b1dafb4925a50a33e1f7ecae2d4868 --- /dev/null +++ b/SorpLib/Basics/Interfaces/BaseClasses/PartialFluidPort.mo @@ -0,0 +1,51 @@ +within SorpLib.Basics.Interfaces.BaseClasses; +partial connector PartialFluidPort "Base model for all fluid ports" + + // + // Definition of parameters + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of connector variables + // + Modelica.Units.SI.Pressure p + "Pressure in the fluid port"; + + flow Modelica.Units.SI.MassFlowRate m_flow + "Mass flow rate: If > 0, mass flows from the outside into the component."; + + stream Modelica.Units.SI.SpecificEnthalpy h_outflow + "Specific enthalpy: If m_flow < 0, specific enthalpy equals specific enthalpy + close to the fluid port."; + stream Modelica.Units.SI.MassFraction Xi_outflow[no_components-1] + "Independent mixture mass fractions m_i/m: If m_flow < 0, mass fractions equal + mass fractions close to the fluid port."; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This connector is the base connector for all fluid ports. It defines the pressure +<i>p</i> as potential variable, the mass flow rate <i>m_flow</i> as flow variable, +and the specific enthalpy <i>h_outflow</i>, and independent mixture mass fractions +<i>Xi_outflow</i> as stream variables. +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialFluidPort; diff --git a/SorpLib/Basics/Interfaces/BaseClasses/PartialHeatPort.mo b/SorpLib/Basics/Interfaces/BaseClasses/PartialHeatPort.mo new file mode 100644 index 0000000000000000000000000000000000000000..7850409c189a5303f0900f3e68b9e712cac1a514 --- /dev/null +++ b/SorpLib/Basics/Interfaces/BaseClasses/PartialHeatPort.mo @@ -0,0 +1,34 @@ +within SorpLib.Basics.Interfaces.BaseClasses; +partial connector PartialHeatPort + "Base model for all heat ports" + + // + // Definition of connector variables + // + Modelica.Units.SI.Temperature T + "Temperature in the heat port"; + + flow Modelica.Units.SI.HeatFlowRate Q_flow + "Heat flow rate: If > 0, heat flows from the outside into the component."; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This connector is the base connector for all heat ports. It defines the temperature +<i>T</i> as potential variable and the heat flow rate <i>Q_flow</i> as flow variable. +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialHeatPort; diff --git a/SorpLib/Basics/Interfaces/BaseClasses/package.mo b/SorpLib/Basics/Interfaces/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f446082c98b9489b91d42c45aa0269c109524115 --- /dev/null +++ b/SorpLib/Basics/Interfaces/BaseClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Basics.Interfaces; +package BaseClasses "Base connectors used to create new interfaces" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial connectors. These partial containg contain fundamental +definitions for ports. The content of this package is only of interest when adding +new ports to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Basics/Interfaces/BaseClasses/package.order b/SorpLib/Basics/Interfaces/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c803305ac306d368c9d97861384968ee50b7876b --- /dev/null +++ b/SorpLib/Basics/Interfaces/BaseClasses/package.order @@ -0,0 +1,4 @@ +PartialHeatPort +PartialFluidPort +PartialAdsorbatePort +PartialAdsorptPort diff --git a/SorpLib/Basics/Interfaces/FluidPorts/GasPort_in.mo b/SorpLib/Basics/Interfaces/FluidPorts/GasPort_in.mo new file mode 100644 index 0000000000000000000000000000000000000000..fc73816773d98f43f8acdd26d6d2383448fbde10 --- /dev/null +++ b/SorpLib/Basics/Interfaces/FluidPorts/GasPort_in.mo @@ -0,0 +1,43 @@ +within SorpLib.Basics.Interfaces.FluidPorts; +connector GasPort_in + "Gas port for design inlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort; + + // + // Annotations + // + annotation (defaultComponentName="gasPort_in", + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, + -100},{100,100}}), graphics={Ellipse( + extent={{-40,40},{40,-40}}, + lineColor={244,125,35}, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), Text(extent={{-150,110},{150,50}}, + textString="%name")}), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ + 100,100}}), graphics={ Ellipse( + extent={{-100,100},{100,-100}}, + lineColor={244,125,35}, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid, + lineThickness=1)}), + Documentation(info="<html> +<p> +This connector is used for gas ports at the design inlet. According to the +Modelica sign convention, a <strong>positive</strong> mass flow rate +<strong>m_flow</strong> is considered to flow <strong>into</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasPort_in; diff --git a/SorpLib/Basics/Interfaces/FluidPorts/GasPort_out.mo b/SorpLib/Basics/Interfaces/FluidPorts/GasPort_out.mo new file mode 100644 index 0000000000000000000000000000000000000000..208c8ccc33ca45a4e1d50d68fcf9c5d562f55682 --- /dev/null +++ b/SorpLib/Basics/Interfaces/FluidPorts/GasPort_out.mo @@ -0,0 +1,55 @@ +within SorpLib.Basics.Interfaces.FluidPorts; +connector GasPort_out + "Gas port for design outlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort; + + // + // Annotations + // + annotation (defaultComponentName="gasPort_out", + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, + -100},{100,100}}), graphics={ + Ellipse( + extent={{-40,40},{40,-40}}, + lineColor={244,125,35}, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,30},{30,-30}}, + lineColor={0,127,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text(extent={{-150,110},{150,50}}, textString="%name")}), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ + 100,100}}), graphics={ + Ellipse( + extent={{-100,100},{100,-100}}, + lineColor={244,125,35}, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid, + lineThickness=1), + Ellipse( + extent={{-80,80},{80,-80}}, + lineColor={244,125,35}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This connector is used for gas ports at the design outlet. According to the +Modelica sign convention, a <strong>negative</strong> mass flow rate +<strong>m_flow</strong> is considered to flow <strong>out</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasPort_out; diff --git a/SorpLib/Basics/Interfaces/FluidPorts/LiquidPort_in.mo b/SorpLib/Basics/Interfaces/FluidPorts/LiquidPort_in.mo new file mode 100644 index 0000000000000000000000000000000000000000..3b8d2dec2d31162b7373d2a01d4a5d6dd739dfdf --- /dev/null +++ b/SorpLib/Basics/Interfaces/FluidPorts/LiquidPort_in.mo @@ -0,0 +1,43 @@ +within SorpLib.Basics.Interfaces.FluidPorts; +connector LiquidPort_in + "Liquid port for design inlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort; + + // + // Annotations + // + annotation (defaultComponentName="liquidPort_in", + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, + -100},{100,100}}), graphics={Ellipse( + extent={{-40,40},{40,-40}}, + lineColor={28,108,200}, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), Text(extent={{-150,110},{150,50}}, + textString="%name")}), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ + 100,100}}), graphics={ Ellipse( + extent={{-100,100},{100,-100}}, + lineColor={28,108,200}, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid, + lineThickness=1)}), + Documentation(info="<html> +<p> +This connector is used for liquid ports at the design inlet. According to the +Modelica sign convention, a <strong>positive</strong> mass flow rate +<strong>m_flow</strong> is considered to flow <strong>into</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end LiquidPort_in; diff --git a/SorpLib/Basics/Interfaces/FluidPorts/LiquidPort_out.mo b/SorpLib/Basics/Interfaces/FluidPorts/LiquidPort_out.mo new file mode 100644 index 0000000000000000000000000000000000000000..c4651653c81a3fb9d9392a38d35ab08a7cb15c7d --- /dev/null +++ b/SorpLib/Basics/Interfaces/FluidPorts/LiquidPort_out.mo @@ -0,0 +1,55 @@ +within SorpLib.Basics.Interfaces.FluidPorts; +connector LiquidPort_out + "Liquid port for design outlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort; + + // + // Annotations + // + annotation (defaultComponentName="liquidPort_out", + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, + -100},{100,100}}), graphics={ + Ellipse( + extent={{-40,40},{40,-40}}, + lineColor={28,108,200}, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,30},{30,-30}}, + lineColor={0,127,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text(extent={{-150,110},{150,50}}, textString="%name")}), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ + 100,100}}), graphics={ + Ellipse( + extent={{-100,100},{100,-100}}, + lineColor={28,108,200}, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid, + lineThickness=1), + Ellipse( + extent={{-80,80},{80,-80}}, + lineColor={28,108,200}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This connector is used for liquid ports at the design outlet. According to the +Modelica sign convention, a <strong>negative</strong> mass flow rate +<strong>m_flow</strong> is considered to flow <strong>out</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end LiquidPort_out; diff --git a/SorpLib/Basics/Interfaces/FluidPorts/VLEPort_in.mo b/SorpLib/Basics/Interfaces/FluidPorts/VLEPort_in.mo new file mode 100644 index 0000000000000000000000000000000000000000..ec7f5d8ee6b4da57f14d96b627c872c0f8a595bc --- /dev/null +++ b/SorpLib/Basics/Interfaces/FluidPorts/VLEPort_in.mo @@ -0,0 +1,43 @@ +within SorpLib.Basics.Interfaces.FluidPorts; +connector VLEPort_in + "VLE port for design inlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort; + + // + // Annotations + // + annotation (defaultComponentName="VLEPort_in", + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, + -100},{100,100}}), graphics={Ellipse( + extent={{-40,40},{40,-40}}, + lineColor={0,140,72}, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), Text(extent={{-150,110},{150,50}}, + textString="%name")}), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ + 100,100}}), graphics={ Ellipse( + extent={{-100,100},{100,-100}}, + lineColor={0,140,72}, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid, + lineThickness=1)}), + Documentation(info="<html> +<p> +This connector is used for VLE ports at the design inlet. According to the +Modelica sign convention, a <strong>positive</strong> mass flow rate +<strong>m_flow</strong> is considered to flow <strong>into</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end VLEPort_in; diff --git a/SorpLib/Basics/Interfaces/FluidPorts/VLEPort_out.mo b/SorpLib/Basics/Interfaces/FluidPorts/VLEPort_out.mo new file mode 100644 index 0000000000000000000000000000000000000000..1b4f65c726c10368e463af1fb1b019f4736a6d2c --- /dev/null +++ b/SorpLib/Basics/Interfaces/FluidPorts/VLEPort_out.mo @@ -0,0 +1,55 @@ +within SorpLib.Basics.Interfaces.FluidPorts; +connector VLEPort_out + "VLE port for design outlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort; + + // + // Annotations + // + annotation (defaultComponentName="VLEPort_out", + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, + -100},{100,100}}), graphics={ + Ellipse( + extent={{-40,40},{40,-40}}, + lineColor={0,140,72}, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,30},{30,-30}}, + lineColor={0,127,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text(extent={{-150,110},{150,50}}, textString="%name")}), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ + 100,100}}), graphics={ + Ellipse( + extent={{-100,100},{100,-100}}, + lineColor={0,140,72}, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid, + lineThickness=1), + Ellipse( + extent={{-80,80},{80,-80}}, + lineColor={0,140,72}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This connector is used for VLE ports at the design outlet. According to the +Modelica sign convention, a <strong>negative</strong> mass flow rate +<strong>m_flow</strong> is considered to flow <strong>out</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end VLEPort_out; diff --git a/SorpLib/Basics/Interfaces/FluidPorts/package.mo b/SorpLib/Basics/Interfaces/FluidPorts/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..95e7daa76afc97b7fe31f0d9f6cc6390390e6b96 --- /dev/null +++ b/SorpLib/Basics/Interfaces/FluidPorts/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Basics.Interfaces; +package FluidPorts "Package containing fluid ports" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains fluid port connectors. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end FluidPorts; diff --git a/SorpLib/Basics/Interfaces/FluidPorts/package.order b/SorpLib/Basics/Interfaces/FluidPorts/package.order new file mode 100644 index 0000000000000000000000000000000000000000..99f28f4159e507168acd42f3ddd1bb17aa77d7d8 --- /dev/null +++ b/SorpLib/Basics/Interfaces/FluidPorts/package.order @@ -0,0 +1,6 @@ +LiquidPort_in +LiquidPort_out +GasPort_in +GasPort_out +VLEPort_in +VLEPort_out diff --git a/SorpLib/Basics/Interfaces/HeatPorts/HeatPort_in.mo b/SorpLib/Basics/Interfaces/HeatPorts/HeatPort_in.mo new file mode 100644 index 0000000000000000000000000000000000000000..2dc0cb513316441b7f79b466b3556249b04093ca --- /dev/null +++ b/SorpLib/Basics/Interfaces/HeatPorts/HeatPort_in.mo @@ -0,0 +1,42 @@ +within SorpLib.Basics.Interfaces.HeatPorts; +connector HeatPort_in + "Heat port for design inlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialHeatPort; + + // + // Annotations + // + annotation (defaultComponentName="heatPort_in", + Icon(graphics={Rectangle( + extent={{-80,80},{80,-80}}, + lineColor={238,46,47}, + fillColor={238,46,47}, + fillPattern=FillPattern.Solid, + lineThickness=1)}), Diagram(graphics={ + Text(extent={{-150,110},{150,50}}, + textString="%name"), Rectangle( + extent={{-40,40},{40,-40}}, + lineColor={238,46,47}, + lineThickness=1, + fillColor={238,46,47}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This connector is used for heat ports at the design inlet. According to the +Modelica sign convention, a <strong>positive</strong> heat flow rate +<strong>Q_flow</strong> is considered to flow <strong>into</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end HeatPort_in; diff --git a/SorpLib/Basics/Interfaces/HeatPorts/HeatPort_out.mo b/SorpLib/Basics/Interfaces/HeatPorts/HeatPort_out.mo new file mode 100644 index 0000000000000000000000000000000000000000..1e028b1eaa716cc32cbb7dfff7f660ea641ac875 --- /dev/null +++ b/SorpLib/Basics/Interfaces/HeatPorts/HeatPort_out.mo @@ -0,0 +1,55 @@ +within SorpLib.Basics.Interfaces.HeatPorts; +connector HeatPort_out + "Heat port for design outlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialHeatPort; + + // + // Annotations + // + annotation (defaultComponentName="heatPort_out", + Icon(graphics={Rectangle( + extent={{-90,88},{90,-92}}, + lineColor={238,46,47}, + fillColor={238,46,47}, + fillPattern=FillPattern.Solid, + lineThickness=1), Rectangle( + extent={{-72,72},{70,-72}}, + lineColor={255,255,255}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid)}), + Diagram(graphics={ + Text(extent={{-150,110},{150,50}}, + textString="%name"), + Rectangle( + extent={{-40,40},{40,-40}}, + lineColor={238,46,47}, + lineThickness=1, + fillColor={238,46,47}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{-36,36},{36,-36}}, + lineColor={255,255,255}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This connector is used for heat ports at the design outlet. According to the +Modelica sign convention, a <strong>negative</strong> heat flow rate +<strong>Q_flow</strong> is considered to flow <strong>out</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end HeatPort_out; diff --git a/SorpLib/Basics/Interfaces/HeatPorts/package.mo b/SorpLib/Basics/Interfaces/HeatPorts/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e04f1635b6b6f3082e86ed994fa8a58e06c71e26 --- /dev/null +++ b/SorpLib/Basics/Interfaces/HeatPorts/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Basics.Interfaces; +package HeatPorts "Package containing heat ports" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains heat port connectors. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end HeatPorts; diff --git a/SorpLib/Basics/Interfaces/HeatPorts/package.order b/SorpLib/Basics/Interfaces/HeatPorts/package.order new file mode 100644 index 0000000000000000000000000000000000000000..3cffaddbc3e90d935bbbf05ab7b99f0af073a148 --- /dev/null +++ b/SorpLib/Basics/Interfaces/HeatPorts/package.order @@ -0,0 +1,2 @@ +HeatPort_in +HeatPort_out diff --git a/SorpLib/Basics/Interfaces/SorptionPorts/AdsorbatePort_in.mo b/SorpLib/Basics/Interfaces/SorptionPorts/AdsorbatePort_in.mo new file mode 100644 index 0000000000000000000000000000000000000000..128c21532e4aceda85479b58c0592d73900fa392 --- /dev/null +++ b/SorpLib/Basics/Interfaces/SorptionPorts/AdsorbatePort_in.mo @@ -0,0 +1,38 @@ +within SorpLib.Basics.Interfaces.SorptionPorts; +connector AdsorbatePort_in "Adsorbate port for design inlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialAdsorbatePort; + + // + // Annotations + // + annotation (defaultComponentName="VLEPort_in", + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, + -100},{100,100}}), graphics={Ellipse( + extent={{-40,40},{40,-40}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), Text(extent={{-150,110},{150,50}}, + textString="%name")}), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ + 100,100}}), graphics={ Ellipse( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid, + lineThickness=1)}), + Documentation(info="<html> +<p> +This connector is used for adsorbate ports at the design inlet. According to the +Modelica sign convention, a <strong>positive</strong> mass flow rate +<strong>m_flow</strong> is considered to flow <strong>into</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorbatePort_in; diff --git a/SorpLib/Basics/Interfaces/SorptionPorts/AdsorbatePort_out.mo b/SorpLib/Basics/Interfaces/SorptionPorts/AdsorbatePort_out.mo new file mode 100644 index 0000000000000000000000000000000000000000..e474d219ae44ce116d83754f9d0e98c41613b1fd --- /dev/null +++ b/SorpLib/Basics/Interfaces/SorptionPorts/AdsorbatePort_out.mo @@ -0,0 +1,50 @@ +within SorpLib.Basics.Interfaces.SorptionPorts; +connector AdsorbatePort_out "Adsorbate port for design outlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialAdsorbatePort; + + // + // Annotations + // + annotation (defaultComponentName="VLEPort_out", + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, + -100},{100,100}}), graphics={ + Ellipse( + extent={{-40,40},{40,-40}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,30},{30,-30}}, + lineColor={0,127,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text(extent={{-150,110},{150,50}}, textString="%name")}), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ + 100,100}}), graphics={ + Ellipse( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid, + lineThickness=1), + Ellipse( + extent={{-80,80},{80,-80}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This connector is used for adsorbate ports at the design outlet. According to the +Modelica sign convention, a <strong>negative</strong> mass flow rate +<strong>m_flow</strong> is considered to flow <strong>out</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorbatePort_out; diff --git a/SorpLib/Basics/Interfaces/SorptionPorts/AdsorptPort_in.mo b/SorpLib/Basics/Interfaces/SorptionPorts/AdsorptPort_in.mo new file mode 100644 index 0000000000000000000000000000000000000000..e648382206c9478e4eb5db3698976ebe99dc2251 --- /dev/null +++ b/SorpLib/Basics/Interfaces/SorptionPorts/AdsorptPort_in.mo @@ -0,0 +1,38 @@ +within SorpLib.Basics.Interfaces.SorptionPorts; +connector AdsorptPort_in "Adsorpt port for design inlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialAdsorptPort; + + // + // Annotations + // + annotation (defaultComponentName="VLEPort_in", + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, + -100},{100,100}}), graphics={Ellipse( + extent={{-40,40},{40,-40}}, + lineColor={175,175,175}, + fillColor={175,175,175}, + fillPattern=FillPattern.Solid), Text(extent={{-150,110},{150,50}}, + textString="%name")}), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ + 100,100}}), graphics={ Ellipse( + extent={{-100,100},{100,-100}}, + lineColor={175,175,175}, + fillColor={175,175,175}, + fillPattern=FillPattern.Solid, + lineThickness=1)}), + Documentation(info="<html> +<p> +This connector is used for adsorpt ports at the design inlet. According to the +Modelica sign convention, a <strong>positive</strong> mass flow rate +<strong>m_flow</strong> is considered to flow <strong>into</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorptPort_in; diff --git a/SorpLib/Basics/Interfaces/SorptionPorts/AdsorptPort_out.mo b/SorpLib/Basics/Interfaces/SorptionPorts/AdsorptPort_out.mo new file mode 100644 index 0000000000000000000000000000000000000000..1ef0a4d5426d0f76acad80dcfb26e48a283ee104 --- /dev/null +++ b/SorpLib/Basics/Interfaces/SorptionPorts/AdsorptPort_out.mo @@ -0,0 +1,50 @@ +within SorpLib.Basics.Interfaces.SorptionPorts; +connector AdsorptPort_out "Adsorpt port for design outlet" + extends SorpLib.Basics.Interfaces.BaseClasses.PartialAdsorptPort; + + // + // Annotations + // + annotation (defaultComponentName="VLEPort_out", + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, + -100},{100,100}}), graphics={ + Ellipse( + extent={{-40,40},{40,-40}}, + lineColor={175,175,175}, + fillColor={175,175,175}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,30},{30,-30}}, + lineColor={0,127,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text(extent={{-150,110},{150,50}}, textString="%name")}), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ + 100,100}}), graphics={ + Ellipse( + extent={{-100,100},{100,-100}}, + lineColor={175,175,175}, + fillColor={175,175,175}, + fillPattern=FillPattern.Solid, + lineThickness=1), + Ellipse( + extent={{-80,80},{80,-80}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This connector is used for adsorpt ports at the design outlet. According to the +Modelica sign convention, a <strong>negative</strong> mass flow rate +<strong>m_flow</strong> is considered to flow <strong>out</strong> a component. +This convention has to be used whenever this connector is used in a model class. +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorptPort_out; diff --git a/SorpLib/Basics/Interfaces/SorptionPorts/package.mo b/SorpLib/Basics/Interfaces/SorptionPorts/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..31ae4e251d7fe2137e514b617b5a59b54d8b1d8f --- /dev/null +++ b/SorpLib/Basics/Interfaces/SorptionPorts/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Basics.Interfaces; +package SorptionPorts "Package containing sorption ports" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains sorption port connectors. +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SorptionPorts; diff --git a/SorpLib/Basics/Interfaces/SorptionPorts/package.order b/SorpLib/Basics/Interfaces/SorptionPorts/package.order new file mode 100644 index 0000000000000000000000000000000000000000..4a01389e4f6622f2ae25f067b1a36b7240b73667 --- /dev/null +++ b/SorpLib/Basics/Interfaces/SorptionPorts/package.order @@ -0,0 +1,4 @@ +AdsorbatePort_in +AdsorbatePort_out +AdsorptPort_in +AdsorptPort_out diff --git a/SorpLib/Basics/Interfaces/package.mo b/SorpLib/Basics/Interfaces/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9007d89b2a01aa93475ab6902ff287d22dd0ab10 --- /dev/null +++ b/SorpLib/Basics/Interfaces/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Basics; +package Interfaces "Interfaces for models" +extends Modelica.Icons.InterfacesPackage; + +annotation (Documentation(info="<html> +<p> +This package provides definitions of basic connectors used to aggregate more +complex models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Interfaces; diff --git a/SorpLib/Basics/Interfaces/package.order b/SorpLib/Basics/Interfaces/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c0f4e3b3eaddce5231730834f812233d456cefc8 --- /dev/null +++ b/SorpLib/Basics/Interfaces/package.order @@ -0,0 +1,4 @@ +BaseClasses +HeatPorts +FluidPorts +SorptionPorts diff --git a/SorpLib/Basics/Sources/BaseClasses/PartialFluidSource.mo b/SorpLib/Basics/Sources/BaseClasses/PartialFluidSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..58a27932f6f3dbc50a9d02353c68902e1df6b989 --- /dev/null +++ b/SorpLib/Basics/Sources/BaseClasses/PartialFluidSource.mo @@ -0,0 +1,377 @@ +within SorpLib.Basics.Sources.BaseClasses; +partial model PartialFluidSource + "Base model for all fluid sources" + + // + // Definition of parameters regarding the boundary type + // + parameter Integer no_components = 1 + "Number of components within the medium" + annotation (Dialog(tab="General", group="Boundary Type"), + Evaluate=true, + HideResult=true); + + parameter SorpLib.Choices.BoundaryFluidPotentialFlow boundaryTypePotentialFlow= + SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure + "Boundary type for potential or flow variable" + annotation (Dialog(tab="General", group="Boundary Type"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Choices.BoundaryFluidStreamEnthalpy boundaryTypeStreamEnthalpy= + SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy + "Boundary type for stream variable of specific enthalpy" + annotation (Dialog(tab="General", group="Boundary Type"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Choices.BoundaryFluidStreamMassFractions boundaryTypeStreamMassFractions= + SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions + "Boundary type for stream variable of mass fractions" + annotation (Dialog(tab="General", group="Boundary Type"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding potential and flow variables + // + parameter Boolean use_pInput = false + " = true, if p is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=(boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Pressure p_fixed = 1.01325e5 + "Fixed pressure at boundary" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=(boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure) + and not use_pInput)); + + parameter Boolean use_mFlowInput = false + "=true, if m_flow is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=(boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.MassFlowRate m_flow_fixed = -0.001 + "Fixed mass flow rate at boundary" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=(boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate) + and not use_mFlowInput)); + + parameter Boolean use_VFlowInput = false + "=true, if V_flow is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=(boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.VolumeFlowRate V_flow_fixed = -10/60 + "Fixed volume flow rate at boundary" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=(boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate) + and not use_VFlowInput)); + + // + // Definition of parameters regarding stream variables of specific enthalpy + // + parameter Boolean use_hInput = false + "=true, if h is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Stream Variables - Specific Enthalpy", + enable=(boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.SpecificEnthalpy h_fixed = 350e3 + "Fixed specific enthalpy at boundary" + annotation (Dialog(tab="General",group="Stream Variables - Specific Enthalpy", + enable=(boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy) + and not use_hInput)); + + parameter Boolean use_TInput = false + "=true, if T is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Stream Variables - Specific Enthalpy", + enable=(boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Temperature T_fixed = 298.15 + "Fixed temperature at boundary" + annotation (Dialog(tab="General",group="Stream Variables - Specific Enthalpy", + enable=(boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature) + and not use_TInput)); + + // + // Definition of parameters regarding stream variables of mass fractions + // + parameter Boolean use_XInput = false + "=true, if X is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Stream Variables - Mass Fractions", + enable=(boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.MassFraction[no_components] X_fixed= + fill(1/no_components, no_components) + "Fixed mass fractions at boundary" + annotation (Dialog(tab="General",group="Stream Variables - Mass Fractions", + enable=(boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions) + and not use_XInput)); + + // + // Definition of advanced parameters + // + parameter Modelica.Units.SI.MassFlowRate m_flow_small = 1e-5 + "Regularization value for mass flow rate to handle flow reversal and division + by zero" + annotation (Dialog(tab = "Advanced", group = "Limiter"), + Evaluate=true, + HideResult=true); + + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput p_input(final unit="Pa") if + (boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure and + use_pInput) + "Input for pressure" + annotation (Placement(transformation(extent={{-120,30},{-80,70}}), + iconTransformation(extent={{-22,40},{-2,60}}))); + + Modelica.Blocks.Interfaces.RealInput m_flow_input(final unit="kg/s") if + (boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate and + use_mFlowInput) + "Input for mass flow rate" + annotation (Placement(transformation(extent={{-120,0},{-80,40}}), + iconTransformation(extent={{-22,10},{-2,30}}))); + + Modelica.Blocks.Interfaces.RealInput V_flow_input(final unit="m3/s") if + (boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate and + use_VFlowInput) + "Input for volume flow rate" + annotation (Placement(transformation(extent={{-120,0},{-80,40}}), + iconTransformation(extent={{-22,10},{-2,30}}))); + + Modelica.Blocks.Interfaces.RealInput h_input(final unit="J/kg") if + (boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy and + use_hInput) + "Input for specific enthalpy" + annotation (Placement(transformation(extent={{-120,0},{-80,-40}}), + iconTransformation(extent={{-22,-30},{-2,-10}}))); + + Modelica.Blocks.Interfaces.RealInput T_input(final unit="K") if + (boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature and + use_TInput) + "Input for temperature" + annotation (Placement(transformation(extent={{-120,0},{-80,-40}}), + iconTransformation(extent={{-22,-30},{-2,-10}}))); + + Modelica.Blocks.Interfaces.RealInput[no_components] X_input(each final unit="kg/kg") if + (boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions and + use_XInput) "Input for mass fractions" + annotation (Placement(transformation(extent={{-120,-30},{-80,-70}}), + iconTransformation(extent={{-22,-60},{-2,-40}}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput p_internal(final unit="Pa") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput m_flow_internal(final unit="kg/s") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput V_flow_internal(final unit="m3/s") + "Needed for connecting to conditional connector"; + + Modelica.Blocks.Interfaces.RealInput h_internal(final unit="J/kg") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput T_internal(final unit="K") + "Needed for connecting to conditional connector"; + + Modelica.Blocks.Interfaces.RealInput[no_components] X_internal(each final unit="kg/kg") + "Needed for connecting to conditional connector"; + + // + // Definition of protected variables + // + Modelica.Units.SI.Density d_in + "Density calculated with pressure, specific enthalpy, and mass fractions + entering the port"; + Modelica.Units.SI.Density d_out + "Density calculated with pressure, specific enthalpy, and mass fractions + leaving the port"; + Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy calculated with pressure at port, temperature, and mass + fractions"; + + // + // Definition of ports + // +public + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port + constrainedby SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid port" + annotation (Placement(transformation(extent={{-4,-4},{4,4}}))); + +equation + // + // Connectors + // + connect(p_input,p_internal); + connect(m_flow_input,m_flow_internal); + connect(V_flow_input,V_flow_internal); + + connect(h_input,h_internal); + connect(T_input,T_internal); + + connect(X_input,X_internal); + + if not use_pInput then + p_internal = p_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_mFlowInput then + m_flow_internal = m_flow_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_VFlowInput then + V_flow_internal = V_flow_fixed + "Needed for connecting to conditional connector"; + end if; + + if not use_hInput then + h_internal = h_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_TInput then + T_internal = T_fixed + "Needed for connecting to conditional connector"; + end if; + + if not use_XInput then + X_internal = X_fixed + "Needed for connecting to conditional connector"; + end if; + + // + // Properties at port + // + if boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure then + port.p = p_internal + "Pressure at port"; + + elseif boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate then + port.m_flow = m_flow_internal + "Mass flow rate at port"; + + else + if not avoid_events then + port.m_flow = V_flow_internal * + SorpLib.Numerics.regStep( + x=V_flow_internal, + y1=d_in, + y2=d_out, + x_small=m_flow_small*1e-3) + "Mass flow rate at port"; + + else + port.m_flow = V_flow_internal * + SorpLib.Numerics.regStep_noEvent( + x=V_flow_internal, + y1=d_in, + y2=d_out, + x_small=m_flow_small*1e-3) + "Mass flow rate at port"; + + end if; + end if; + + if boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy then + port.h_outflow = h_internal + "Specific enthalpy at port"; + + else + port.h_outflow = h + "Specific enthalpy at port"; + + end if; + + if boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions then + port.Xi_outflow = X_internal[1:no_components-1] + "Independent mass fractions at port"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model can be used to specify either the pressure or mass flow rate as well +as the specific enthalpy and independent mass fractions at a fluid port. +<br/><br/> +Models that inherit properties from this partial model must augment equations for +the densities <i>d_in</i>/<i>d_out</i> and specific enthalpy <i>h</i>. Furthermore, +the boundary type <i>boundaryTypeStreamMassFractions</i> must either be fixed or +equations must be augmented for the case of given dry air mass fractions and +relative humidity. +</p> + +<h4>Options</h4> +<ul> + <li> + <i>boundaryTypePotentialFlow</i>: Defines if pressure, mass flow rate, or volume + flow rate are prescribed. + </li> + <li> + <i>boundaryTypeStreamEnthalpy</i>: Defines if specific enthalpy or temperature + are prescribed. + </li> + <li> + <i>boundaryTypeStreamMassFractions</i>: Defines if mass fractions or mass fractions + of dry air and relative humidity are prescribed. + </li> +</ul> +</html>",revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialFluidSource; diff --git a/SorpLib/Basics/Sources/BaseClasses/package.mo b/SorpLib/Basics/Sources/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..90ce165891ae13e3e3750514fc405bc1006ff4ee --- /dev/null +++ b/SorpLib/Basics/Sources/BaseClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Basics.Sources; +package BaseClasses "Base classes used to create new sources" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial models. These partial models contain fundamental +definitions for thermal and fluid source models. The content of this package is +only of interest when adding new source models to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Basics/Sources/BaseClasses/package.order b/SorpLib/Basics/Sources/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..0d59b0607ba22fd7af387d9a71930fb55336bcd2 --- /dev/null +++ b/SorpLib/Basics/Sources/BaseClasses/package.order @@ -0,0 +1 @@ +PartialFluidSource diff --git a/SorpLib/Basics/Sources/Fluids/GasSource.mo b/SorpLib/Basics/Sources/Fluids/GasSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..1e2a701c4e91830b72afc88ec5de46e8dbdd4683 --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/GasSource.mo @@ -0,0 +1,113 @@ +within SorpLib.Basics.Sources.Fluids; +model GasSource "Boundary model of an ideal gas or ideal gas mixture" + extends SorpLib.Basics.Sources.BaseClasses.PartialFluidSource( + redeclare final Interfaces.FluidPorts.GasPort_in port, + final no_components = Medium.nX, + final boundaryTypeStreamMassFractions= + SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + X_fixed=Medium.reference_X); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas or ideal gas mixture" + annotation (Dialog(tab="General", group="Boundary Type"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculate properties + // + if boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate then + d_in = Medium.density_phX( + p=port.p, + h=inStream(port.h_outflow), + X=cat(1, inStream(port.Xi_outflow), {1-sum(inStream(port.Xi_outflow))})) + "Density calculated with pressure, specific enthalpy, and mass fractions + entering the port"; + + d_out =if boundaryTypeStreamEnthalpy <> + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature then + Medium.density_phX( + p=port.p, + h=port.h_outflow, + X=cat(1, port.Xi_outflow, {1-sum(port.Xi_outflow)})) else + Medium.density_pTX( + p=port.p, + T=T_internal, + X=cat(1, port.Xi_outflow, {1-sum(port.Xi_outflow)})) + "Density calculated with pressure, specific enthalpy or temperature, and + mass fractions leaving the port"; + + else + d_in = m_flow_fixed / V_flow_fixed + "Density calculated with pressure, specific enthalpy, and mass fractions + entering the port: Not needed, so set dummy value"; + d_out = m_flow_fixed / V_flow_fixed + "Density calculated with pressure, specific enthalpy, and mass fractions + leaving the port: Not needed, so set dummy value"; + + end if; + + if boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature then + h = Medium.specificEnthalpy_pTX( + p=port.p, + T=T_internal, + X=X_internal) + "Specific enthalpy calculated with pressure at port and temperature"; + + else + h = h_fixed + "Specific enthalpy calculated with pressure at port and temperature: Not + needed, so set dummy value"; + + end if; + + // + // Annotations + // + annotation (Icon(graphics={Rectangle( + extent={{-2,80},{2,-80}}, + lineColor={244,125,35}, + lineThickness=0.5, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This model can be used to specify either the pressure or mass flow rate as well as +the specific enthalpy and independent mass fractions at an ideal gas or gas mixture +port. +</p> + +<h4>Options</h4> +<ul> + <li> + <i>boundaryTypePotentialFlow</i>: Defines if pressure, mass flow rate, or volume + flow rate are prescribed. + </li> + <li> + <i>boundaryTypeStreamEnthalpy</i>: Defines if specific enthalpy or temperature + are prescribed. + </li> +</ul> + +</html>",revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasSource; diff --git a/SorpLib/Basics/Sources/Fluids/GasVaporMixtureSource.mo b/SorpLib/Basics/Sources/Fluids/GasVaporMixtureSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..cb24312fc0eab306d56b52c55e95b6f9b41a2241 --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/GasVaporMixtureSource.mo @@ -0,0 +1,232 @@ +within SorpLib.Basics.Sources.Fluids; +model GasVaporMixtureSource + "Boundary model of an ideal gas-vapor mixture" + extends SorpLib.Basics.Sources.BaseClasses.PartialFluidSource( + redeclare final Interfaces.FluidPorts.GasPort_in port, + final no_components = Medium.nX, + X_fixed=Medium.reference_X); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture + "Medium model of the ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Boundary Type"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding stream variables of mass fractions + // + parameter Boolean use_xDryInput = false + "=true, if xDry is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Stream Variables - Mass Fractions", + enable=(boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.DryMassFractionsPhi)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.MassFraction[no_components-1] xDry_fixed= + Medium.reference_X[1:no_components-1]/sum(Medium.reference_X[1:no_components-1]) + "Fixed mass fractions of dry air components (per dry air component mass) at boundary" + annotation (Dialog(tab="General",group="Stream Variables - Mass Fractions", + enable=(boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.DryMassFractionsPhi) + and not use_xDryInput)); + + parameter Boolean use_phiInput = false + "=true, if phi is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Stream Variables - Mass Fractions", + enable=(boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.DryMassFractionsPhi)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Real phi_fixed(unit="1") = 0.5 + "Fixed relative humidity at boundary" + annotation (Dialog(tab="General",group="Stream Variables - Mass Fractions", + enable=(boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.DryMassFractionsPhi) + and not use_phiInput)); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput[no_components-1] + XDry_input(each final unit="kg/kg") if + (boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.DryMassFractionsPhi and + use_xDryInput) + "Input for mass fractions of dry gas components" + annotation (Placement(transformation(extent={{-120,-30},{-80,-70}}), + iconTransformation(extent={{-22,-60},{-2,-40}}))); + Modelica.Blocks.Interfaces.RealInput phi_input(final unit="1") if + (boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.DryMassFractionsPhi and + use_phiInput) + "Input for relative humidity" + annotation (Placement(transformation(extent={{-120,-60},{-80,-100}}), + iconTransformation(extent={{-22,-90},{-2,-70}}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput[no_components-1] xDry_internal(each final unit="kg/kg") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput phi_internal(final unit="1") + "Needed for connecting to conditional connector"; + + // + // Definition of protected variables + // + Modelica.Units.SI.MassFraction[no_components] X + "Mass fractions calculated with pressure and specific enthalpy leaving the + port as well as dry air mass fractions and relative humidity"; + +equation + // + // Assertions + // + if boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.DryMassFractionsPhi then + assert((boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature) and + (boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure), + "Can only use mass fractions of dry air components and relative humidity " + + "if pressure and temperature are prescribed at the boundary model!", + level = AssertionLevel.error); + + end if; + + // + // Connectors + // + connect(XDry_input,xDry_internal); + connect(phi_input,phi_internal); + + if not use_xDryInput then + xDry_internal = xDry_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_phiInput then + phi_internal = phi_fixed + "Needed for connecting to conditional connector"; + end if; + + // + // Calculate properties + // + if boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate then + d_in = Medium.density_phX( + p=port.p, + h=inStream(port.h_outflow), + X=cat(1, inStream(port.Xi_outflow), {1-sum(inStream(port.Xi_outflow))})) + "Density calculated with pressure, specific enthalpy, and mass fractions + entering the port"; + + d_out =if boundaryTypeStreamEnthalpy <> + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature then + Medium.density_phX( + p=port.p, + h=port.h_outflow, + X=cat(1, port.Xi_outflow, {1-sum(port.Xi_outflow)})) else + Medium.density_pTX( + p=port.p, + T=T_internal, + X=cat(1, port.Xi_outflow, {1-sum(port.Xi_outflow)})) + "Density calculated with pressure, specific enthalpy or temperature, and + mass fractions leaving the port"; + + else + d_in = m_flow_fixed / V_flow_fixed + "Density calculated with pressure, specific enthalpy, and mass fractions + entering the port: Not needed, so set dummy value"; + d_out = m_flow_fixed / V_flow_fixed + "Density calculated with pressure, specific enthalpy, and mass fractions + leaving the port: Not needed, so set dummy value"; + + end if; + + if boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature then + h = Medium.specificEnthalpy_pTX( + p=port.p, + T=T_internal, + X=X_internal) + "Specific enthalpy calculated with pressure at port and temperature"; + + else + h = h_fixed + "Specific enthalpy calculated with pressure at port and temperature: Not + needed, so set dummy value"; + + end if; + + if boundaryTypeStreamMassFractions == + SorpLib.Choices.BoundaryFluidStreamMassFractions.DryMassFractionsPhi then + X = Medium.massFractions_pTxDryPhi( + p = port.p, + T=T_internal, + x=xDry_internal, + phi=phi_internal) + "Mass fractions calculated with pressure and specific enthalpy leaving the + port as well as dry air mass fractions and relative humidity"; + + port.Xi_outflow = X[1:no_components-1] + "Independent mass fractions at port"; + + else + X = X_fixed + "Mass fractions calculated with pressure and specific enthalpy leaving the + port as well as dry air mass fractions and relative humidity: Not needed, + so set dummy values"; + + end if; + + // + // Annotations + // + annotation (Icon(graphics={Rectangle( + extent={{-2,80},{2,-80}}, + lineColor={244,125,35}, + lineThickness=0.5, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This model can be used to specify either the pressure or mass flow rate as well as +the specific enthalpy and independent mass fractions at an ideal gas-vapor mixture +port. +</p> + +<h4>Options</h4> +<ul> + <li> + <i>boundaryTypePotentialFlow</i>: Defines if pressure, mass flow rate, or volume + flow rate are prescribed. + </li> + <li> + <i>boundaryTypeStreamEnthalpy</i>: Defines if specific enthalpy or temperature + are prescribed. + </li> + <li> + <i>boundaryTypeStreamMassFractions</i>: Defines if mass fractions or mass fractions + of dry air and relative humidity are prescribed. + </li></ul> + +</html>",revisions="<html> +<ul> + <li> + December 5, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasVaporMixtureSource; diff --git a/SorpLib/Basics/Sources/Fluids/LiquidSource.mo b/SorpLib/Basics/Sources/Fluids/LiquidSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..4101b16ef477726deda61edf24d3236270759725 --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/LiquidSource.mo @@ -0,0 +1,112 @@ +within SorpLib.Basics.Sources.Fluids; +model LiquidSource + "Boundary model of an (ideal) liquid" + extends SorpLib.Basics.Sources.BaseClasses.PartialFluidSource( + redeclare final Interfaces.FluidPorts.LiquidPort_in port, + final no_components = Medium.nX, + final boundaryTypeStreamMassFractions= + SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + X_fixed=Medium.reference_X); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Boundary Type"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculate properties + // + if boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate then + d_in = Medium.density_phX( + p=port.p, + h=inStream(port.h_outflow), + X=cat(1, inStream(port.Xi_outflow), {1-sum(inStream(port.Xi_outflow))})) + "Density calculated with pressure, specific enthalpy, and mass fractions + entering the port"; + + d_out =if boundaryTypeStreamEnthalpy <> + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature then + Medium.density_phX( + p=port.p, + h=port.h_outflow, + X=cat(1, port.Xi_outflow, {1-sum(port.Xi_outflow)})) else + Medium.density_pTX( + p=port.p, + T=T_internal, + X=cat(1, port.Xi_outflow, {1-sum(port.Xi_outflow)})) + "Density calculated with pressure, specific enthalpy or temperature, and + mass fractions leaving the port"; + + else + d_in = m_flow_fixed / V_flow_fixed + "Density calculated with pressure, specific enthalpy, and mass fractions + entering the port: Not needed, so set dummy value"; + d_out = m_flow_fixed / V_flow_fixed + "Density calculated with pressure, specific enthalpy, and mass fractions + leaving the port: Not needed, so set dummy value"; + + end if; + + if boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature then + h = Medium.specificEnthalpy_pTX( + p=port.p, + T=T_internal, + X=X_internal) + "Specific enthalpy calculated with pressure at port and temperature"; + + else + h = h_fixed + "Specific enthalpy calculated with pressure at port and temperature: Not + needed, so set dummy value"; + + end if; + + // + // Annotations + // + annotation (Icon(graphics={Rectangle( + extent={{-2,80},{2,-80}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This model can be used to specify either the pressure or mass flow rate as well as +the specific enthalpy and independent mass fractions at an (ideal) liquid port. +</p> + +<h4>Options</h4> +<ul> + <li> + <i>boundaryTypePotentialFlow</i>: Defines if pressure, mass flow rate, or volume + flow rate are prescribed. + </li> + <li> + <i>boundaryTypeStreamEnthalpy</i>: Defines if specific enthalpy or temperature + are prescribed. + </li> +</ul> + +</html>",revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end LiquidSource; diff --git a/SorpLib/Basics/Sources/Fluids/Tester/Test_GasSource.mo b/SorpLib/Basics/Sources/Fluids/Tester/Test_GasSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..ba20feb7880fb8e1e3bc378d2006a242be751db1 --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/Tester/Test_GasSource.mo @@ -0,0 +1,253 @@ +within SorpLib.Basics.Sources.Fluids.Tester; +model Test_GasSource + "Tester for ideal gas or ideal gas mixture source" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasSource sourceA_pFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + p_fixed=1000000) "Source A: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,70},{-30,90}}))); + + SorpLib.Basics.Sources.Fluids.GasSource sourceB_MFlowFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=0.2, + T_fixed=323.15) "Source B: Fixed mass flow rate and fixed temperature" + annotation (Placement(transformation(extent={{30,70},{50,90}}))); + + SorpLib.Basics.Sources.Fluids.GasSource sourceA_pFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=1000000, + T_fixed=303.15) "Source A: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,50},{-30,70}}))); + SorpLib.Basics.Sources.Fluids.GasSource sourceB_MFlowFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + m_flow_fixed=-0.2, + h_fixed=400e3) "Source B: Fixed mass flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{30,50},{50,70}}))); + + SorpLib.Basics.Sources.Fluids.GasSource sourceA_VFlowFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + V_flow_fixed(displayUnit="l/min") = -0.016666666666667, + T_fixed=348.15) "Source A: Fixed volume flow rate and fixed temperature" + annotation (Placement(transformation(extent={{-50,30},{-30,50}}))); + SorpLib.Basics.Sources.Fluids.GasSource sourceB_pFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=500000, + T_fixed=283.15) "Source B: Fixed pressure and fixed temperature" + annotation (Placement(transformation(extent={{30,30},{50,50}}))); + + SorpLib.Basics.Sources.Fluids.GasSource sourceA_VFlowFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + V_flow_fixed(displayUnit="l/min") = -0.016666666666667, + h_fixed=275e3) + "Source A: Fixed volume flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,10},{-30,30}}))); + SorpLib.Basics.Sources.Fluids.GasSource sourceB_pFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + p_fixed=500000, + h_fixed=300e3) "Source B: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{30,10},{50,30}}))); + + SorpLib.Basics.Sources.Fluids.GasSource sourceA_pVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_pInput=true) + "Source A: Variable pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-30},{-30,-10}}))); + SorpLib.Basics.Sources.Fluids.GasSource sourceB_MFlowVar_TVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true) + "Source B: Variable mass flow rate and variable temperature" + annotation (Placement(transformation(extent={{50,-30},{30,-10}}))); + + SorpLib.Basics.Sources.Fluids.GasSource sourceA_pVar_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=303.15) + "Source A: Variable pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-50},{-30,-30}}))); + SorpLib.Basics.Sources.Fluids.GasSource sourceB_MFlowVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_mFlowInput=true, + h_fixed=400e3) + "Source B: Variable mass flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{50,-50},{30,-30}}))); + + SorpLib.Basics.Sources.Fluids.GasSource sourceA_VFlowVar_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_VFlowInput=true, + V_flow_fixed(displayUnit="l/min"), + T_fixed=348.15) + "Source A: Variable volume flow rate and fixed temperature" + annotation (Placement(transformation(extent={{-50,-70},{-30,-50}}))); + SorpLib.Basics.Sources.Fluids.GasSource sourceB_pFixed_TVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=500000, + use_TInput=true) + "Source B: Fixed pressure and variable temperature" + annotation (Placement(transformation(extent={{50,-70},{30,-50}}))); + + SorpLib.Basics.Sources.Fluids.GasSource sourceA_VFlowVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_VFlowInput=true, + V_flow_fixed(displayUnit="l/min"), + h_fixed=275e3) + "Source A: Variable volume flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-90},{-30,-70}}))); + SorpLib.Basics.Sources.Fluids.GasSource sourceB_pFixed_hVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + p_fixed=500000, + use_hInput=true) "Source B: Fixed pressure and variable specific enthalpy" + annotation (Placement(transformation(extent={{50,-90},{30,-70}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Ramp input_pVar( + height=10e5 - 1e5, + duration=2500, + offset=1e5, + startTime=0) + "Ramp to simulate input signal of pressure" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_mFlowVar( + height=2, + duration=2500, + offset=-1, + startTime=0) "Ramp to simulate input signal of mass flow rate" + annotation (Placement(transformation(extent={{80,-30},{60,-10}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_VFlowVar( + height=40000/60000, + duration=2500, + offset=-20000/60000, + startTime=0) "Ramp to simulate input signal of volume flow rate" + annotation (Placement(transformation(extent={{-80,-80},{-60,-60}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_hVar( + height=1e5, + duration=2500, + offset=273e3, + startTime=0) + "Ramp to simulate input signal of specific enthalpy" + annotation (Placement(transformation(extent={{80,-90},{60,-70}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_TVar( + height=90, + duration=2500, + offset=283.15, + startTime=0) "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{80,-60},{60,-40}})), + HideResult=true); + +equation + // + // Connections + // + connect(sourceA_pFixed_hFixed.port, sourceB_MFlowFixed_TFixed.port) + annotation (Line( + points={{-40,80},{40,80}}, + color={244,125,35}, + thickness=1)); + connect(sourceB_MFlowFixed_hFixed.port, sourceA_pFixed_TFixed.port) + annotation (Line( + points={{40,60},{-40,60}}, + color={244,125,35}, + thickness=1)); + connect(sourceA_VFlowFixed_TFixed.port, sourceB_pFixed_TFixed.port) + annotation (Line( + points={{-40,40},{40,40}}, + color={244,125,35}, + thickness=1)); + connect(sourceB_pFixed_hFixed.port, sourceA_VFlowFixed_hFixed.port) + annotation (Line( + points={{40,20},{-40,20}}, + color={244,125,35}, + thickness=1)); + connect(sourceA_pVar_hFixed.port, sourceB_MFlowVar_TVar.port) annotation ( + Line( + points={{-40,-20},{40,-20}}, + color={244,125,35}, + thickness=1)); + connect(sourceB_MFlowVar_hFixed.port, sourceA_pVar_TFixed.port) annotation ( + Line( + points={{40,-40},{-40,-40}}, + color={244,125,35}, + thickness=1)); + connect(sourceA_VFlowVar_TFixed.port, sourceB_pFixed_TVar.port) annotation ( + Line( + points={{-40,-60},{40,-60}}, + color={244,125,35}, + thickness=1)); + connect(sourceB_pFixed_hVar.port, sourceA_VFlowVar_hFixed.port) annotation ( + Line( + points={{40,-80},{-40,-80}}, + color={244,125,35}, + thickness=1)); + + connect(input_pVar.y, sourceA_pVar_hFixed.p_input) annotation (Line(points={{-59,-30}, + {-50,-30},{-50,-15},{-41.2,-15}}, color={0,0,127})); + connect(input_pVar.y, sourceA_pVar_TFixed.p_input) annotation (Line(points={{-59,-30}, + {-50,-30},{-50,-35},{-41.2,-35}}, color={0,0,127})); + connect(input_VFlowVar.y, sourceA_VFlowVar_TFixed.V_flow_input) annotation ( + Line(points={{-59,-70},{-50,-70},{-50,-58},{-41.2,-58}}, color={0,0,127})); + connect(input_VFlowVar.y, sourceA_VFlowVar_hFixed.V_flow_input) annotation ( + Line(points={{-59,-70},{-50,-70},{-50,-78},{-41.2,-78}}, color={0,0,127})); + connect(input_mFlowVar.y, sourceB_MFlowVar_TVar.m_flow_input) annotation ( + Line(points={{59,-20},{54,-20},{54,-18},{41.2,-18}}, color={0,0,127})); + connect(input_mFlowVar.y, sourceB_MFlowVar_hFixed.m_flow_input) annotation ( + Line(points={{59,-20},{54,-20},{54,-38},{41.2,-38}}, color={0,0,127})); + connect(input_TVar.y, sourceB_MFlowVar_TVar.T_input) annotation (Line(points={{59,-50}, + {50,-50},{50,-22},{41.2,-22}}, color={0,0,127})); + connect(input_TVar.y, sourceB_pFixed_TVar.T_input) annotation (Line(points={{59,-50}, + {50,-50},{50,-62},{41.2,-62}}, color={0,0,127})); + connect(input_hVar.y, sourceB_pFixed_hVar.h_input) annotation (Line(points={{59,-80}, + {50,-80},{50,-82},{41.2,-82}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the ideal gas or gas mixture source model used to prescribe +properties at a gas fluid port. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasSource; diff --git a/SorpLib/Basics/Sources/Fluids/Tester/Test_GasVaporMixtureSource.mo b/SorpLib/Basics/Sources/Fluids/Tester/Test_GasVaporMixtureSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..d7dce4fdc9fe941ae3996fa8cc81294c160253f5 --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/Tester/Test_GasVaporMixtureSource.mo @@ -0,0 +1,284 @@ +within SorpLib.Basics.Sources.Fluids.Tester; +model Test_GasVaporMixtureSource + "Tester for ideal gas-vapor mixture source" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceA_pFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + p_fixed=1000000) "Source A: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,70},{-30,90}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceB_MFlowFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + m_flow_fixed=0.2, + T_fixed=323.15) "Source B: Fixed mass flow rate and fixed temperature" + annotation (Placement(transformation(extent={{30,70},{50,90}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceA_pFixed_TFixed_xDryFixed_phiFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.DryMassFractionsPhi, + p_fixed=1000000, + T_fixed=303.15) + "Source A: Fixed pressure, fixed specific enthalpy, fixed dry mass fractions, and fixed relative humidity" + annotation (Placement(transformation(extent={{-50,50},{-30,70}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceB_MFlowFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + m_flow_fixed=-0.2, + h_fixed=400e3) "Source B: Fixed mass flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{30,50},{50,70}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceA_VFlowFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + V_flow_fixed(displayUnit="l/min") = -0.016666666666667, + T_fixed=348.15) "Source A: Fixed volume flow rate and fixed temperature" + annotation (Placement(transformation(extent={{-50,30},{-30,50}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceB_pFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + p_fixed=500000, + T_fixed=283.15) "Source B: Fixed pressure and fixed temperature" + annotation (Placement(transformation(extent={{30,30},{50,50}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceA_VFlowFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + V_flow_fixed(displayUnit="l/min") = -0.016666666666667, + h_fixed=275e3) + "Source A: Fixed volume flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,10},{-30,30}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceB_pFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + p_fixed=500000, + h_fixed=300e3) "Source B: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{30,10},{50,30}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceA_pVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + use_pInput=true) + "Source A: Variable pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-30},{-30,-10}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceB_MFlowVar_TVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + use_mFlowInput=true, + use_TInput=true) + "Source B: Variable mass flow rate and variable temperature" + annotation (Placement(transformation(extent={{50,-30},{30,-10}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceA_pVar_TFixed_xDryFixed_phiVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.DryMassFractionsPhi, + use_pInput=true, + T_fixed=303.15, + use_phiInput=true) + "Source A: Variable pressure, fixed specific enthalpy, fixed dry air mass fractions, and variable relative humidity" + annotation (Placement(transformation(extent={{-50,-50},{-30,-30}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceB_MFlowVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + use_mFlowInput=true, + h_fixed=400e3) + "Source B: Variable mass flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{50,-50},{30,-30}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceA_VFlowVar_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + use_VFlowInput=true, + V_flow_fixed(displayUnit="l/min"), + T_fixed=348.15) + "Source A: Variable volume flow rate and fixed temperature" + annotation (Placement(transformation(extent={{-50,-70},{-30,-50}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceB_pFixed_TVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + p_fixed=500000, + use_TInput=true) + "Source B: Fixed pressure and variable temperature" + annotation (Placement(transformation(extent={{50,-70},{30,-50}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceA_VFlowVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + use_VFlowInput=true, + V_flow_fixed(displayUnit="l/min"), + h_fixed=275e3) + "Source A: Variable volume flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-90},{-30,-70}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource sourceB_pFixed_hVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + p_fixed=500000, + use_hInput=true) "Source B: Fixed pressure and variable specific enthalpy" + annotation (Placement(transformation(extent={{50,-90},{30,-70}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Ramp input_pVar( + height=10e5 - 1e5, + duration=2500, + offset=1e5, + startTime=0) "Ramp to simulate input signal of pressure" + annotation (Placement(transformation(extent={{-80,-30},{-60,-10}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_mFlowVar( + height=2, + duration=2500, + offset=-1, + startTime=0) "Ramp to simulate input signal of mass flow rate" + annotation (Placement(transformation(extent={{80,-30},{60,-10}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_VFlowVar( + height=40000/60000, + duration=2500, + offset=-20000/60000, + startTime=0) "Ramp to simulate input signal of volume flow rate" + annotation (Placement(transformation(extent={{-80,-90},{-60,-70}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_hVar( + height=9e4, + duration=2500, + offset=1e4, + startTime=0) + "Ramp to simulate input signal of specific enthalpy" + annotation (Placement(transformation(extent={{80,-90},{60,-70}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_TVar( + height=90, + duration=2500, + offset=283.15, + startTime=0) "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{80,-60},{60,-40}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_phiVar( + height=1, + duration=2500, + offset=0, + startTime=0) "Ramp to simulate input signal of relative humidity" + annotation (Placement(transformation(extent={{-80,-60},{-60,-40}})), + HideResult=true); + +equation + // + // Connections + // + connect(sourceA_pFixed_hFixed.port, sourceB_MFlowFixed_TFixed.port) + annotation (Line( + points={{-40,80},{40,80}}, + color={244,125,35}, + thickness=1)); + connect(sourceB_MFlowFixed_hFixed.port, + sourceA_pFixed_TFixed_xDryFixed_phiFixed.port) annotation (Line( + points={{40,60},{-40,60}}, + color={244,125,35}, + thickness=1)); + connect(sourceA_VFlowFixed_TFixed.port, sourceB_pFixed_TFixed.port) + annotation (Line( + points={{-40,40},{40,40}}, + color={244,125,35}, + thickness=1)); + connect(sourceB_pFixed_hFixed.port, sourceA_VFlowFixed_hFixed.port) + annotation (Line( + points={{40,20},{-40,20}}, + color={244,125,35}, + thickness=1)); + connect(sourceA_pVar_hFixed.port, sourceB_MFlowVar_TVar.port) annotation ( + Line( + points={{-40,-20},{40,-20}}, + color={244,125,35}, + thickness=1)); + connect(sourceB_MFlowVar_hFixed.port, sourceA_pVar_TFixed_xDryFixed_phiVar.port) + annotation (Line( + points={{40,-40},{-40,-40}}, + color={244,125,35}, + thickness=1)); + connect(sourceA_VFlowVar_TFixed.port, sourceB_pFixed_TVar.port) annotation ( + Line( + points={{-40,-60},{40,-60}}, + color={244,125,35}, + thickness=1)); + connect(sourceB_pFixed_hVar.port, sourceA_VFlowVar_hFixed.port) annotation ( + Line( + points={{40,-80},{-40,-80}}, + color={244,125,35}, + thickness=1)); + + connect(input_pVar.y, sourceA_pVar_hFixed.p_input) annotation (Line(points={{-59,-20}, + {-50,-20},{-50,-15},{-41.2,-15}}, color={0,0,127})); + connect(input_pVar.y, sourceA_pVar_TFixed_xDryFixed_phiVar.p_input) + annotation (Line(points={{-59,-20},{-50,-20},{-50,-35},{-41.2,-35}}, color={ + 0,0,127})); + connect(input_VFlowVar.y, sourceA_VFlowVar_TFixed.V_flow_input) annotation ( + Line(points={{-59,-80},{-50,-80},{-50,-58},{-41.2,-58}}, color={0,0,127})); + connect(input_VFlowVar.y, sourceA_VFlowVar_hFixed.V_flow_input) annotation ( + Line(points={{-59,-80},{-50,-80},{-50,-78},{-41.2,-78}}, color={0,0,127})); + connect(input_mFlowVar.y, sourceB_MFlowVar_TVar.m_flow_input) annotation ( + Line(points={{59,-20},{54,-20},{54,-18},{41.2,-18}}, color={0,0,127})); + connect(input_mFlowVar.y, sourceB_MFlowVar_hFixed.m_flow_input) annotation ( + Line(points={{59,-20},{54,-20},{54,-38},{41.2,-38}}, color={0,0,127})); + connect(input_TVar.y, sourceB_MFlowVar_TVar.T_input) annotation (Line(points={{59,-50}, + {50,-50},{50,-22},{41.2,-22}}, color={0,0,127})); + connect(input_TVar.y, sourceB_pFixed_TVar.T_input) annotation (Line(points={{59,-50}, + {50,-50},{50,-62},{41.2,-62}}, color={0,0,127})); + connect(input_hVar.y, sourceB_pFixed_hVar.h_input) annotation (Line(points={{59,-80}, + {50,-80},{50,-82},{41.2,-82}}, color={0,0,127})); + connect(input_phiVar.y, sourceA_pVar_TFixed_xDryFixed_phiVar.phi_input) + annotation (Line(points={{-59,-50},{-50,-50},{-50,-48},{-41.2,-48}}, color={ + 0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the ideal gas-vapor mixture source model used to prescribe +properties at a gas fluid port. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 5, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasVaporMixtureSource; diff --git a/SorpLib/Basics/Sources/Fluids/Tester/Test_LiquidSource.mo b/SorpLib/Basics/Sources/Fluids/Tester/Test_LiquidSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..248e27846a61b360097d6b6f9bf20d9549ef4b68 --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/Tester/Test_LiquidSource.mo @@ -0,0 +1,252 @@ +within SorpLib.Basics.Sources.Fluids.Tester; +model Test_LiquidSource "Tester for ideal liquid source" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource sourceA_pFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + p_fixed=1000000) "Source A: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,70},{-30,90}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource sourceB_MFlowFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=0.2, + T_fixed=323.15) "Source B: Fixed mass flow rate and fixed temperature" + annotation (Placement(transformation(extent={{30,70},{50,90}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource sourceA_pFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=1000000, + T_fixed=303.15) "Source A: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,50},{-30,70}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource sourceB_MFlowFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + m_flow_fixed=-0.2, + h_fixed=400e3) "Source B: Fixed mass flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{30,50},{50,70}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource sourceA_VFlowFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + V_flow_fixed(displayUnit="l/min") = -0.00016666666666667, + T_fixed=348.15) "Source A: Fixed volume flow rate and fixed temperature" + annotation (Placement(transformation(extent={{-50,30},{-30,50}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource sourceB_pFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=500000, + T_fixed=283.15) "Source B: Fixed pressure and fixed temperature" + annotation (Placement(transformation(extent={{30,30},{50,50}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource sourceA_VFlowFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + V_flow_fixed(displayUnit="l/min") = -0.00016666666666667, + h_fixed=275e3) + "Source A: Fixed volume flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,10},{-30,30}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource sourceB_pFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + p_fixed=500000, + h_fixed=300e3) "Source B: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{30,10},{50,30}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource sourceA_pVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_pInput=true) + "Source A: Variable pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-30},{-30,-10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource sourceB_MFlowVar_TVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true) + "Source B: Variable mass flow rate and variable temperature" + annotation (Placement(transformation(extent={{50,-30},{30,-10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource sourceA_pVar_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=303.15) + "Source A: Variable pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-50},{-30,-30}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource sourceB_MFlowVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_mFlowInput=true, + h_fixed=400e3) + "Source B: Variable mass flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{50,-50},{30,-30}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource sourceA_VFlowVar_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_VFlowInput=true, + V_flow_fixed(displayUnit="l/min"), + T_fixed=348.15) + "Source A: Variable volume flow rate and fixed temperature" + annotation (Placement(transformation(extent={{-50,-70},{-30,-50}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource sourceB_pFixed_TVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=500000, + use_TInput=true) + "Source B: Fixed pressure and variable temperature" + annotation (Placement(transformation(extent={{50,-70},{30,-50}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource sourceA_VFlowVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_VFlowInput=true, + V_flow_fixed(displayUnit="l/min"), + h_fixed=275e3) + "Source A: Variable volume flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-90},{-30,-70}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource sourceB_pFixed_hVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + p_fixed=500000, + use_hInput=true) "Source B: Fixed pressure and variable specific enthalpy" + annotation (Placement(transformation(extent={{50,-90},{30,-70}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Ramp input_pVar( + height=10e5 - 1e5, + duration=2500, + offset=1e5, + startTime=0) + "Ramp to simulate input signal of pressure" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_mFlowVar( + height=2, + duration=2500, + offset=-1, + startTime=0) "Ramp to simulate input signal of mass flow rate" + annotation (Placement(transformation(extent={{80,-30},{60,-10}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_VFlowVar( + height=40/60000, + duration=2500, + offset=-20/60000, + startTime=0) "Ramp to simulate input signal of volume flow rate" + annotation (Placement(transformation(extent={{-80,-80},{-60,-60}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_hVar( + height=3e5, + duration=2500, + offset=1e5, + startTime=0) + "Ramp to simulate input signal of specific enthalpy" + annotation (Placement(transformation(extent={{80,-90},{60,-70}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_TVar( + height=90, + duration=2500, + offset=283.15, + startTime=0) "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{80,-60},{60,-40}})), + HideResult=true); + +equation + // + // Connections + // + connect(sourceA_pFixed_hFixed.port, sourceB_MFlowFixed_TFixed.port) + annotation (Line( + points={{-40,80},{40,80}}, + color={28,108,200}, + thickness=1)); + connect(sourceB_MFlowFixed_hFixed.port, sourceA_pFixed_TFixed.port) + annotation (Line( + points={{40,60},{-40,60}}, + color={28,108,200}, + thickness=1)); + connect(sourceA_VFlowFixed_TFixed.port, sourceB_pFixed_TFixed.port) + annotation (Line( + points={{-40,40},{40,40}}, + color={28,108,200}, + thickness=1)); + connect(sourceB_pFixed_hFixed.port, sourceA_VFlowFixed_hFixed.port) + annotation (Line( + points={{40,20},{-40,20}}, + color={28,108,200}, + thickness=1)); + connect(sourceA_pVar_hFixed.port, sourceB_MFlowVar_TVar.port) annotation ( + Line( + points={{-40,-20},{40,-20}}, + color={28,108,200}, + thickness=1)); + connect(sourceB_MFlowVar_hFixed.port, sourceA_pVar_TFixed.port) annotation ( + Line( + points={{40,-40},{-40,-40}}, + color={28,108,200}, + thickness=1)); + connect(sourceA_VFlowVar_TFixed.port, sourceB_pFixed_TVar.port) annotation ( + Line( + points={{-40,-60},{40,-60}}, + color={28,108,200}, + thickness=1)); + connect(sourceB_pFixed_hVar.port, sourceA_VFlowVar_hFixed.port) annotation ( + Line( + points={{40,-80},{-40,-80}}, + color={28,108,200}, + thickness=1)); + + connect(input_pVar.y, sourceA_pVar_hFixed.p_input) annotation (Line(points={{-59,-30}, + {-50,-30},{-50,-15},{-41.2,-15}}, color={0,0,127})); + connect(input_pVar.y, sourceA_pVar_TFixed.p_input) annotation (Line(points={{-59,-30}, + {-50,-30},{-50,-35},{-41.2,-35}}, color={0,0,127})); + connect(input_VFlowVar.y, sourceA_VFlowVar_TFixed.V_flow_input) annotation ( + Line(points={{-59,-70},{-50,-70},{-50,-58},{-41.2,-58}}, color={0,0,127})); + connect(input_VFlowVar.y, sourceA_VFlowVar_hFixed.V_flow_input) annotation ( + Line(points={{-59,-70},{-50,-70},{-50,-78},{-41.2,-78}}, color={0,0,127})); + connect(input_mFlowVar.y, sourceB_MFlowVar_TVar.m_flow_input) annotation ( + Line(points={{59,-20},{54,-20},{54,-18},{41.2,-18}}, color={0,0,127})); + connect(input_mFlowVar.y, sourceB_MFlowVar_hFixed.m_flow_input) annotation ( + Line(points={{59,-20},{54,-20},{54,-38},{41.2,-38}}, color={0,0,127})); + connect(input_TVar.y, sourceB_MFlowVar_TVar.T_input) annotation (Line(points={{59,-50}, + {50,-50},{50,-22},{41.2,-22}}, color={0,0,127})); + connect(input_TVar.y, sourceB_pFixed_TVar.T_input) annotation (Line(points={{59,-50}, + {50,-50},{50,-62},{41.2,-62}}, color={0,0,127})); + connect(input_hVar.y, sourceB_pFixed_hVar.h_input) annotation (Line(points={{59,-80}, + {50,-80},{50,-82},{41.2,-82}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the (ideal) liquid source model used to prescribe properties +at a liquid fluid port. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_LiquidSource; diff --git a/SorpLib/Basics/Sources/Fluids/Tester/Test_VLESource.mo b/SorpLib/Basics/Sources/Fluids/Tester/Test_VLESource.mo new file mode 100644 index 0000000000000000000000000000000000000000..c08c55f34832534bffd1b2be834fb9daac99024c --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/Tester/Test_VLESource.mo @@ -0,0 +1,252 @@ +within SorpLib.Basics.Sources.Fluids.Tester; +model Test_VLESource "Tester for VLE source" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource sourceA_pFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + p_fixed=1000000) "Source A: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,70},{-30,90}}))); + + SorpLib.Basics.Sources.Fluids.VLESource sourceB_MFlowFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=0.2, + T_fixed=323.15) "Source B: Fixed mass flow rate and fixed temperature" + annotation (Placement(transformation(extent={{30,70},{50,90}}))); + + SorpLib.Basics.Sources.Fluids.VLESource sourceA_pFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=1000000, + T_fixed=303.15) "Source A: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,50},{-30,70}}))); + SorpLib.Basics.Sources.Fluids.VLESource sourceB_MFlowFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + m_flow_fixed=-0.2, + h_fixed=400e3) "Source B: Fixed mass flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{30,50},{50,70}}))); + + SorpLib.Basics.Sources.Fluids.VLESource sourceA_VFlowFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + V_flow_fixed(displayUnit="l/min") = -0.00016666666666667, + T_fixed=348.15) "Source A: Fixed volume flow rate and fixed temperature" + annotation (Placement(transformation(extent={{-50,30},{-30,50}}))); + SorpLib.Basics.Sources.Fluids.VLESource sourceB_pFixed_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=500000, + T_fixed=283.15) "Source B: Fixed pressure and fixed temperature" + annotation (Placement(transformation(extent={{30,30},{50,50}}))); + + SorpLib.Basics.Sources.Fluids.VLESource sourceA_VFlowFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + V_flow_fixed(displayUnit="l/min") = -0.00016666666666667, + h_fixed=275e3) + "Source A: Fixed volume flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,10},{-30,30}}))); + SorpLib.Basics.Sources.Fluids.VLESource sourceB_pFixed_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + p_fixed=500000, + h_fixed=300e3) "Source B: Fixed pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{30,10},{50,30}}))); + + SorpLib.Basics.Sources.Fluids.VLESource sourceA_pVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_pInput=true) + "Source A: Variable pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-30},{-30,-10}}))); + SorpLib.Basics.Sources.Fluids.VLESource sourceB_MFlowVar_TVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true) + "Source B: Variable mass flow rate and variable temperature" + annotation (Placement(transformation(extent={{50,-30},{30,-10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource sourceA_pVar_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=303.15) + "Source A: Variable pressure and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-50},{-30,-30}}))); + SorpLib.Basics.Sources.Fluids.VLESource sourceB_MFlowVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_mFlowInput=true, + h_fixed=400e3) + "Source B: Variable mass flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{50,-50},{30,-30}}))); + + SorpLib.Basics.Sources.Fluids.VLESource sourceA_VFlowVar_TFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_VFlowInput=true, + V_flow_fixed(displayUnit="l/min"), + T_fixed=348.15) + "Source A: Variable volume flow rate and fixed temperature" + annotation (Placement(transformation(extent={{-50,-70},{-30,-50}}))); + SorpLib.Basics.Sources.Fluids.VLESource sourceB_pFixed_TVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=500000, + use_TInput=true) + "Source B: Fixed pressure and variable temperature" + annotation (Placement(transformation(extent={{50,-70},{30,-50}}))); + + SorpLib.Basics.Sources.Fluids.VLESource sourceA_VFlowVar_hFixed( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_VFlowInput=true, + V_flow_fixed(displayUnit="l/min"), + h_fixed=275e3) + "Source A: Variable volume flow rate and fixed specific enthalpy" + annotation (Placement(transformation(extent={{-50,-90},{-30,-70}}))); + SorpLib.Basics.Sources.Fluids.VLESource sourceB_pFixed_hVar( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + p_fixed=500000, + use_hInput=true) "Source B: Fixed pressure and variable specific enthalpy" + annotation (Placement(transformation(extent={{50,-90},{30,-70}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Ramp input_pVar( + height=10e5 - 1e3, + duration=2500, + offset=1e3, + startTime=0) + "Ramp to simulate input signal of pressure" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_mFlowVar( + height=2, + duration=2500, + offset=-1, + startTime=0) "Ramp to simulate input signal of mass flow rate" + annotation (Placement(transformation(extent={{80,-30},{60,-10}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_VFlowVar( + height=40/60000, + duration=2500, + offset=-20/60000, + startTime=0) "Ramp to simulate input signal of volume flow rate" + annotation (Placement(transformation(extent={{-80,-80},{-60,-60}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_hVar( + height=3e5, + duration=2500, + offset=1e5, + startTime=0) + "Ramp to simulate input signal of specific enthalpy" + annotation (Placement(transformation(extent={{80,-90},{60,-70}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_TVar( + height=90, + duration=2500, + offset=283.15, + startTime=0) "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{80,-60},{60,-40}})), + HideResult=true); + +equation + // + // Connections + // + connect(sourceA_pFixed_hFixed.port, sourceB_MFlowFixed_TFixed.port) + annotation (Line( + points={{-40,80},{40,80}}, + color={0,140,72}, + thickness=1)); + connect(sourceB_MFlowFixed_hFixed.port, sourceA_pFixed_TFixed.port) + annotation (Line( + points={{40,60},{-40,60}}, + color={0,140,72}, + thickness=1)); + connect(sourceA_VFlowFixed_TFixed.port, sourceB_pFixed_TFixed.port) + annotation (Line( + points={{-40,40},{40,40}}, + color={0,140,72}, + thickness=1)); + connect(sourceB_pFixed_hFixed.port, sourceA_VFlowFixed_hFixed.port) + annotation (Line( + points={{40,20},{-40,20}}, + color={0,140,72}, + thickness=1)); + connect(sourceA_pVar_hFixed.port, sourceB_MFlowVar_TVar.port) annotation ( + Line( + points={{-40,-20},{40,-20}}, + color={0,140,72}, + thickness=1)); + connect(sourceB_MFlowVar_hFixed.port, sourceA_pVar_TFixed.port) annotation ( + Line( + points={{40,-40},{-40,-40}}, + color={0,140,72}, + thickness=1)); + connect(sourceA_VFlowVar_TFixed.port, sourceB_pFixed_TVar.port) annotation ( + Line( + points={{-40,-60},{40,-60}}, + color={0,140,72}, + thickness=1)); + connect(sourceB_pFixed_hVar.port, sourceA_VFlowVar_hFixed.port) annotation ( + Line( + points={{40,-80},{-40,-80}}, + color={0,140,72}, + thickness=1)); + + connect(input_pVar.y, sourceA_pVar_hFixed.p_input) annotation (Line(points={{-59,-30}, + {-50,-30},{-50,-15},{-41.2,-15}}, color={0,0,127})); + connect(input_pVar.y, sourceA_pVar_TFixed.p_input) annotation (Line(points={{-59,-30}, + {-50,-30},{-50,-35},{-41.2,-35}}, color={0,0,127})); + connect(input_VFlowVar.y, sourceA_VFlowVar_TFixed.V_flow_input) annotation ( + Line(points={{-59,-70},{-50,-70},{-50,-58},{-41.2,-58}}, color={0,0,127})); + connect(input_VFlowVar.y, sourceA_VFlowVar_hFixed.V_flow_input) annotation ( + Line(points={{-59,-70},{-50,-70},{-50,-78},{-41.2,-78}}, color={0,0,127})); + connect(input_mFlowVar.y, sourceB_MFlowVar_TVar.m_flow_input) annotation ( + Line(points={{59,-20},{54,-20},{54,-18},{41.2,-18}}, color={0,0,127})); + connect(input_mFlowVar.y, sourceB_MFlowVar_hFixed.m_flow_input) annotation ( + Line(points={{59,-20},{54,-20},{54,-38},{41.2,-38}}, color={0,0,127})); + connect(input_TVar.y, sourceB_MFlowVar_TVar.T_input) annotation (Line(points={{59,-50}, + {50,-50},{50,-22},{41.2,-22}}, color={0,0,127})); + connect(input_TVar.y, sourceB_pFixed_TVar.T_input) annotation (Line(points={{59,-50}, + {50,-50},{50,-62},{41.2,-62}}, color={0,0,127})); + connect(input_hVar.y, sourceB_pFixed_hVar.h_input) annotation (Line(points={{59,-80}, + {50,-80},{50,-82},{41.2,-82}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the VLE source model used to prescribe properties at a VLE +fluid port. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 5, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_VLESource; diff --git a/SorpLib/Basics/Sources/Fluids/Tester/package.mo b/SorpLib/Basics/Sources/Fluids/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..7fd6936a8e20ede1afac4e576950d77643c60a4b --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/Tester/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Basics.Sources.Fluids; +package Tester "Models to test and varify models for fluid sources" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented fluid sources. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Basics/Sources/Fluids/Tester/package.order b/SorpLib/Basics/Sources/Fluids/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..f90a2d93ef434a19eabce90b003a3abee4a5671a --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/Tester/package.order @@ -0,0 +1,4 @@ +Test_LiquidSource +Test_GasSource +Test_GasVaporMixtureSource +Test_VLESource diff --git a/SorpLib/Basics/Sources/Fluids/VLESource.mo b/SorpLib/Basics/Sources/Fluids/VLESource.mo new file mode 100644 index 0000000000000000000000000000000000000000..9d53a3d4605f4c99b881ff7f0ca7d1dd2b731f0d --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/VLESource.mo @@ -0,0 +1,113 @@ +within SorpLib.Basics.Sources.Fluids; +model VLESource + "Boundary model of a real fluid (i.e., with two-phase regime)" + extends SorpLib.Basics.Sources.BaseClasses.PartialFluidSource( + redeclare final Interfaces.FluidPorts.VLEPort_in port, + final no_components = Medium.nX, + final boundaryTypeStreamMassFractions= + SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + X_fixed=Medium.reference_X); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Boundary Type"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculate properties + // + if boundaryTypePotentialFlow == + SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate then + d_in = Medium.density_phX( + p=port.p, + h=inStream(port.h_outflow), + X=cat(1, inStream(port.Xi_outflow), {1-sum(inStream(port.Xi_outflow))})) + "Density calculated with pressure, specific enthalpy, and mass fractions + entering the port"; + + d_out =if boundaryTypeStreamEnthalpy <> + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature then + Medium.density_phX( + p=port.p, + h=port.h_outflow, + X=cat(1, port.Xi_outflow, {1-sum(port.Xi_outflow)})) else + Medium.density_pTX( + p=port.p, + T=T_internal, + X=cat(1, port.Xi_outflow, {1-sum(port.Xi_outflow)})) + "Density calculated with pressure, specific enthalpy or temperature, and + mass fractions leaving the port"; + + else + d_in = m_flow_fixed / V_flow_fixed + "Density calculated with pressure, specific enthalpy, and mass fractions + entering the port: Not needed, so set dummy value"; + d_out = m_flow_fixed / V_flow_fixed + "Density calculated with pressure, specific enthalpy, and mass fractions + leaving the port: Not needed, so set dummy value"; + + end if; + + if boundaryTypeStreamEnthalpy == + SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature then + h = Medium.specificEnthalpy_pTX( + p=port.p, + T=T_internal, + X=X_internal) + "Specific enthalpy calculated with pressure at port and temperature"; + + else + h = h_fixed + "Specific enthalpy calculated with pressure at port and temperature: Not + needed, so set dummy value"; + + end if; + + // + // Annotations + // + annotation (Icon(graphics={Rectangle( + extent={{-2,80},{2,-80}}, + lineColor={0,140,72}, + lineThickness=0.5, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This model can be used to specify either the pressure or mass flow rate as well as +the specific enthalpy and independent mass fractions at a VLE port. +</p> + +<h4>Options</h4> +<ul> + <li> + <i>boundaryTypePotentialFlow</i>: Defines if pressure, mass flow rate, or volume + flow rate are prescribed. + </li> + <li> + <i>boundaryTypeStreamEnthalpy</i>: Defines if specific enthalpy or temperature + are prescribed. + </li> +</ul> + +</html>",revisions="<html> +<ul> + <li> + December 5, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end VLESource; diff --git a/SorpLib/Basics/Sources/Fluids/package.mo b/SorpLib/Basics/Sources/Fluids/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..1fecbebbb177e1d11e89d6044f991dfefc833428 --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Basics.Sources; +package Fluids "Fluid sources used to prescribe pressure, mass flow rate, specific enthalpy, and independent mass fractions" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains sources for fluid connectors to define fixed or prescribed +conditions. This package calculates fluid properties based on the open-source +Modelica Standard Library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Fluids; diff --git a/SorpLib/Basics/Sources/Fluids/package.order b/SorpLib/Basics/Sources/Fluids/package.order new file mode 100644 index 0000000000000000000000000000000000000000..56391de59905f58f7fec8bc9071817e440424eda --- /dev/null +++ b/SorpLib/Basics/Sources/Fluids/package.order @@ -0,0 +1,5 @@ +LiquidSource +GasSource +GasVaporMixtureSource +VLESource +Tester diff --git a/SorpLib/Basics/Sources/Sorption/AdsorbateSource.mo b/SorpLib/Basics/Sources/Sorption/AdsorbateSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..ce456246d4f2378194c224f41dd409fb0390842c --- /dev/null +++ b/SorpLib/Basics/Sources/Sorption/AdsorbateSource.mo @@ -0,0 +1,236 @@ +within SorpLib.Basics.Sources.Sorption; +model AdsorbateSource + "Boundary model of an adsorbate source" + + // + // Definition of parameters regarding the boundary type + // + parameter Integer no_adsorptivs = 1 + "Number of adsorptivs (i.e., components that can be adsorbed/desorbed)" + annotation (Dialog(tab="General", group="Boundary Type"), + Evaluate=true, + HideResult=true); + + parameter Boolean boundaryTypePressure = true + " = true, if pressure is prescribed; otherwise, mass flow rate is prescribed" + annotation (Dialog(tab="General", group="Boundary Type"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding potential and flow variables + // + parameter Boolean use_pInput = false + " = true, if p is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=boundaryTypePressure), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Pressure p_fixed = 1.01325e5 + "Fixed pressure at boundary" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=boundaryTypePressure and not use_pInput)); + + parameter Boolean use_mFlowInput = false + "=true, if m_flow is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=not boundaryTypePressure), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.MassFlowRate m_flow_fixed = -0.1 + "Fixed sorbent mass flow rate at boundary" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=not boundaryTypePressure and not use_mFlowInput)); + + // + // Definition of parameters regarding stream variables of specific enthalpy + // + parameter Boolean use_hInput = false + "=true, if h is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Stream Variables - Specific Enthalpy"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.SpecificEnthalpy h_fixed = 350e3 + "Fixed specific enthalpy at boundary" + annotation (Dialog(tab="General",group="Stream Variables - Specific Enthalpy", + enable = not use_hInput)); + + // + // Definition of parameters regarding stream variables of loadings + // + parameter Boolean use_xInput = false + "=true, if x is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Stream Variables - Loadings"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter SorpLib.Units.Uptake[no_adsorptivs] x_fixed= + fill(0.05, no_adsorptivs) + "Fixed loadings at boundary" + annotation (Dialog(tab="General",group="Stream Variables - Loadings", + enable=not use_xInput)); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of variables + // + Modelica.Units.SI.MassFlowRate m_flow_total + "Total mass flow rate"; + Modelica.Units.SI.MassFlowRate[no_adsorptivs] m_flow_adsorpt_i + "Mass flow rates of adsorpt components"; + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput p_input(final unit="Pa") if + (boundaryTypePressure and use_pInput) + "Input for pressure" + annotation (Placement(transformation(extent={{-120,30},{-80,70}}), + iconTransformation(extent={{-22,40},{-2,60}}))); + + Modelica.Blocks.Interfaces.RealInput m_flow_input(final unit="kg/s") if + (not boundaryTypePressure and use_mFlowInput) + "Input for mass flow rate" + annotation (Placement(transformation(extent={{-120,0},{-80,40}}), + iconTransformation(extent={{-22,10},{-2,30}}))); + + Modelica.Blocks.Interfaces.RealInput h_input(final unit="J/kg") if + (use_hInput) + "Input for specific enthalpy" + annotation (Placement(transformation(extent={{-120,0},{-80,-40}}), + iconTransformation(extent={{-22,-30},{-2,-10}}))); + + Modelica.Blocks.Interfaces.RealInput[no_adsorptivs] x_input(each final unit="kg/kg") if + (use_xInput) + "Input for loadings" + annotation (Placement(transformation(extent={{-120,-30},{-80,-70}}), + iconTransformation(extent={{-22,-60},{-2,-40}}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput p_internal(final unit="Pa") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealOutput m_flow_internal(final unit="kg/s") + "Needed for connecting to conditional connector"; + + Modelica.Blocks.Interfaces.RealInput h_internal(final unit="J/kg") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput[no_adsorptivs] x_internal(each final unit="kg/kg") + "Needed for connecting to conditional connector"; + + // + // Definition of ports + // +public + SorpLib.Basics.Interfaces.SorptionPorts.AdsorbatePort_in port + "Adsorbate port" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + +equation + // + // Connectors + // + connect(p_input,p_internal); + connect(m_flow_input,m_flow_internal); + + connect(h_input,h_internal); + connect(x_input,x_internal); + + if not use_pInput then + p_internal = p_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_mFlowInput then + m_flow_internal = m_flow_fixed + "Needed for connecting to conditional connector"; + end if; + + if not use_hInput then + h_internal = h_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_xInput then + x_internal = x_fixed + "Needed for connecting to conditional connector"; + end if; + + // + // Properties at port + // + if boundaryTypePressure then + port.p = p_internal + "Pressure at port"; + + else + port.m_flow = m_flow_internal + "Mass flow rate at port"; + + end if; + + port.h_outflow = h_internal + "Specific enthalpy at port"; + port.x_outflow = x_internal + "Loadings at port"; + + // + // Calculate mass flow rates + // + m_flow_total = port.m_flow + sum(m_flow_adsorpt_i) + "Total mass flow rate"; + m_flow_adsorpt_i = if avoid_events then + port.m_flow .* noEvent(actualStream(port.x_outflow)) else + port.m_flow .* actualStream(port.x_outflow) + "Mass flow rates of adsorpt components"; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle( + extent={{-2,80},{2,-80}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid)}), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This model can be used to specify either the pressure or the mass flow rate as +well as the specific enthalpy and loadings at an adsorbate port. Note that the +mass flow rate does not indicate the total mass flow rate, but only the mass flow +rate of the sorbent. The mass flow rates of the adsorpt components are calculated as +<i>port.m_flow * actualStram(port.x_outflow)</i>. +</p> + +<h4>Options</h4> +<ul> + <li> + <i>boundaryTypePressure</i>: Defines if pressure or mass flow rate is + prescribed. + </li> +</ul> + +</html>",revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorbateSource; diff --git a/SorpLib/Basics/Sources/Sorption/AdsorptSource.mo b/SorpLib/Basics/Sources/Sorption/AdsorptSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..236caea7733ce6a1096ee52e10a063e1261eab78 --- /dev/null +++ b/SorpLib/Basics/Sources/Sorption/AdsorptSource.mo @@ -0,0 +1,165 @@ +within SorpLib.Basics.Sources.Sorption; +model AdsorptSource "Boundary model of an adsorpt source" + + // + // Definition of parameters regarding the boundary type + // + parameter Boolean boundaryTypeLoading = true + " = true, if loading is prescribed; otherwise, mass flow rate is prescribed" + annotation (Dialog(tab="General", group="Boundary Type"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding potential and flow variables + // + parameter Boolean use_xInput = false + " = true, if x is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=boundaryTypeLoading), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter SorpLib.Units.Uptake x_fixed = 0.05 + "Fixed loading at boundary" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=boundaryTypeLoading and not use_xInput)); + + parameter Boolean use_mFlowInput = false + "=true, if m_flow is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=not boundaryTypeLoading), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.MassFlowRate m_flow_fixed = -0.001 + "Fixed adsorpt mass flow rate at boundary" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=not boundaryTypeLoading and not use_mFlowInput)); + + // + // Definition of parameters regarding stream variables of specific enthalpy + // + parameter Boolean use_hInput = false + "=true, if h is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Stream Variables - Specific Enthalpy"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.SpecificEnthalpy h_fixed = 350e3 + "Fixed specific enthalpy at boundary" + annotation (Dialog(tab="General",group="Stream Variables - Specific Enthalpy", + enable = not use_hInput)); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput x_input(final unit="kg/kg") if + (boundaryTypeLoading and use_xInput) + "Input for loading" + annotation (Placement(transformation(extent={{-120,30},{-80,70}}), + iconTransformation(extent={{-22,40},{-2,60}}))); + + Modelica.Blocks.Interfaces.RealInput m_flow_input(final unit="kg/s") if + (not boundaryTypeLoading and use_mFlowInput) + "Input for mass flow rate" + annotation (Placement(transformation(extent={{-120,0},{-80,40}}), + iconTransformation(extent={{-22,10},{-2,30}}))); + + Modelica.Blocks.Interfaces.RealInput h_input(final unit="J/kg") if + (use_hInput) + "Input for specific enthalpy" + annotation (Placement(transformation(extent={{-120,0},{-80,-40}}), + iconTransformation(extent={{-22,-30},{-2,-10}}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput x_internal(final unit="kg/kg") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealOutput m_flow_internal(final unit="kg/s") + "Needed for connecting to conditional connector"; + + Modelica.Blocks.Interfaces.RealInput h_internal(final unit="J/kg") + "Needed for connecting to conditional connector"; + + // + // Definition of ports + // +public + SorpLib.Basics.Interfaces.SorptionPorts.AdsorptPort_in port + "Adsorpt port" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + +equation + // + // Connectors + // + connect(x_input,x_internal); + connect(m_flow_input,m_flow_internal); + connect(h_input,h_internal); + + if not use_xInput then + x_internal = x_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_mFlowInput then + m_flow_internal = m_flow_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_hInput then + h_internal = h_fixed + "Needed for connecting to conditional connector"; + end if; + + // + // Properties at port + // + if boundaryTypeLoading then + port.x = x_internal + "Loading at port"; + + else + port.m_flow = m_flow_internal + "Mass flow rate at port"; + + end if; + + port.h_outflow = h_internal + "Specific enthalpy at port"; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle( + extent={{-2,80},{2,-80}}, + lineColor={175,175,175}, + lineThickness=0.5, + fillColor={175,175,175}, + fillPattern=FillPattern.Solid)}), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This model can be used to specify either the loading or the mass flow rate as +well as the specific enthalpy at an adsorpt port. +</p> + +<h4>Options</h4> +<ul> + <li> + <i>boundaryTypeLoading</i>: Defines if loading or mass flow rate is prescribed. + </li> +</ul> + +</html>",revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorptSource; diff --git a/SorpLib/Basics/Sources/Sorption/Tester/Test_AdsorbateSource.mo b/SorpLib/Basics/Sources/Sorption/Tester/Test_AdsorbateSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..6409539a0117126da72416b7939f01ceb2a58ba7 --- /dev/null +++ b/SorpLib/Basics/Sources/Sorption/Tester/Test_AdsorbateSource.mo @@ -0,0 +1,130 @@ +within SorpLib.Basics.Sources.Sorption.Tester; +model Test_AdsorbateSource "Tester for adsorbate source" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Sorption.AdsorbateSource pFixed( + boundaryTypePressure=false, + p_fixed(displayUnit="Pa"), + m_flow_fixed=-0.1, + h_fixed=151688, + x_fixed={0.05}) + "Adsorbate source with fixed pressure" + annotation (Placement(transformation(extent={{-50,40},{-30,60}}))); + SorpLib.Basics.Sources.Sorption.AdsorbateSource pVar( + use_pInput=true, + h_fixed=151688, + x_fixed={0.05}) "Adsorbate source with variable pressure" + annotation (Placement(transformation(extent={{-50,-42},{-30,-22}}))); + + SorpLib.Basics.Sources.Sorption.AdsorbateSource mFixed( + p_fixed=545200000, + h_fixed=151688, + x_fixed={0.05}) + "Adsorbate source with fixed mass flow rate" + annotation (Placement(transformation(extent={{50,40},{30,60}}))); + SorpLib.Basics.Sources.Sorption.AdsorbateSource mVar( + boundaryTypePressure=false, + use_mFlowInput=true, + h_fixed=151688, + x_fixed={0.05}) "Adsorbate source with variable mass flow rate" + annotation (Placement(transformation(extent={{50,-42},{30,-22}}))); + + SorpLib.Basics.Sources.Sorption.AdsorbateSource pVar_hVar_X_var( + use_pInput=true, + use_hInput=true, + use_xInput=true) + "Adsorbate source with variable pressure, specific enthaly, and loadings" + annotation (Placement(transformation(extent={{-50,-80},{-30,-60}}))); + SorpLib.Basics.Sources.Sorption.AdsorbateSource mVar_h_var( + boundaryTypePressure=false, + use_mFlowInput=true, + use_hInput=true, + x_fixed={0.05}) + "Adsorbate source with variable mass flow rate and specific enthalpy" + annotation (Placement(transformation(extent={{50,-80},{30,-60}}))); + +protected + Modelica.Blocks.Sources.Ramp input_pVar( + height=1e5-1e3, + duration=2500, + offset=1e3, + startTime=0) "Ramp to simulate input signal of pressure" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_mVar( + height=0.2, + duration=2500, + offset=-0.1, + startTime=0) "Ramp to simulate input signal of mass flow rate" + annotation (Placement(transformation(extent={{80,-40},{60,-20}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_hVar( + height=-0.5e5, + duration=2500, + offset=1.5e5, + startTime=0) "Ramp to simulate input signal of specific enthalpy" + annotation (Placement(transformation(extent={{80,-80},{60,-60}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_xVar( + height=0.2, + duration=2500, + offset=0.05, + startTime=0) "Ramp to simulate input signal of loading" annotation ( + Placement(transformation(extent={{-80,-80},{-60,-60}})), HideResult=true); + +equation + // + // Connections + // + connect(pFixed.port, mFixed.port) annotation (Line( + points={{-40,50},{40,50}}, + color={0,0,0}, + thickness=1)); + connect(pVar.port, mVar.port) annotation (Line( + points={{-40,-32},{40,-32}}, + color={0,0,0}, + thickness=1)); + connect(pVar_hVar_X_var.port, mVar_h_var.port) annotation (Line( + points={{-40,-70},{40,-70}}, + color={0,0,0}, + thickness=1)); + + connect(input_pVar.y, pVar.p_input) annotation (Line(points={{-59,-30},{-50,-30}, + {-50,-27},{-41.2,-27}}, color={0,0,127})); + connect(input_mVar.y, mVar.m_flow_input) annotation (Line(points={{59,-30},{41.2, + -30}}, color={0,0,127})); + connect(input_pVar.y, pVar_hVar_X_var.p_input) annotation (Line(points={{-59,-30}, + {-50,-30},{-50,-65},{-41.2,-65}}, color={0,0,127})); + connect(input_mVar.y, mVar_h_var.m_flow_input) annotation (Line(points={{59,-30}, + {50,-30},{50,-68},{41.2,-68}}, color={0,0,127})); + connect(input_hVar.y, mVar_h_var.h_input) annotation (Line(points={{59,-70},{50, + -70},{50,-72},{41.2,-72}}, color={0,0,127})); + connect(input_hVar.y, pVar_hVar_X_var.h_input) annotation (Line(points={{59,-70}, + {50,-70},{50,-90},{-50,-90},{-50,-72},{-41.2,-72}}, color={0,0,127})); + connect(input_xVar.y, pVar_hVar_X_var.x_input[1]) annotation (Line(points={{-59, + -70},{-52,-70},{-52,-75},{-41.2,-75}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the adsorbate source model used to prescribe properties +at an adsorbate port. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_AdsorbateSource; diff --git a/SorpLib/Basics/Sources/Sorption/Tester/Test_AdsorptSource.mo b/SorpLib/Basics/Sources/Sorption/Tester/Test_AdsorptSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..00f75ccde19af8e27b8945b541d3c98353486362 --- /dev/null +++ b/SorpLib/Basics/Sources/Sorption/Tester/Test_AdsorptSource.mo @@ -0,0 +1,92 @@ +within SorpLib.Basics.Sources.Sorption.Tester; +model Test_AdsorptSource "Tester for adsorpt source" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Sorption.AdsorptSource xFixed( + m_flow_fixed=-0.1, + h_fixed=151688, + x_fixed=0.05) "Adsorbate source with fixed loading" + annotation (Placement(transformation(extent={{-50,40},{-30,60}}))); + SorpLib.Basics.Sources.Sorption.AdsorptSource xVar(use_xInput=true, + h_fixed=151688) "Adsorbate source with variable loading" + annotation (Placement(transformation(extent={{-50,-60},{-30,-40}}))); + + SorpLib.Basics.Sources.Sorption.AdsorptSource mFixed(boundaryTypeLoading=false, + h_fixed=151688) + "Adsorbate source with fixed mass flow rate" + annotation (Placement(transformation(extent={{50,40},{30,60}}))); + SorpLib.Basics.Sources.Sorption.AdsorptSource mVar_hVar( + boundaryTypeLoading=false, + use_hInput=true, + use_mFlowInput=true, + h_fixed=151688) + "Adsorbate source with variable mass flow rate and specific enthalpy" + annotation (Placement(transformation(extent={{50,-60},{30,-40}}))); + +protected + Modelica.Blocks.Sources.Ramp input_xVar( + height=0.2, + duration=2500, + offset=0.05, + startTime=0) "Ramp to simulate input signal of loading" + annotation (Placement(transformation(extent={{-80,-58},{-60,-38}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_mVar( + height=0.2, + duration=2500, + offset=-0.1, + startTime=0) "Ramp to simulate input signal of mass flow rate" + annotation (Placement(transformation(extent={{80,-40},{60,-20}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_hVar( + height=-0.5e5, + duration=2500, + offset=1.5e5, + startTime=0) "Ramp to simulate input signal of specific enthalpy" + annotation (Placement(transformation(extent={{80,-80},{60,-60}})), + HideResult=true); + +equation + // + // Connections + // + connect(xFixed.port, mFixed.port) annotation (Line( + points={{-40,50},{40,50}}, + color={175,175,175}, + thickness=1)); + connect(xVar.port, mVar_hVar.port) annotation (Line( + points={{-40,-50},{40,-50}}, + color={175,175,175}, + thickness=1)); + + connect(input_xVar.y, xVar.x_input) annotation (Line(points={{-59,-48},{-50,-48}, + {-50,-45},{-41.2,-45}}, color={0,0,127})); + connect(input_mVar.y, mVar_hVar.m_flow_input) annotation (Line(points={{59,-30}, + {50,-30},{50,-48},{41.2,-48}}, color={0,0,127})); + connect(input_hVar.y, mVar_hVar.h_input) annotation (Line(points={{59,-70},{50, + -70},{50,-52},{41.2,-52}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the adsorpt source model used to prescribe properties +at an adsorpt port. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_AdsorptSource; diff --git a/SorpLib/Basics/Sources/Sorption/Tester/package.mo b/SorpLib/Basics/Sources/Sorption/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..43c25072c2ed38e51d53918b99a055b4f4767431 --- /dev/null +++ b/SorpLib/Basics/Sources/Sorption/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Basics.Sources.Sorption; +package Tester "Models to test and varify models for sorption sources" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented sorption +sources. +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Basics/Sources/Sorption/Tester/package.order b/SorpLib/Basics/Sources/Sorption/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..14b729a066ffca8bde098b2582e56f6f47b46a4c --- /dev/null +++ b/SorpLib/Basics/Sources/Sorption/Tester/package.order @@ -0,0 +1,2 @@ +Test_AdsorbateSource +Test_AdsorptSource diff --git a/SorpLib/Basics/Sources/Sorption/package.mo b/SorpLib/Basics/Sources/Sorption/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..8a51ccf3a56a2d813725dbd7d2751ad06cd0a5bc --- /dev/null +++ b/SorpLib/Basics/Sources/Sorption/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Basics.Sources; +package Sorption "Sorption sources used to prescribe pressure, mass flow rate, specific enthalpy, and loadings" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains sources for sorption connectors to define fixed or prescribed +conditions. +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Sorption; diff --git a/SorpLib/Basics/Sources/Sorption/package.order b/SorpLib/Basics/Sources/Sorption/package.order new file mode 100644 index 0000000000000000000000000000000000000000..b89258b59514577af72f5059003d03aa43044ea9 --- /dev/null +++ b/SorpLib/Basics/Sources/Sorption/package.order @@ -0,0 +1,3 @@ +AdsorbateSource +AdsorptSource +Tester diff --git a/SorpLib/Basics/Sources/Thermal/HeatSource.mo b/SorpLib/Basics/Sources/Thermal/HeatSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..3dcbdbe38094ea12d93c9e6c98fd769b1aa5a0e0 --- /dev/null +++ b/SorpLib/Basics/Sources/Thermal/HeatSource.mo @@ -0,0 +1,147 @@ +within SorpLib.Basics.Sources.Thermal; +model HeatSource + "Boundary model of a heat source" + + // + // Definition of parameters regarding the boundary type + // + parameter SorpLib.Choices.BoundaryThermal boundaryType= + SorpLib.Choices.BoundaryThermal.Temperature + "Prescribed variable for potential or flow" + annotation (Dialog(tab="General", group="Boundary Type"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding potential and flow variables + // + parameter Boolean use_TInput = false + " = true, if T is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=(boundaryType == + SorpLib.Choices.BoundaryThermal.Temperature)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Temperature T_fixed = 293.15 + "Fixed temperature at boundary" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=(boundaryType == + SorpLib.Choices.BoundaryThermal.Temperature) + and not use_TInput)); + + parameter Boolean use_QFlowInput = false + "=true, if Q_flow is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=(boundaryType == + SorpLib.Choices.BoundaryThermal.HeatFlowRate)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.HeatFlowRate Q_flow_fixed = 25 + "Fixed heat flow at boundary" + annotation (Dialog(tab="General",group="Potential and Flow Variables", + enable=(boundaryType == + SorpLib.Choices.BoundaryThermal.HeatFlowRate) + and not use_QFlowInput)); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput T_input(final unit="K") if + (boundaryType == SorpLib.Choices.BoundaryThermal.Temperature and + use_TInput) + "Input for temperature" + annotation (Placement(transformation(extent={{-40,30},{0,70}}), + iconTransformation(extent={{-20,42},{0,62}}))); + + Modelica.Blocks.Interfaces.RealInput Q_flow_input(final unit="W") if + (boundaryType == SorpLib.Choices.BoundaryThermal.HeatFlowRate and + use_QFlowInput) + "Input for heat flow rate" + annotation (Placement(transformation(extent={{-40,-70},{0,-30}}), + iconTransformation(extent={{-20,-60},{0,-40}}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput T_internal(final unit="K") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput Q_flow_internal(final unit="W") + "Needed for connecting to conditional connector"; + + // + // Definition of ports + // +public + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in port + "Heat port" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + +equation + // + // Connectors + // + connect(T_input,T_internal); + connect(Q_flow_input,Q_flow_internal); + + if not use_TInput then + T_internal = T_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_QFlowInput then + Q_flow_internal = Q_flow_fixed + "Needed for connecting to conditional connector"; + end if; + + // + // Properties at port + // + if boundaryType == SorpLib.Choices.BoundaryThermal.Temperature then + port.T = T_internal + "Temperature at port"; + + else + port.Q_flow = Q_flow_internal + "Heat flow rate at port"; + + end if; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle( + extent={{-2,80},{2,-80}}, + lineColor={238,46,47}, + lineThickness=0.5, + fillColor={238,46,47}, + fillPattern=FillPattern.Solid)}), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This model can be used to specify either the temperature or the heat flow rate +at a heat port. +</p> + +<h4>Options</h4> +<ul> + <li> + <i>boundaryType</i>: Defines if temperature or heat flow rate is prescribed. + </li> +</ul> + +</html>",revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end HeatSource; diff --git a/SorpLib/Basics/Sources/Thermal/Tester/Test_HeatSource.mo b/SorpLib/Basics/Sources/Thermal/Tester/Test_HeatSource.mo new file mode 100644 index 0000000000000000000000000000000000000000..06222ba9c4a88990099027db1c81f7e337a23bb0 --- /dev/null +++ b/SorpLib/Basics/Sources/Thermal/Tester/Test_HeatSource.mo @@ -0,0 +1,84 @@ +within SorpLib.Basics.Sources.Thermal.Tester; +model Test_HeatSource "Tester for heat source" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + HeatSource TFixed( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=false) "Heat source with fixed temperature" + annotation (Placement(transformation(extent={{-50,20},{-30,40}}))); + HeatSource TVar( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=true) "Heat source with variable temperature" + annotation (Placement(transformation(extent={{-50,-40},{-30,-20}}))); + + HeatSource QFixed( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + use_QFlowInput=false) "Heat source with fixed heat flow rate" + annotation (Placement(transformation(extent={{50,20},{30,40}}))); + HeatSource QVar( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + use_QFlowInput=true) "Heat source with variable heat flow" + annotation (Placement(transformation(extent={{50,-40},{30,-20}}))); + + Modelica.Blocks.Sources.Ramp input_TVar( + height=80, + duration=2500, + offset=293.15, + startTime=0) + "Ramp to simulate input signal of temperrature" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_QVar( + height=2000, + duration=2500, + offset=-1000, + startTime=0) + "Ramp to simulate input signal of heat flow" + annotation (Placement(transformation(extent={{80,-40},{60,-20}})), + HideResult=true); + +equation + // + // Connections + // + connect(TFixed.port, QFixed.port) annotation (Line( + points={{-40,30},{40,30}}, + color={238,46,47}, + thickness=1)); + connect(TVar.port, QVar.port) annotation (Line( + points={{-40,-30},{40,-30}}, + color={238,46,47}, + thickness=1)); + + connect(input_TVar.y, TVar.T_input) annotation (Line(points={{-59,-30},{-50,-30}, + {-50,-24.8},{-41,-24.8}}, color={0,0,127})); + connect(input_QVar.y, QVar.Q_flow_input) annotation (Line(points={{59,-30},{50, + -30},{50,-36},{41,-36},{41,-35}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the heat source model used to prescribe properties at +a heat port. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 4, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 11, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_HeatSource; diff --git a/SorpLib/Basics/Sources/Thermal/Tester/package.mo b/SorpLib/Basics/Sources/Thermal/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..576175cba1d8357425fdbf50b6ff6418b6b706c9 --- /dev/null +++ b/SorpLib/Basics/Sources/Thermal/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Basics.Sources.Thermal; +package Tester "Models to test and varify models for thermal sources" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented thermal +sources. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Basics/Sources/Thermal/Tester/package.order b/SorpLib/Basics/Sources/Thermal/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..1eba10d6832d6fc7f6234a77cdad6b29b10e5d42 --- /dev/null +++ b/SorpLib/Basics/Sources/Thermal/Tester/package.order @@ -0,0 +1 @@ +Test_HeatSource diff --git a/SorpLib/Basics/Sources/Thermal/package.mo b/SorpLib/Basics/Sources/Thermal/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..45daa54a2b81e087558d248f0d620c50620d8295 --- /dev/null +++ b/SorpLib/Basics/Sources/Thermal/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Basics.Sources; +package Thermal "Thermal sources used to prescribe heat flow rate or temperature" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains sources for thermal connectors to define fixed or prescribed +conditions. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Thermal; diff --git a/SorpLib/Basics/Sources/Thermal/package.order b/SorpLib/Basics/Sources/Thermal/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6cdbdf9bbc4ca95132c26e4c671844808e431855 --- /dev/null +++ b/SorpLib/Basics/Sources/Thermal/package.order @@ -0,0 +1,2 @@ +HeatSource +Tester diff --git a/SorpLib/Basics/Sources/package.mo b/SorpLib/Basics/Sources/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..312a13f22ab0848601d45c714a75bf3192e53ed4 --- /dev/null +++ b/SorpLib/Basics/Sources/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Basics; +package Sources "Library containing models defining fixed or prescribed boundary conditions" + extends Modelica.Icons.SourcesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains generic sources for thermal or fluid connectors to define +fixed or prescribed conditions. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Sources; diff --git a/SorpLib/Basics/Sources/package.order b/SorpLib/Basics/Sources/package.order new file mode 100644 index 0000000000000000000000000000000000000000..4301334932e4b4a00248590690f3c8d085906e61 --- /dev/null +++ b/SorpLib/Basics/Sources/package.order @@ -0,0 +1,4 @@ +BaseClasses +Thermal +Fluids +Sorption diff --git a/SorpLib/Basics/Volumes/AdsorbateVolumes/AdsorbatePureGasVolume.mo b/SorpLib/Basics/Volumes/AdsorbateVolumes/AdsorbatePureGasVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..b252c096d84903f5daf8b38c189de964cd37aa41 --- /dev/null +++ b/SorpLib/Basics/Volumes/AdsorbateVolumes/AdsorbatePureGasVolume.mo @@ -0,0 +1,333 @@ +within SorpLib.Basics.Volumes.AdsorbateVolumes; +model AdsorbatePureGasVolume + "Homogenous adsorbate volume of an ideal gas for pure component adsorption" + extends + SorpLib.Basics.Volumes.BaseClasses.PartialPureComponentAdsorbateVolume( + redeclare final SorpLib.Basics.Interfaces.FluidPorts.GasPort_in fp_sorption, + redeclare replaceable package Medium = SorpLib.Media.IdealGases.H2O + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa, + redeclare replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGel_Toth_WangDouglasLeVan2009_Gas + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare package Medium = Medium, + stateVariables=independentStateVariables, + calcCaloricProperties=true, + calcEntropicProperties=false, + calcAdsorptAdsorbateState=useAdsorbatePorts, + calcDerivativesIsotherm=true, + calcDerivativesMassEnergyBalance=true, + calcDerivativesEntropyBalance=false, + p_adsorpt=p, + x_adsorpt=x, + T_adsorpt=T, + avoidEvents=avoid_events)); + +equation + // + // Mass balance + // + masor_flow = if useAdsorbatePorts then + ap_xMinus.m_flow + ap_xPlus.m_flow else 0 + "Sum of all adsorbent mass flow rates across adsorbate boundaries"; + mas_flow = if useAdsorbatePorts then (if avoid_events then + ap_xMinus.m_flow * sum(noEvent(actualStream(ap_xMinus.x_outflow))) + + ap_xPlus.m_flow * sum(noEvent(actualStream(ap_xPlus.x_outflow))) else + ap_xMinus.m_flow * sum(actualStream(ap_xMinus.x_outflow)) + + ap_xPlus.m_flow * sum(actualStream(ap_xPlus.x_outflow))) else 0 + "Sum of all sorption mass flow rates across adsorbate boundaries"; + md_flow = sum(dp_xMinus.m_flow) + sum(dp_xPlus.m_flow) + "Sum of all diffusive mass flow rates across boundaries"; + ms_flow = sum(fp_sorption.m_flow) + "Sum of all sorption mass flow rates across boundaries"; + + // + // Energy balance + // + if avoid_events then + if useAdsorbatePorts then + Hb_flow = + ap_xMinus.m_flow * noEvent(actualStream(ap_xMinus.h_outflow)) + + ap_xPlus.m_flow * noEvent(actualStream(ap_xPlus.h_outflow)) + + sum(dp_xMinus.m_flow .* noEvent(actualStream(dp_xMinus.h_outflow))) + + sum(dp_xPlus.m_flow .* noEvent(actualStream(dp_xPlus.h_outflow))) + + sum(fp_sorption.m_flow .* noEvent(actualStream(fp_sorption.h_outflow))) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + sum(dp_xMinus.m_flow .* noEvent(actualStream(dp_xMinus.h_outflow))) + + sum(dp_xPlus.m_flow .* noEvent(actualStream(dp_xPlus.h_outflow))) + + sum(fp_sorption.m_flow .* noEvent(actualStream(fp_sorption.h_outflow))) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + + else + if useAdsorbatePorts then + Hb_flow = + ap_xMinus.m_flow * actualStream(ap_xMinus.h_outflow) + + ap_xPlus.m_flow * actualStream(ap_xPlus.h_outflow) + + sum(dp_xMinus.m_flow .* actualStream(dp_xMinus.h_outflow)) + + sum(dp_xPlus.m_flow .* actualStream(dp_xPlus.h_outflow)) + + sum(fp_sorption.m_flow .* actualStream(fp_sorption.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + sum(dp_xMinus.m_flow .* actualStream(dp_xMinus.h_outflow)) + + sum(dp_xPlus.m_flow .* actualStream(dp_xPlus.h_outflow)) + + sum(fp_sorption.m_flow .* actualStream(fp_sorption.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + end if; + + // + // Summary record + // + adsorbateProperties.ma_flow_yMinus = 0 + "Adsorbate mass flow rate at port '-dy/2'"; + adsorbateProperties.ma_flow_yPlus = 0 + "Adsorbate mass flow rate at port '+dy/2'"; + adsorbateProperties.ma_flow_zMinus = 0 + "Adsorbate mass flow rate at port '-dz/2'"; + adsorbateProperties.ma_flow_zPlus = 0 + "Adsorbate mass flow rate at port '+dz/2'"; + + adsorbateProperties.md_flow_yMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dy/2'"; + adsorbateProperties.md_flow_yPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dy/2'"; + adsorbateProperties.md_flow_zMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dz/2'"; + adsorbateProperties.md_flow_zPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents an adsorbate volume, applying a lumped modeling approach, for +pure component adsorption of an adsorptive described by an ideal gas. Depending +on the volume setup, this model may have up to seven heat ports (i.e., two for +each spatial direction of a cartesian coordinate system and one for sorption). +Furthermore, this model has adsorbate and diffusive (i.e., adsorpt) ports in +y-direction and a sorption fluid port. These ports allow for the combination of +several adsorbate volumes to create a spatially distributed model. +</p> + +<h4>Main equations</h4> +<p> +The most important equations are the momentum, mass, and energy balance. According to +the staggered grid approach, the momentum balance is not solved within the volume but +at the volume's boundaries via so-called +<a href=\"Modelica://SorpLib.Components.Fittings\">flow models</a> or +<a href=\"Modelica://SorpLib.Components.MassTransfer\">mass transfer models</a>. Hennce, +no pressure losses occur within the volume: +</p> +<pre> + p = ap_xMinus.p; +</pre> +<pre> + p = ap_xPlus.p; +</pre> +<pre> + p = fp_sorption.p; +</pre> +<p> +For the diffusive (i.e., adsorpt) ports, the potential variables are the loading: +</p> +<pre> + x = dp_xMinus.x; +</pre> +<pre> + x = dp_xPlus.x; +</pre> + +<p> +Regarding the mass and energy balances, either steady-state or tansient balnaces +can be selected. When using the pressure <i>p</i>, temperature <i>T</i>, and sorbent +mass <i>m<sub>sor</sub></i> as independent states, the adsorbent mass balance is +defined as +</p> +<pre> + (dm<sub>sor</sub>/dτ) = ∑ m<sub>a,sor,flow</sub>; +</pre> +<p> +the adsorpt mass balance is defined as +</p> +<pre> + (dm<sub>adsorpt</sub>/dτ) = (dm<sub>sor</sub>/dτ) * x + m<sub>sor</sub> * (dx/dτ) = (dm<sub>sor</sub>/dτ) * x + m<sub>sor</sub> * [(∂x/∂p)<sub>T</sub> * (dp/dτ) + (∂x/∂T)<sub>p</sub> * (dT/dτ)] = ∑ m<sub>s,flow</sub> + ∑ m<sub>a,s,flow</sub> + ∑ m<sub>d,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU<sub>adsorbate</sub>/dτ) = (dm<sub>sor</sub>/dτ) * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [(du<sub>sor</sub>/dτ) + (d(x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>)/dτ] = (dm<sub>sor</sub>/dτ) * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [(v<sub>sor</sub>) + (h<sub>adsorpt</sub> - p * v<sub>adsorpt</sub>) * (∂x/∂p)<sub>T</sub> - (v<sub>sor</sub> + x<sub>adsorpt</sub> * v<sub>adsorpt</sub>)] * (dp/dτ) + m<sub>sor</sub> * [(c<sub>sor</sub>) + (c<sub>adsorpt</sub> * x<sub>adsorpt</sub> + h<sub>adsorpt</sub> * (∂x/∂T)<sub>p</sub> - x<sub>adsorpt</sub> * (∂v<sub>adsorpt</sub>/∂T)<sub>p</sub> - v<sub>adsorpt</sub> * (∂x/∂T)<sub>p</sub>)] * (dT/dτ) = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +When using the loading <i>x</i>, temperature <i>T</i>, and sorbent mass <i>m<sub>sor</sub></i> +as independent states, the adsorbent mass balance is defined as +</p> +</p> +<pre> + (dm<sub>sor</sub>/dτ) = ∑ m<sub>a,sor,flow</sub>; +</pre> +<p> +the adsorpt mass balance is defined as +</p> +<pre> + (dm<sub>adsorpt</sub>/dτ) = (dm<sub>sor</sub>/dτ) * x + m<sub>sor</sub> * (dx/dτ) = ∑ m<sub>s,flow</sub> + ∑ m<sub>a,s,flow</sub> + ∑ m<sub>d,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU<sub>adsorbate</sub>/dτ) = (dm<sub>sor</sub>/dτ) * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [(du<sub>sor</sub>/dτ) + (d(x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>)/dτ] = (dm<sub>sor</sub>/dτ) * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [(h<sub>adsorpt</sub> - p * v<sub>adsorpt</sub> - x<sub>adsorpt</sub> * v<sub>adsorpt</sub> / (∂x/∂p)<sub>T</sub>)] * (dx/dτ) + m<sub>sor</sub> * [(c<sub>sor</sub>) + (c<sub>adsorpt</sub> * x<sub>adsorpt</sub> - x<sub>adsorpt</sub> * (∂v<sub>adsorpt</sub>/∂T)<sub>p</sub>] * (dT/dτ) = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +Herein, <i>dm<sub>sor</sub>/dτ</i> is the derivative of the adsorbent mass w.r.t. +time, <i>dm<sub>adsorpt</sub>/dτ</i> is the derivative of the adsorpt mass w.r.t. +time, <i>dU<sub>adsorbate</sub>/dτ</i> is the derivative of the uptake-averaged +internal energy w.r.t. time, <i>dp/dτ</i> is the derivative of the pressure w.r.t. +time, <i>dx/dτ</i> is the derivative of the loading w.r.t. time, and <i>dT/dτ</i> +is the derivative of the temperature w.r.t. time, + +The expression <i>(∂x/∂p)<sub>T</sub></i> describes the partial derivative of +the loading w.r.t. pressure at constant temperature, <i>(∂x/∂T)<sub>p</sub></i> +is the partial derivative of the loading w.r.t. temperature at constant pressure, and +<i>(∂v<sub>adsorpt</sub>/∂T)<sub>p</sub></i> is the partial derivative of the +specific volume of the adsorpt w.r.t. temperature at constant pressure. + +The expression <i>m<sub>a,sor,flow</sub></i> is the sum of the adsorbent mass flow rates +across the adsorbate ports, <i>m<sub>s,flow</sub></i> is the sum of the sorption mass +flow rates across the adsorbate ports, <i>m<sub>a,s,flow</sub></i> is the sum of the +sorption mass flow rates, <i>m<sub>d,flow</sub></i> is the sum of the diffusive mass flow +rates, <i>H<sub>b,flow</sub></i> is the sum of the enthalpy flow rates, and +<i>Q<sub>b,flow</sub></i> is the sum of the heat flow rates. + +The variable <i>v<sub>sor</sub></i> describes the specific volume of the adsorbent, +<i>u<sub>sor</sub></i> is the specific internal energy of the adsorbent, <i>c<sub>sor</sub></i> +is the specific heat capacity of the adsorbent, <i><SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub></i> +is the uptake-averaged specific internal energy of the adsorpt, <i>v<sub>adsorpt</sub></i> +is the specific volume of the last adsorbed molecule, <i>h<sub>adsorpt</sub></i> is the +specific enthalpy of the last adsorbed molecule, and <i>c<sub>adsorpt</sub></i> is the +specific heat capacity of the adsorpt. +</p> + + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> + <li> + Adsorption equilibrium with all adsorptive beeing adsorbed and in adsorpt + phase (i.e., chemical equilibrium). + </li> + <li> + The sorbent and adsorpt have the same pressure (i.e., mechanical equilibrium). + </li> + <li> + The sorbent and adsorpt have the same temperature (i.e., thermal equilibrium). + </li> + <li> + Specific volume of the adsorpt may only depend on the temperature and is thus + a macroscopic property without averaging. + </li> + <li> + Specific heat capacity of the adsorpt may only depend on the temperature or is + assumed to already be an uptake-averaged specific heat capacity. + </li> + <li> + Ideal and inert sorbent with constant specific volume. + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to model the adsorbate within adsorber heat exchanger or other +adsorption modules. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useHeatPorts</i>: + Defines if heat ports in the spatial direction <i>i</i> are required. + </li> + <li> + <i>useAdsorbatePorts</i>: + Defines if adsorbate ports are connected (requires uptake-averaged properties). + </li> + <li> + <i>useDiffusivePorts</i>: + Defines if diffusive ports are connected (requires uptake-averaged properties). + </li> + <li> + <i>calcUptakeAveragedProperties</i>: + Defines if duptake-averaged properties are calculated. + </li> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <br/> + <li> + <i>type_adsorbentMassBalance</i>: + Defines the type of the adsorbent mass balance. + </li> + <li> + <i>type_adsorptMassBalance</i>: + Defines the type of the adsorpt mass balance. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +transient mass balances are combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has two dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i> and temperature <i>T</i>, or + </li> + <li> + loading <i>x</i> and temperature <i>T</i> (recommended). + </li> +</ul> +<p> +Furthermore, this model has the adsorbent mass <i>m_sor</i> as dynamic state if the +adsorbate ports are connected to other models (see option 'useAdsorbatePorts'). +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorbatePureGasVolume; diff --git a/SorpLib/Basics/Volumes/AdsorbateVolumes/AdsorbatePureVLEVolume.mo b/SorpLib/Basics/Volumes/AdsorbateVolumes/AdsorbatePureVLEVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..47a7200051cd189ea498c12b4d433d7703378bbf --- /dev/null +++ b/SorpLib/Basics/Volumes/AdsorbateVolumes/AdsorbatePureVLEVolume.mo @@ -0,0 +1,337 @@ +within SorpLib.Basics.Volumes.AdsorbateVolumes; +model AdsorbatePureVLEVolume + "Homogenous adsorbate volume of a real fluid (i.e., with a two-phase regime) for pure component adsorption" + extends + SorpLib.Basics.Volumes.BaseClasses.PartialPureComponentAdsorbateVolume( + redeclare final SorpLib.Basics.Interfaces.FluidPorts.VLEPort_in fp_sorption, + redeclare replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium, + redeclare replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare package Medium = Medium, + stateVariables=independentStateVariables, + calcCaloricProperties=true, + calcEntropicProperties=false, + calcAdsorptAdsorbateState=useAdsorbatePorts, + calcDerivativesIsotherm=true, + calcDerivativesMassEnergyBalance=true, + calcDerivativesEntropyBalance=false, + p_adsorpt=p, + x_adsorpt=x, + T_adsorpt=T, + avoidEvents=avoid_events)); + +equation + // + // Mass balance + // + masor_flow = if useAdsorbatePorts then + ap_xMinus.m_flow + ap_xPlus.m_flow else 0 + "Sum of all adsorbent mass flow rates across adsorbate boundaries"; + mas_flow = if useAdsorbatePorts then (if avoid_events then + ap_xMinus.m_flow * sum(noEvent(actualStream(ap_xMinus.x_outflow))) + + ap_xPlus.m_flow * sum(noEvent(actualStream(ap_xPlus.x_outflow))) else + ap_xMinus.m_flow * sum(actualStream(ap_xMinus.x_outflow)) + + ap_xPlus.m_flow * sum(actualStream(ap_xPlus.x_outflow))) else 0 + "Sum of all sorption mass flow rates across adsorbate boundaries"; + md_flow = sum(dp_xMinus.m_flow) + sum(dp_xPlus.m_flow) + "Sum of all diffusive mass flow rates across boundaries"; + ms_flow = sum(fp_sorption.m_flow) + "Sum of all sorption mass flow rates across boundaries"; + + // + // Energy balance + // + if avoid_events then + if useAdsorbatePorts then + Hb_flow = + ap_xMinus.m_flow * noEvent(actualStream(ap_xMinus.h_outflow)) + + ap_xPlus.m_flow * noEvent(actualStream(ap_xPlus.h_outflow)) + + sum(dp_xMinus.m_flow .* noEvent(actualStream(dp_xMinus.h_outflow))) + + sum(dp_xPlus.m_flow .* noEvent(actualStream(dp_xPlus.h_outflow))) + + sum(fp_sorption.m_flow .* noEvent(actualStream(fp_sorption.h_outflow))) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + sum(dp_xMinus.m_flow .* noEvent(actualStream(dp_xMinus.h_outflow))) + + sum(dp_xPlus.m_flow .* noEvent(actualStream(dp_xPlus.h_outflow))) + + sum(fp_sorption.m_flow .* noEvent(actualStream(fp_sorption.h_outflow))) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + + else + if useAdsorbatePorts then + Hb_flow = + ap_xMinus.m_flow * actualStream(ap_xMinus.h_outflow) + + ap_xPlus.m_flow * actualStream(ap_xPlus.h_outflow) + + sum(dp_xMinus.m_flow .* actualStream(dp_xMinus.h_outflow)) + + sum(dp_xPlus.m_flow .* actualStream(dp_xPlus.h_outflow)) + + sum(fp_sorption.m_flow .* actualStream(fp_sorption.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + sum(dp_xMinus.m_flow .* actualStream(dp_xMinus.h_outflow)) + + sum(dp_xPlus.m_flow .* actualStream(dp_xPlus.h_outflow)) + + sum(fp_sorption.m_flow .* actualStream(fp_sorption.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + end if; + + // + // Summary record + // + adsorbateProperties.ma_flow_yMinus = 0 + "Adsorbate mass flow rate at port '-dy/2'"; + adsorbateProperties.ma_flow_yPlus = 0 + "Adsorbate mass flow rate at port '+dy/2'"; + adsorbateProperties.ma_flow_zMinus = 0 + "Adsorbate mass flow rate at port '-dz/2'"; + adsorbateProperties.ma_flow_zPlus = 0 + "Adsorbate mass flow rate at port '+dz/2'"; + + adsorbateProperties.md_flow_yMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dy/2'"; + adsorbateProperties.md_flow_yPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dy/2'"; + adsorbateProperties.md_flow_zMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dz/2'"; + adsorbateProperties.md_flow_zPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents an adsorbate volume, applying a lumped modeling approach, for +pure component adsorption of an adsorptive described by a real fluid (i.e., with a +two-phase regime). Depending on the volume setup, this model may have up to seven +heat ports (i.e., two for each spatial direction of a cartesian coordinate system +and one for sorption). Furthermore, this model has adsorbate and diffusive (i.e., +adsorpt) ports in y-direction and a sorption fluid port. These ports allow for the +combination of several adsorbate volumes to create a spatially distributed model. +</p> + +<h4>Main equations</h4> +<p> +The most important equations are the momentum, mass, and energy balance. According to +the staggered grid approach, the momentum balance is not solved within the volume but +at the volume's boundaries via so-called +<a href=\"Modelica://SorpLib.Components.Fittings\">flow models</a> or +<a href=\"Modelica://SorpLib.Components.MassTransfer\">mass transfer models</a>. Hennce, +no pressure losses occur within the volume: +</p> +<pre> + p = ap_xMinus.p; +</pre> +<pre> + p = ap_xPlus.p; +</pre> +<pre> + p = fp_sorption.p; +</pre> +<p> +For the diffusive (i.e., adsorpt) ports, the potential variables are the loading: +</p> +<pre> + x = dp_xMinus.x; +</pre> +<pre> + x = dp_xPlus.x; +</pre> + +<p> +Regarding the mass and energy balances, either steady-state or tansient balnaces +can be selected. When using the pressure <i>p</i>, temperature <i>T</i>, and sorbent +mass <i>m<sub>sor</sub></i> as independent states, the adsorbent mass balance is +defined as +</p> +<pre> + (dm<sub>sor</sub>/dτ) = ∑ m<sub>a,sor,flow</sub>; +</pre> +<p> +the adsorpt mass balance is defined as +</p> +<pre> + (dm<sub>adsorpt</sub>/dτ) = (dm<sub>sor</sub>/dτ) * x + m<sub>sor</sub> * (dx/dτ) = (dm<sub>sor</sub>/dτ) * x + m<sub>sor</sub> * [(∂x/∂p)<sub>T</sub> * (dp/dτ) + (∂x/∂T)<sub>p</sub> * (dT/dτ)] = ∑ m<sub>s,flow</sub> + ∑ m<sub>a,s,flow</sub> + ∑ m<sub>d,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU<sub>adsorbate</sub>/dτ) = (dm<sub>sor</sub>/dτ) * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [(du<sub>sor</sub>/dτ) + (d(x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>)/dτ] = (dm<sub>sor</sub>/dτ) * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [(v<sub>sor</sub>) + (h<sub>adsorpt</sub> - p * v<sub>adsorpt</sub>) * (∂x/∂p)<sub>T</sub> - (v<sub>sor</sub> + x<sub>adsorpt</sub> * v<sub>adsorpt</sub>)] * (dp/dτ) + m<sub>sor</sub> * [(c<sub>sor</sub>) + (c<sub>adsorpt</sub> * x<sub>adsorpt</sub> + h<sub>adsorpt</sub> * (∂x/∂T)<sub>p</sub> - x<sub>adsorpt</sub> * (∂v<sub>adsorpt</sub>/∂T)<sub>p</sub> - v<sub>adsorpt</sub> * (∂x/∂T)<sub>p</sub>)] * (dT/dτ) = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +When using the loading <i>x</i>, temperature <i>T</i>, and sorbent mass <i>m<sub>sor</sub></i> +as independent states, the adsorbent mass balance is defined as +</p> +</p> +<pre> + (dm<sub>sor</sub>/dτ) = ∑ m<sub>a,sor,flow</sub>; +</pre> +<p> +the adsorpt mass balance is defined as +</p> +<pre> + (dm<sub>adsorpt</sub>/dτ) = (dm<sub>sor</sub>/dτ) * x + m<sub>sor</sub> * (dx/dτ) = ∑ m<sub>s,flow</sub> + ∑ m<sub>a,s,flow</sub> + ∑ m<sub>d,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU<sub>adsorbate</sub>/dτ) = (dm<sub>sor</sub>/dτ) * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [(du<sub>sor</sub>/dτ) + (d(x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>)/dτ] = (dm<sub>sor</sub>/dτ) * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [(h<sub>adsorpt</sub> - p * v<sub>adsorpt</sub> - x<sub>adsorpt</sub> * v<sub>adsorpt</sub> / (∂x/∂p)<sub>T</sub>)] * (dx/dτ) + m<sub>sor</sub> * [(c<sub>sor</sub>) + (c<sub>adsorpt</sub> * x<sub>adsorpt</sub> - x<sub>adsorpt</sub> * (∂v<sub>adsorpt</sub>/∂T)<sub>p</sub>] * (dT/dτ) = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +Herein, <i>dm<sub>sor</sub>/dτ</i> is the derivative of the adsorbent mass w.r.t. +time, <i>dm<sub>adsorpt</sub>/dτ</i> is the derivative of the adsorpt mass w.r.t. +time, <i>dU<sub>adsorbate</sub>/dτ</i> is the derivative of the uptake-averaged +internal energy w.r.t. time, <i>dp/dτ</i> is the derivative of the pressure w.r.t. +time, <i>dx/dτ</i> is the derivative of the loading w.r.t. time, and <i>dT/dτ</i> +is the derivative of the temperature w.r.t. time, + +The expression <i>(∂x/∂p)<sub>T</sub></i> describes the partial derivative of +the loading w.r.t. pressure at constant temperature, <i>(∂x/∂T)<sub>p</sub></i> +is the partial derivative of the loading w.r.t. temperature at constant pressure, and +<i>(∂v<sub>adsorpt</sub>/∂T)<sub>p</sub></i> is the partial derivative of the +specific volume of the adsorpt w.r.t. temperature at constant pressure. + +The expression <i>m<sub>a,sor,flow</sub></i> is the sum of the adsorbent mass flow rates +across the adsorbate ports, <i>m<sub>s,flow</sub></i> is the sum of the sorption mass +flow rates across the adsorbate ports, <i>m<sub>a,s,flow</sub></i> is the sum of the +sorption mass flow rates, <i>m<sub>d,flow</sub></i> is the sum of the diffusive mass flow +rates, <i>H<sub>b,flow</sub></i> is the sum of the enthalpy flow rates, and +<i>Q<sub>b,flow</sub></i> is the sum of the heat flow rates. + +The variable <i>v<sub>sor</sub></i> describes the specific volume of the adsorbent, +<i>u<sub>sor</sub></i> is the specific internal energy of the adsorbent, <i>c<sub>sor</sub></i> +is the specific heat capacity of the adsorbent, <i><SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub></i> +is the uptake-averaged specific internal energy of the adsorpt, <i>v<sub>adsorpt</sub></i> +is the specific volume of the last adsorbed molecule, <i>h<sub>adsorpt</sub></i> is the +specific enthalpy of the last adsorbed molecule, and <i>c<sub>adsorpt</sub></i> is the +specific heat capacity of the adsorpt. +</p> + + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> + <li> + Adsorption equilibrium with all adsorptive beeing adsorbed and in adsorpt + phase (i.e., chemical equilibrium). + </li> + <li> + The sorbent and adsorpt have the same pressure (i.e., mechanical equilibrium). + </li> + <li> + The sorbent and adsorpt have the same temperature (i.e., thermal equilibrium). + </li> + <li> + Specific volume of the adsorpt may only depend on the temperature and is thus + a macroscopic property without averaging. + </li> + <li> + Specific heat capacity of the adsorpt may only depend on the temperature or is + assumed to already be an uptake-averaged specific heat capacity. + </li> + <li> + Ideal and inert sorbent with constant specific volume. + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to model the adsorbate within adsorber heat exchanger or other +adsorption modules. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useHeatPorts</i>: + Defines if heat ports in the spatial direction <i>i</i> are required. + </li> + <li> + <i>useAdsorbatePorts</i>: + Defines if adsorbate ports are connected (requires uptake-averaged properties). + </li> + <li> + <i>useDiffusivePorts</i>: + Defines if diffusive ports are connected (requires uptake-averaged properties). + </li> + <li> + <i>calcUptakeAveragedProperties</i>: + Defines if duptake-averaged properties are calculated. + </li> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <br/> + <li> + <i>type_adsorbentMassBalance</i>: + Defines the type of the adsorbent mass balance. + </li> + <li> + <i>type_adsorptMassBalance</i>: + Defines the type of the adsorpt mass balance. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +transient mass balances are combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has two dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i> and temperature <i>T</i>, or + </li> + <li> + loading <i>x</i> and temperature <i>T</i> (recommended). + </li> +</ul> +<p> +Furthermore, this model has the adsorbent mass <i>m_sor</i> as dynamic state if the +adsorbate ports are connected to other models (see option 'useAdsorbatePorts'). +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + Major revision (e.g., object-oriented approach, initialization, working pair) after restructering of the library. + </li> + <li> + November 18, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end AdsorbatePureVLEVolume; diff --git a/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/Test_AdsorbatePureGasVolume.mo b/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/Test_AdsorbatePureGasVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..c37a70a0b3a04b4aef54cf498bfbaf22851842b1 --- /dev/null +++ b/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/Test_AdsorbatePureGasVolume.mo @@ -0,0 +1,262 @@ +within SorpLib.Basics.Volumes.AdsorbateVolumes.Tester; +model Test_AdsorbatePureGasVolume + "Tester for pure-component adsorbate volume with an ideal gas" + extends Modelica.Icons.Example; + + // + // Definition of adsorbate models + // + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureGasVolume + adsorbate_cooling_heating( + m_sor_initial=adsorbate_cooling_heating.geometry.V/0.0013793104, + T_initial=373.15, + geometry( + dx=0.2, + dy=0.1, + dz=0.6), + redeclare model PureWorkingPairModel = + Media.WorkingPairs.PureComponents.H2O.Zeolith13X_Toth_WangDouglasLeVan2010_Gas + (approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron), + x_initial=0.05) "Adsorbate volume that is cooled and heated" + annotation (Placement(transformation(extent={{-10,50},{10,70}}))); + + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureGasVolume + adsorbate_adsorption_desorption( + m_sor_initial=adsorbate_cooling_heating.geometry.V/0.0013793104, + T_initial=313.15, + geometry( + dx=0.2, + dy=0.1, + dz=0.6), + redeclare model PureWorkingPairModel = + Media.WorkingPairs.PureComponents.H2O.Zeolith13X_Toth_WangDouglasLeVan2010_Gas + (approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron), + x_initial=0.1, + nSorptionPorts=1) + "Adsorbate volume with adsorption and desorption" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureGasVolume + adsorbate_adsorbatePorts( + m_sor_initial=adsorbate_cooling_heating.geometry.V/0.0013793104, + T_initial=313.15, + geometry( + dx=0.2, + dy=0.1, + dz=0.6), + calcUptakeAveragedProperties=true, + useAdsorbatePorts=true, + redeclare model PureWorkingPairModel = + Media.WorkingPairs.PureComponents.H2O.Zeolith13X_Toth_WangDouglasLeVan2010_Gas + (approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron, + x_adsorpt_lb=1e-2), + x_initial=0.1, + nSorptionPorts=1) + "Adsorbate volume with adsorbate ports" + annotation (Placement(transformation(extent={{-10,-70},{10,-50}}))); + + // + // Definition of fluid boundaries + // +protected + SorpLib.Basics.Sources.Fluids.GasSource fs_adsorbate_adsorption_desorption( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true, + redeclare package Medium = Media.IdealGases.H2O) + "Fluid source for adsorbate volume with adsorption and desorption" + annotation (Placement(transformation(extent={{-30,20},{-10,40}}))); + + SorpLib.Basics.Sources.Fluids.GasSource fs_adsorbate_adsorbatePorts( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true, + redeclare package Medium = Modelica.Media.IdealGases.SingleGases.H2O) + "Fluid source for adsorbate volume with adsorption and desorption" + annotation (Placement(transformation(extent={{-30,-40},{-10,-20}}))); + SorpLib.Basics.Sources.Sorption.AdsorbateSource as_adsorbate_adsorbatePorts_out( + boundaryTypePressure=false, + use_mFlowInput=true, + h_fixed=74547.97, + use_xInput=false, + x_fixed={0.3}) "Adsorbate source for adsorbate volume with adsorbate ports" + annotation (Placement(transformation(extent={{30,-70},{10,-50}}))); + SorpLib.Basics.Sources.Sorption.AdsorbateSource as_adsorbate_adsorbatePorts_in( + boundaryTypePressure=false, + use_mFlowInput=true, + h_fixed=134547.97, + use_xInput=false, + x_fixed={0.1}) "Adsorbate source for adsorbate volume with adsorbate ports" + annotation (Placement(transformation(extent={{-30,-70},{-10,-50}}))); + + // + // Definition of thermal boundaries + // + SorpLib.Basics.Sources.Thermal.HeatSource ts_adsorbate_cooling_heating( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + use_QFlowInput=true) + "Thermal for adsorbate volume that is cooled and heated" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,80}))); + + SorpLib.Basics.Sources.Thermal.HeatSource ts_adsorbate_adsorption_desorption(boundaryType= + SorpLib.Choices.BoundaryThermal.HeatFlowRate, use_QFlowInput=true) + "Thermal for adsorbate volume with adsorption and desorption" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={20,30}))); + + SorpLib.Basics.Sources.Thermal.HeatSource ts_adsorbate_adsorbate_adsorbatePorts(boundaryType= + SorpLib.Choices.BoundaryThermal.HeatFlowRate, use_QFlowInput=true) + "Thermal for adsorbate volume with adsorption and desorption" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={20,-30}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Ramp input_QFlow_adsorbate_cooling_heating( + height=-2000, + duration=2500, + offset=1000) "Input signal for heat flow rate" + annotation (Placement(transformation(extent={{-20,86},{-10,96}}))); + + Modelica.Blocks.Sources.RealExpression + input_mFlow_adsorbate_adsorption_desorption(y=if time < 1250 then min(-1e-3* + (1.7e3 - adsorbate_adsorption_desorption.p), 0) else max(1e-3*( + adsorbate_adsorption_desorption.p - 3.1e3), 0)) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-52,28},{-40,40}}))); + Modelica.Blocks.Sources.RealExpression + input_T_adsorbate_adsorption_desorption(y=if time < 1250 then 273.15 + 15 + else 273.15 + 25) "Input signal for temperature" + annotation (Placement(transformation(extent={{-52,34},{-40,22}}))); + Modelica.Blocks.Sources.RealExpression + input_QFlow_adsorbate_adsorption_desorption(y=if time < 1250 then 100*( + adsorbate_adsorption_desorption.T - (273.15 + 25)) else -100*((273.15 + + 85) - adsorbate_adsorption_desorption.T)) + "Input signal for heat flow rate" + annotation (Placement(transformation(extent={{52,28},{40,40}}))); + + Modelica.Blocks.Sources.RealExpression input_mFlow_adsorbatePorts(y=if time < + 1250 then min(-1e-3*(5e3 - adsorbate_adsorbatePorts.p), 0) else max(1e-3 + *(adsorbate_adsorbatePorts.p - 1.7e3), 0)) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-52,-32},{-40,-20}}))); + Modelica.Blocks.Sources.RealExpression input_T_adsorbatePorts(y=if time < 1250 + then 273.15 + 25 else 273.15 + 160) "Input signal for temperature" + annotation (Placement(transformation(extent={{-52,-26},{-40,-38}}))); + Modelica.Blocks.Sources.RealExpression input_QFlow_adsorbatePorts(y=if time < + 1250 then 1000*(adsorbate_adsorbatePorts.T - (273.15 + 25)) else -1000*( + (273.15 + 160) - adsorbate_adsorbatePorts.T)) + "Input signal for heat flow rate" + annotation (Placement(transformation(extent={{52,-32},{40,-20}}))); + + Modelica.Blocks.Sources.Step input_mFlow_adsorbate_adsorbatePorts_in( + height=2*8.7, + offset=-8.7, + startTime=1250) "Input signal for adsorbate flow rate" + annotation (Placement(transformation(extent={{-52,-56},{-40,-44}}))); + Modelica.Blocks.Sources.Step input_mFlow_adsorbate_adsorbatePorts_out( + height=-2*8.7, + offset=8.7, + startTime=1250) "Input signal for adsorbate flow rate" + annotation (Placement(transformation(extent={{52,-56},{40,-44}}))); + +equation + // + // Connections + // + connect(fs_adsorbate_adsorption_desorption.port, + adsorbate_adsorption_desorption.fp_sorption[1]) annotation (Line( + points={{-20,30},{-1.6,30},{-1.6,4.4}}, + color={244,125,35}, + thickness=1)); + connect(fs_adsorbate_adsorbatePorts.port, adsorbate_adsorbatePorts.fp_sorption[ + 1]) annotation (Line( + points={{-20,-30},{-1.6,-30},{-1.6,-55.6}}, + color={244,125,35}, + thickness=1)); + connect(ts_adsorbate_cooling_heating.port, adsorbate_cooling_heating.hp_sorption) + annotation (Line( + points={{0,80},{0,74},{1.6,74},{1.6,67.6}}, + color={238,46,47}, + thickness=1)); + connect(ts_adsorbate_adsorption_desorption.port, + adsorbate_adsorption_desorption.hp_sorption) annotation (Line( + points={{20,30},{1.6,30},{1.6,7.6}}, + color={238,46,47}, + thickness=1)); + connect(as_adsorbate_adsorbatePorts_in.port, adsorbate_adsorbatePorts.ap_xMinus) + annotation (Line( + points={{-20,-60},{-14,-60},{-14,-58.2},{-4.2,-58.2}}, + color={0,0,0}, + thickness=1)); + connect(as_adsorbate_adsorbatePorts_out.port, adsorbate_adsorbatePorts.ap_xPlus) + annotation (Line( + points={{20,-60},{14,-60},{14,-58.2},{7.8,-58.2}}, + color={0,0,0}, + thickness=1)); + + connect(input_QFlow_adsorbate_cooling_heating.y, ts_adsorbate_cooling_heating.Q_flow_input) + annotation (Line(points={{-9.5,91},{-5,91},{-5,81}}, color={0,0,127})); + connect(input_mFlow_adsorbate_adsorption_desorption.y, + fs_adsorbate_adsorption_desorption.m_flow_input) annotation (Line(points={{-39.4, + 34},{-30,34},{-30,32},{-21.2,32}}, color={0,0,127})); + connect(input_T_adsorbate_adsorption_desorption.y, + fs_adsorbate_adsorption_desorption.T_input) + annotation (Line(points={{-39.4,28},{-21.2,28}}, color={0,0,127})); + connect(input_QFlow_adsorbate_adsorption_desorption.y, + ts_adsorbate_adsorption_desorption.Q_flow_input) annotation (Line(points={{39.4, + 34},{30,34},{30,35},{21,35}}, color={0,0,127})); + connect(input_mFlow_adsorbate_adsorbatePorts_in.y, + as_adsorbate_adsorbatePorts_in.m_flow_input) annotation (Line(points={{-39.4, + -50},{-32,-50},{-32,-58},{-21.2,-58}}, color={0,0,127})); + connect(input_mFlow_adsorbate_adsorbatePorts_out.y, + as_adsorbate_adsorbatePorts_out.m_flow_input) annotation (Line(points={{39.4, + -50},{30,-50},{30,-58},{21.2,-58}}, color={0,0,127})); + connect(ts_adsorbate_adsorbate_adsorbatePorts.port, adsorbate_adsorbatePorts.hp_sorption) + annotation (Line( + points={{20,-30},{1.6,-30},{1.6,-52.4}}, + color={238,46,47}, + thickness=1)); + connect(input_mFlow_adsorbatePorts.y, fs_adsorbate_adsorbatePorts.m_flow_input) + annotation (Line(points={{-39.4,-26},{-30,-26},{-30,-28},{-21.2,-28}}, + color={0,0,127})); + connect(input_T_adsorbatePorts.y, fs_adsorbate_adsorbatePorts.T_input) + annotation (Line(points={{-39.4,-32},{-21.2,-32}}, color={0,0,127})); + connect(input_QFlow_adsorbatePorts.y, ts_adsorbate_adsorbate_adsorbatePorts.Q_flow_input) + annotation (Line(points={{39.4,-26},{30,-26},{30,-25},{21,-25}}, color={0,0, + 127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the model of an adsorbate volume for pure comonent adsorption +using an ideal gas +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + Extension and added documentation. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_AdsorbatePureGasVolume; diff --git a/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/Test_AdsorbatePureVLEVolume.mo b/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/Test_AdsorbatePureVLEVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..c5ac7ffcd27c56b117e7fa514d2cee93c3d2dcf3 --- /dev/null +++ b/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/Test_AdsorbatePureVLEVolume.mo @@ -0,0 +1,272 @@ +within SorpLib.Basics.Volumes.AdsorbateVolumes.Tester; +model Test_AdsorbatePureVLEVolume + "Tester for pure-component adsorbate volume with a real fluid" + extends Modelica.Icons.Example; + + // + // Definition of adsorbate models + // + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureVLEVolume + adsorbate_cooling_heating( + m_sor_initial=adsorbate_cooling_heating.geometry.V/0.0013793104, + T_initial=373.15, + geometry( + dx=0.2, + dy=0.1, + dz=0.6), + redeclare model PureWorkingPairModel = + Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl, + limitLowerPressure=true, + limitLowerPressureAdsorptive=true), + x_initial=0.05) "Adsorbate volume that is cooled and heated" + annotation (Placement(transformation(extent={{-10,50},{10,70}}))); + + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureVLEVolume + adsorbate_adsorption_desorption( + m_sor_initial=adsorbate_cooling_heating.geometry.V/0.0013793104, + T_initial=313.15, + geometry( + dx=0.2, + dy=0.1, + dz=0.6), + redeclare model PureWorkingPairModel = + Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl, + limitLowerPressure=true, + limitLowerPressureAdsorptive=true), + x_initial=0.1, + nSorptionPorts=1) + "Adsorbate volume with adsorption and desorption" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureVLEVolume + adsorbate_adsorbatePorts( + m_sor_initial=adsorbate_cooling_heating.geometry.V/0.0013793104, + T_initial=313.15, + geometry( + dx=0.2, + dy=0.1, + dz=0.6), + calcUptakeAveragedProperties=true, + useAdsorbatePorts=true, + redeclare model PureWorkingPairModel = + Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl, + limitLowerPressure=true, + limitLowerPressureAdsorptive=true, + x_adsorpt_lb=1e-2), + x_initial=0.1, + nSorptionPorts=1) + "Adsorbate volume with adsorbate ports" + annotation (Placement(transformation(extent={{-10,-70},{10,-50}}))); + + // + // Definition of fluid boundaries + // +protected + SorpLib.Basics.Sources.Fluids.VLESource fs_adsorbate_adsorption_desorption( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true) + "Fluid source for adsorbate volume with adsorption and desorption" + annotation (Placement(transformation(extent={{-30,20},{-10,40}}))); + + SorpLib.Basics.Sources.Fluids.VLESource fs_adsorbate_adsorbatePorts( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true) + "Fluid source for adsorbate volume with adsorption and desorption" + annotation (Placement(transformation(extent={{-30,-40},{-10,-20}}))); + SorpLib.Basics.Sources.Sorption.AdsorbateSource as_adsorbate_adsorbatePorts_out( + boundaryTypePressure=false, + use_mFlowInput=true, + h_fixed=74547.97, + use_xInput=false, + x_fixed={0.3}) "Adsorbate source for adsorbate volume with adsorbate ports" + annotation (Placement(transformation(extent={{30,-70},{10,-50}}))); + SorpLib.Basics.Sources.Sorption.AdsorbateSource as_adsorbate_adsorbatePorts_in( + boundaryTypePressure=false, + use_mFlowInput=true, + h_fixed=134547.97, + use_xInput=false, + x_fixed={0.1}) "Adsorbate source for adsorbate volume with adsorbate ports" + annotation (Placement(transformation(extent={{-30,-70},{-10,-50}}))); + + // + // Definition of thermal boundaries + // + SorpLib.Basics.Sources.Thermal.HeatSource ts_adsorbate_cooling_heating( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + use_QFlowInput=true) + "Thermal for adsorbate volume that is cooled and heated" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,80}))); + + SorpLib.Basics.Sources.Thermal.HeatSource ts_adsorbate_adsorption_desorption(boundaryType= + SorpLib.Choices.BoundaryThermal.HeatFlowRate, use_QFlowInput=true) + "Thermal for adsorbate volume with adsorption and desorption" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={20,30}))); + + SorpLib.Basics.Sources.Thermal.HeatSource ts_adsorbate_adsorbate_adsorbatePorts(boundaryType= + SorpLib.Choices.BoundaryThermal.HeatFlowRate, use_QFlowInput=true) + "Thermal for adsorbate volume with adsorption and desorption" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={20,-30}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Ramp input_QFlow_adsorbate_cooling_heating( + height=-2000, + duration=2500, + offset=1000) "Input signal for heat flow rate" + annotation (Placement(transformation(extent={{-20,86},{-10,96}}))); + + Modelica.Blocks.Sources.RealExpression + input_mFlow_adsorbate_adsorption_desorption(y=if time < 1250 then min(-1e-3* + (1.7e3 - adsorbate_adsorption_desorption.p), 0) else max(1e-3*( + adsorbate_adsorption_desorption.p - 3.1e3), 0)) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-52,28},{-40,40}}))); + Modelica.Blocks.Sources.RealExpression + input_T_adsorbate_adsorption_desorption(y=if time < 1250 then 273.15 + 15 + else 273.15 + 25) "Input signal for temperature" + annotation (Placement(transformation(extent={{-52,34},{-40,22}}))); + Modelica.Blocks.Sources.RealExpression + input_QFlow_adsorbate_adsorption_desorption(y=if time < 1250 then 100*( + adsorbate_adsorption_desorption.T - (273.15 + 25)) else -100*((273.15 + + 85) - adsorbate_adsorption_desorption.T)) + "Input signal for heat flow rate" + annotation (Placement(transformation(extent={{52,28},{40,40}}))); + + Modelica.Blocks.Sources.RealExpression input_mFlow_adsorbatePorts(y=if time < + 1250 then min(-1e-3*(5e3 - adsorbate_adsorbatePorts.p), 0) else max(1e-3 + *(adsorbate_adsorbatePorts.p - 1.7e3), 0)) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-52,-32},{-40,-20}}))); + Modelica.Blocks.Sources.RealExpression input_T_adsorbatePorts(y=if time < 1250 + then 273.15 + 25 else 273.15 + 160) "Input signal for temperature" + annotation (Placement(transformation(extent={{-52,-26},{-40,-38}}))); + Modelica.Blocks.Sources.RealExpression input_QFlow_adsorbatePorts(y=if time < + 1250 then 1000*(adsorbate_adsorbatePorts.T - (273.15 + 25)) else -1000*( + (273.15 + 160) - adsorbate_adsorbatePorts.T)) + "Input signal for heat flow rate" + annotation (Placement(transformation(extent={{52,-32},{40,-20}}))); + + Modelica.Blocks.Sources.Step input_mFlow_adsorbate_adsorbatePorts_in( + height=2*8.7, + offset=-8.7, + startTime=1250) "Input signal for adsorbate flow rate" + annotation (Placement(transformation(extent={{-52,-56},{-40,-44}}))); + Modelica.Blocks.Sources.Step input_mFlow_adsorbate_adsorbatePorts_out( + height=-2*8.7, + offset=8.7, + startTime=1250) "Input signal for adsorbate flow rate" + annotation (Placement(transformation(extent={{52,-56},{40,-44}}))); + +equation + // + // Connections + // + connect(fs_adsorbate_adsorption_desorption.port, + adsorbate_adsorption_desorption.fp_sorption[1]) annotation (Line( + points={{-20,30},{-1.6,30},{-1.6,4.4}}, + color={0,140,72}, + thickness=1)); + connect(fs_adsorbate_adsorbatePorts.port, adsorbate_adsorbatePorts.fp_sorption[ + 1]) annotation (Line( + points={{-20,-30},{-1.6,-30},{-1.6,-55.6}}, + color={0,140,72}, + thickness=1)); + connect(ts_adsorbate_cooling_heating.port, adsorbate_cooling_heating.hp_sorption) + annotation (Line( + points={{0,80},{0,74},{1.6,74},{1.6,67.6}}, + color={238,46,47}, + thickness=1)); + connect(ts_adsorbate_adsorption_desorption.port, + adsorbate_adsorption_desorption.hp_sorption) annotation (Line( + points={{20,30},{1.6,30},{1.6,7.6}}, + color={238,46,47}, + thickness=1)); + connect(as_adsorbate_adsorbatePorts_in.port, adsorbate_adsorbatePorts.ap_xMinus) + annotation (Line( + points={{-20,-60},{-14,-60},{-14,-58.2},{-4.2,-58.2}}, + color={0,0,0}, + thickness=1)); + connect(as_adsorbate_adsorbatePorts_out.port, adsorbate_adsorbatePorts.ap_xPlus) + annotation (Line( + points={{20,-60},{14,-60},{14,-58.2},{7.8,-58.2}}, + color={0,0,0}, + thickness=1)); + + connect(input_QFlow_adsorbate_cooling_heating.y, ts_adsorbate_cooling_heating.Q_flow_input) + annotation (Line(points={{-9.5,91},{-5,91},{-5,81}}, color={0,0,127})); + connect(input_mFlow_adsorbate_adsorption_desorption.y, + fs_adsorbate_adsorption_desorption.m_flow_input) annotation (Line(points={{-39.4, + 34},{-30,34},{-30,32},{-21.2,32}}, color={0,0,127})); + connect(input_T_adsorbate_adsorption_desorption.y, + fs_adsorbate_adsorption_desorption.T_input) + annotation (Line(points={{-39.4,28},{-21.2,28}}, color={0,0,127})); + connect(input_QFlow_adsorbate_adsorption_desorption.y, + ts_adsorbate_adsorption_desorption.Q_flow_input) annotation (Line(points={{39.4, + 34},{30,34},{30,35},{21,35}}, color={0,0,127})); + connect(input_mFlow_adsorbate_adsorbatePorts_in.y, + as_adsorbate_adsorbatePorts_in.m_flow_input) annotation (Line(points={{-39.4, + -50},{-32,-50},{-32,-58},{-21.2,-58}}, color={0,0,127})); + connect(input_mFlow_adsorbate_adsorbatePorts_out.y, + as_adsorbate_adsorbatePorts_out.m_flow_input) annotation (Line(points={{39.4, + -50},{30,-50},{30,-58},{21.2,-58}}, color={0,0,127})); + connect(ts_adsorbate_adsorbate_adsorbatePorts.port, adsorbate_adsorbatePorts.hp_sorption) + annotation (Line( + points={{20,-30},{1.6,-30},{1.6,-52.4}}, + color={238,46,47}, + thickness=1)); + connect(input_mFlow_adsorbatePorts.y, fs_adsorbate_adsorbatePorts.m_flow_input) + annotation (Line(points={{-39.4,-26},{-30,-26},{-30,-28},{-21.2,-28}}, + color={0,0,127})); + connect(input_T_adsorbatePorts.y, fs_adsorbate_adsorbatePorts.T_input) + annotation (Line(points={{-39.4,-32},{-21.2,-32}}, color={0,0,127})); + connect(input_QFlow_adsorbatePorts.y, ts_adsorbate_adsorbate_adsorbatePorts.Q_flow_input) + annotation (Line(points={{39.4,-26},{30,-26},{30,-25},{21,-25}}, color={0,0, + 127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the model of an adsorbate volume for pure comonent adsorption +using a real fluid with a two-phase regime. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + Extension and added documentation. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_AdsorbatePureVLEVolume; diff --git a/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/package.mo b/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..7aebcf284ad8210d1ea798268ae0361b7b140403 --- /dev/null +++ b/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Basics.Volumes.AdsorbateVolumes; +package Tester "Models to test and varify models of adsorbate volumes" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented adsorbate +volumes. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/package.order b/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..0722318b37b1802c40df330598f396d1ded59059 --- /dev/null +++ b/SorpLib/Basics/Volumes/AdsorbateVolumes/Tester/package.order @@ -0,0 +1,2 @@ +Test_AdsorbatePureGasVolume +Test_AdsorbatePureVLEVolume diff --git a/SorpLib/Basics/Volumes/AdsorbateVolumes/package.mo b/SorpLib/Basics/Volumes/AdsorbateVolumes/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..4ee6fda85a593b2eff8d767d3f1facc2f82fe9eb --- /dev/null +++ b/SorpLib/Basics/Volumes/AdsorbateVolumes/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Basics.Volumes; +package AdsorbateVolumes "Package containing finte volume models of adsorbates" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains finite volume models of adsorbates. This package calculates +fluid properties based on the open-source Modelica Standard Library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end AdsorbateVolumes; diff --git a/SorpLib/Basics/Volumes/AdsorbateVolumes/package.order b/SorpLib/Basics/Volumes/AdsorbateVolumes/package.order new file mode 100644 index 0000000000000000000000000000000000000000..25ad706bee19cf585e01228aea3ac19c498d05da --- /dev/null +++ b/SorpLib/Basics/Volumes/AdsorbateVolumes/package.order @@ -0,0 +1,3 @@ +AdsorbatePureGasVolume +AdsorbatePureVLEVolume +Tester diff --git a/SorpLib/Basics/Volumes/BaseClasses/PartialAdsorbateVolume.mo b/SorpLib/Basics/Volumes/BaseClasses/PartialAdsorbateVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..a46c9b2b35226f319ab6288064a6c69092e3b80b --- /dev/null +++ b/SorpLib/Basics/Volumes/BaseClasses/PartialAdsorbateVolume.mo @@ -0,0 +1,387 @@ +within SorpLib.Basics.Volumes.BaseClasses; +partial model PartialAdsorbateVolume + "Base model for all adsorbate volumes" + + // + // Definition of parameters describing media + // + parameter Integer no_components = 1 + "Number of components in the medium" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true); + parameter Integer no_adsorptivs(min=1, max=no_components) = 1 + "Number of adsorptivs (i.e., components that can be adsorbed/desorbed)" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.Mass m_sor_initial = geometry.V * 725 + "Initial value of adsorbent mass" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + parameter Modelica.Units.SI.Temperature T_initial = 298.15 + "Initial value of temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + + parameter Modelica.Units.SI.MassFlowRate msor_flow_initialX = 1e-4 + "Start value for adsorbent mass flow rate in x direction" + annotation (Dialog(tab="Initialisation", group="Start Values")); + parameter Modelica.Units.SI.MassFlowRate ms_flow_initial = 1e-4 + "Start value for sorption mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + parameter Modelica.Units.SI.MassFlowRate md_flow_initialX = 1e-4 + "Start value for diffusive mass flow rates in x direction" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + extends SorpLib.Basics.Volumes.BaseClasses.PartialVolume; + + // + // Definition of parameters regarding calculation setup + // + parameter Boolean calcUptakeAveragedProperties = false + " = true, if uptake-averaged adsorpt and abosrabte properties are calculated" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding volume setup + // + parameter Boolean useAdsorbatePorts = false + " = true, if adsorbate ports are connected outside the model and, thus, + are considered within the mass and energy balance (i.e., uptake-averaged + adsorbate properties are required)" + annotation (Dialog(tab="Volume Setup", group="Fluid Ports", + enable=calcUptakeAveragedProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useDiffusivePorts = false + " = true, if diffusive ports are connected outside the model (i.e., uptake- + averaged adsorpt properties are required)" + annotation (Dialog(tab="Volume Setup", group="Fluid Ports", + enable=calcUptakeAveragedProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + // + // Definition of advanced parameters + // + parameter SorpLib.Choices.BalanceEquations type_adsorbentMassBalance= + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial + "Handling of the adsorbent mass balance and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations", + enable=useAdsorbatePorts), + Evaluate=true, + HideResult=true); + parameter SorpLib.Choices.BalanceEquations type_adsorptMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial + "Handling of the adsorpt mass balances and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult=true); + + // + // Definition of ports + // + SorpLib.Basics.Interfaces.SorptionPorts.AdsorbatePort_in ap_xMinus( + final no_adsorptivs=no_adsorptivs, + m_flow(start=msor_flow_initialX)) + "Adsorbate fluid port at position '-dx/2'" + annotation (Placement(transformation(extent={{-46,14},{-38,22}}), + iconTransformation(extent={{-46,14},{-38,22}}))); + SorpLib.Basics.Interfaces.SorptionPorts.AdsorbatePort_in ap_xPlus( + final no_adsorptivs=no_adsorptivs, + m_flow(start=-msor_flow_initialX)) + "Adsorbate fluid port at position '+dx/2'" + annotation (Placement(transformation(extent={{74,14},{82,22}}), + iconTransformation(extent={{74,14},{82,22}}))); + + SorpLib.Basics.Interfaces.SorptionPorts.AdsorptPort_in[no_adsorptivs] dp_xMinus( + m_flow(each start=-md_flow_initialX)) + "Diffusive fluid port at position '-dx/2'" + annotation (Placement(transformation(extent={{-82,-22},{-74,-14}}), + iconTransformation(extent={{-82,-22},{-74,-14}}))); + SorpLib.Basics.Interfaces.SorptionPorts.AdsorptPort_out[no_adsorptivs] dp_xPlus( + m_flow(each start=md_flow_initialX)) + "Diffusive fluid port at position '+dx/2'" + annotation (Placement(transformation(extent={{38,-22},{46,-14}}), + iconTransformation(extent={{38,-22},{46,-14}}))); + + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_sorption + "Sorption heat port" + annotation (Placement(transformation(extent={{10,70},{22,82}}), + iconTransformation(extent={{10,70},{22,82}}))); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p + "Pressure"; + Modelica.Units.SI.Temperature T( + start=T_initial, + stateSelect=StateSelect.prefer) + "Temperature"; + SorpLib.Units.Uptake x + "Uptake"; + + Modelica.Units.SI.SpecificEnthalpy h( + stateSelect=StateSelect.avoid) + "Uptake-averaged specific enthalpy: h_sor + x * h_avg_adsorpt"; + Modelica.Units.SI.SpecificInternalEnergy u + "Uptake-averaged specific internal energy: u_sor + x * u_avg_adsorpt"; + + Modelica.Units.SI.Mass m_adsorbate + "Adsorbate mass (i.e., total mass)"; + Modelica.Units.SI.Mass m_sor( + start=m_sor_initial, + stateSelect= if useAdsorbatePorts then + StateSelect.prefer else StateSelect.avoid) + "Adsorbent mass"; + Modelica.Units.SI.Mass m_adsorpt + "Adsorpt mass"; + + Modelica.Units.SI.MassFlowRate dm_adsorbate_dtau + "Derivative of adsorbate mass (i.e., total mass) w.r.t. time"; + Modelica.Units.SI.MassFlowRate dm_sor_dtau + "Derivative of adsorbent mass w.r.t. time"; + Modelica.Units.SI.MassFlowRate dm_adsorpt_dtau + "Derivative of adsorpt mass w.r.t. time"; + + Modelica.Units.SI.MassFlowRate masor_flow + "Sum of all adsorbent mass flow rates across adsorbate boundaries"; + Modelica.Units.SI.MassFlowRate mas_flow + "Sum of all sorption mass flow rates across adsorbate boundaries"; + Modelica.Units.SI.MassFlowRate ms_flow + "Sum of all sorption mass flow rates across boundaries"; + Modelica.Units.SI.MassFlowRate md_flow + "Sum of all diffusive mass flow rates across boundaries"; + + Modelica.Units.SI.InternalEnergy U + "Uptake-averaged internal energy"; + Real dU_dtau(final unit="W") + "Derivative of uptake-averaged internal energy w.r.t. time"; + Modelica.Units.SI.EnthalpyFlowRate Hb_flow + "Sum of all enthalpy flow rates across boundaries"; + Modelica.Units.SI.HeatFlowRate Qb_flow + "Sum of all heat flow rates across boundaries"; + + SorpLib.Basics.Volumes.Records.AdsorbateVolumeProperties adsorbateProperties( + final no_adsorptivs=no_adsorptivs) + "Properties of fluid volume often required for calculation of heat transfer"; + +initial equation + if useAdsorbatePorts then + if type_adsorbentMassBalance == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + m_sor = m_sor_initial + "Fixed initial value"; + + elseif type_adsorbentMassBalance == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + der(m_sor) = 0 + "Steady-state initialisation of overall mass balance"; + + end if; + end if; + + if type_energyBalance == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + T = T_initial + "Fixed initial value"; + + elseif type_energyBalance == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + der(T) = 0 + "Steady-state initial value"; + + end if; + +equation + // + // Momentum balance + // + ap_xMinus.p = p + "Total pressure at the port (i.e., homogenous volume)"; + ap_xPlus.p = p + "Total pressure at the port (i.e., homogenous volume)"; + + // + // Mass balance + // + m_adsorbate = m_sor + m_adsorpt + "Adsorbate mass (i.e., total mass)"; + m_adsorpt = x * m_sor + "Adsorpt mass"; + + dm_adsorbate_dtau = dm_adsorpt_dtau + dm_sor_dtau + "Adsorbate mass balance (i.e., total mass balance)"; + dm_sor_dtau = masor_flow + "Derivative of adsorbent mass w.r.t. time"; + dm_adsorpt_dtau = ms_flow + md_flow + mas_flow + "Adsorpt mass balance"; + + if useAdsorbatePorts then + if type_adsorbentMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_sor_dtau = 0 + "Steady-state adsorbent mass balance"; + + else + dm_sor_dtau = der(m_sor) + "Transient adsorbent mass balance"; + + end if; + + else + m_sor = m_sor_initial + "Sorbent mass cannot change as adsorbate ports are not used"; + + end if; + + // + // Energy balance + // + U = m_adsorbate * u + "Uptake-averaged internal energy"; + + dU_dtau = Hb_flow + Qb_flow + "Energy balane"; + + Qb_flow = Q_flow_xMinus + Q_flow_xPlus + + Q_flow_yMinus + Q_flow_yPlus + + Q_flow_zMinus + Q_flow_zPlus + + hp_sorption.Q_flow + "Sum of all heat flow rates across boundaries"; + + T_heatPorts = T + "Required for conditional component"; + + ap_xMinus.h_outflow = h + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + ap_xPlus.h_outflow = h + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + + hp_sorption.T = T_heatPorts + "Temperature at sorption heat port"; + + // + // Summary record + // + adsorbateProperties.p = p + "Pressure"; + adsorbateProperties.T = T + "Temperature"; + adsorbateProperties.x = x + "Total loading"; + + adsorbateProperties.ma_flow_xMinus = if useAdsorbatePorts then ap_xMinus.m_flow * + (1 + (if avoid_events then sum(noEvent(actualStream(ap_xMinus.x_outflow))) + else sum(actualStream(ap_xMinus.x_outflow)))) else 0 + "Adsorbate mass flow rate at port '-dx/2'"; + adsorbateProperties.ma_flow_xPlus = if useAdsorbatePorts then ap_xPlus.m_flow * + (1 + (if avoid_events then sum(noEvent(actualStream(ap_xPlus.x_outflow))) + else sum(actualStream(ap_xPlus.x_outflow)))) else 0 + "Adsorbate mass flow rate at port '+dx/2'"; + + adsorbateProperties.md_flow_xMinus = dp_xMinus.m_flow + "Diffusive mass flow rate at port '-dx/2'"; + adsorbateProperties.md_flow_xPlus = dp_xPlus.m_flow + "Diffusive mass flow rate at port '+dx/2'"; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle(extent={{-90,30},{30,-90}}, lineColor={0,0,0}), + Line(points={{-90,30},{-30,90}}, color={0,0,0}), + Line( + points={{-30,-30},{-90,-90}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line(points={{90,-30},{30,-90}}, color={0,0,0}), + Line(points={{90,90},{30,30}}, color={0,0,0}), + Line(points={{-30,90},{90,90},{90,-30}}, color={0,0,0}), + Line( + points={{90,-30},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line( + points={{-30,90},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash)}), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the base model of all adsorbate volumes. It defines the +volume geometry, heat ports in all spatial directions, as well as adsorbate and +diffusive (i.e., adsorpt) ports in x-direction. The required heat ports can be +adjusted via the volume setup. Furthermore, this model defines fundamental variables +for the momentum, mass, and energy balance, as well as the initialization of these +balances. +<br/><br/> +Models that inherit properties from this partial model must add a sorption port. +Further, inherting models may have to add further adsorbate and diffusive (i.e., +adsorpt) ports in the required spatial direction (e.g., y- or z-direction). +Furthermore, conservation equations must be added. In this context, appropriate +working pair models are required. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Pressure <i>p</i> or loading <i>x</i> in dependence of the independent state + variables. + </li> + <li> + Uptake-averaged specific enthalpy <i>h</i>. + </li> + <li> + Uptake-averaged specific internal energy <i>u</i>. + </li> + <br/> + <li> + Partial derivative of the adsorpt mass w.r.t. time <i>dm_adsorpt_dtau</i>. + </li> + <li> + Sum of all adsorbent mass flow rates across adsorbate boundaries <i>masor_flow</i>. + </li> + <li> + Sum of all adsorpt mass flow rates across adsorbate boundaries <i>mas_flow</i>. + </li> + <li> + Sum of all sorption mass flow rates across sorption boundaries <i>ms_flow</i>. + </li> + <br/> + <li> + Partial derivative of the uptake-averaged internal energy w.r.t. time <i>dU_dtau</i>. + </li> + <li> + Sum of all enthalpy flow rates across boundaries <i>Hb_flow</i>. + </li> + <br/> + <li> + Variables of the summary record except for pressure <i>p</i>, temperature <i>T</i>, + total loading <i>x</i>, adsorbate mass flow rates in x-direction + <i>ma_flow_xMinus</i>/<i>ma_flow_xPlus</i>, and diffusive mass flow rates in + x-direction <i>md_flow_xMinus</i>/<i>md_flow_xPlus</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialAdsorbateVolume; diff --git a/SorpLib/Basics/Volumes/BaseClasses/PartialFluidVolume.mo b/SorpLib/Basics/Volumes/BaseClasses/PartialFluidVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..da7b7e023af560a281726098d6a0811a35f51a4c --- /dev/null +++ b/SorpLib/Basics/Volumes/BaseClasses/PartialFluidVolume.mo @@ -0,0 +1,350 @@ +within SorpLib.Basics.Volumes.BaseClasses; +partial model PartialFluidVolume + "Base model for all fluid-based volumes" + + // + // Definition of parameters describing media + // + parameter Integer no_components = 1 + "Number of components in the medium" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding classes + // + replaceable connector FluidPortsIn = + SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_in + constrainedby SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort + "Fluid ports for inlet design direction" + annotation (Dialog(tab="Volume Setup", group="Classes"), + Evaluate=true, + HideResult=true); + replaceable connector FluidPortsOut = + SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_out + constrainedby SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort + "Fluid ports for outlet design direction" + annotation (Dialog(tab="Volume Setup", group="Classes"), + Evaluate=true, + HideResult=true); + + parameter Integer nPorts_cfp_xMinus=0 + "Number of ports at cfp_xMinus" + annotation (Dialog(connectorSizing=true), + HideResult=true); + parameter Integer nPorts_cfp_xPlus=0 + "Number of ports at cfp_xPlus" + annotation (Dialog(connectorSizing=true), + HideResult=true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.Pressure p_initial = 1e5 + "Initial value of pressure" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + parameter Modelica.Units.SI.Temperature T_initial = 298.15 + "Initial value of temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=(independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX))); + parameter Modelica.Units.SI.SpecificEnthalpy h_initial = 0 + "Initial value of specific enthalpy" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=(independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX))); + + parameter Modelica.Units.SI.MassFlowRate mc_flow_initialX = 1e-4 + "Start value for convective mass flow rate in x direction" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + extends SorpLib.Basics.Volumes.BaseClasses.PartialVolume; + + // + // Definition of parameters regarding calculation setup + // + parameter SorpLib.Choices.IndependentVariablesVolume independentStateVariables= + SorpLib.Choices.IndependentVariablesVolume.phX + "Independent state variables" + annotation (Dialog(tab="General", group="Calculation Setup"), + Evaluate=true, + HideResult = true); + parameter Boolean pressureNoStateVariable = true + " = true, if pressure is not a state variable and is not needed to calculate + fluid properties like density (e.g., incompressible fluid)" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Boolean neglectTermVp = false + " = true, if term p * v is neglected for the specific internal energy (i.e., + u = h)" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Boolean calculateAdditionalProperties = false + "= true, if additional properties required for tranport models are calculated" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of advanced parameters + // + parameter SorpLib.Choices.BalanceEquations type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial + "Handling of the overall mass balance and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult=true); + + // + // Definition of ports + // + FluidPortsIn[nPorts_cfp_xMinus] cfp_xMinus( + each final no_components=no_components, + m_flow(each start=mc_flow_initialX)) + "Convective fluid port at position '-dx/2'" + annotation (Placement(transformation(extent={{-46,14},{-38,22}}), + iconTransformation(extent={{-46,14},{-38,22}}))); + FluidPortsOut[nPorts_cfp_xPlus] cfp_xPlus( + each final no_components=no_components, + m_flow(each start=-mc_flow_initialX)) + "Convective fluid port at position '+dx/2'" + annotation (Placement(transformation(extent={{74,14},{82,22}}), + iconTransformation(extent={{74,14},{82,22}}))); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p( + start=p_initial, + stateSelect= if not pressureNoStateVariable then StateSelect.prefer + else StateSelect.avoid) + "Pressure"; + Modelica.Units.SI.Temperature T( + start=T_initial, + stateSelect= if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then StateSelect.prefer + else StateSelect.avoid) + "Temperature"; + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + Modelica.Units.SI.Density rho + "Density"; + + Modelica.Units.SI.SpecificEnthalpy h( + start=h_initial, + stateSelect= if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX then StateSelect.prefer + else StateSelect.avoid) + "Specific enthalpy"; + Modelica.Units.SI.SpecificInternalEnergy u + "Specific internal energy"; + + Modelica.Units.SI.Mass m + "Mass"; + Modelica.Units.SI.MassFlowRate dm_dtau + "Derivative of mass w.r.t. time"; + Modelica.Units.SI.MassFlowRate mc_flow + "Sum of all convective mass flow rates across boundaries"; + + Modelica.Units.SI.InternalEnergy U + "Internal energy"; + Real dU_dtau(final unit="W") + "Derivative of internal energy w.r.t. time"; + Modelica.Units.SI.EnthalpyFlowRate Hb_flow + "Sum of all enthalpy flow rates across boundaries"; + Modelica.Units.SI.HeatFlowRate Qb_flow + "Sum of all heat flow rates across boundaries"; + + SorpLib.Basics.Volumes.Records.FluidVolumeProperties fluidProperties( + final no_components=no_components) + "Properties of fluid volume often required for calculation of heat transfer"; + +initial equation + if not pressureNoStateVariable and type_overallMassBalance == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + p = p_initial + "Fixed initial value"; + + elseif not pressureNoStateVariable and type_overallMassBalance == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + der(p) = 0 + "Steady-state initialisation of overall mass balance"; + + end if; + + if type_energyBalance == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + T = T_initial + "Fixed initial value"; + + else + h = h_initial + "Fixed initial value"; + + end if; + + elseif type_energyBalance == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + der(T) = 0 + "Steady-state initial value"; + + else + der(h) = 0 + "Steady-state initial value"; + + end if; + end if; + +equation + // + // Property calculation + // + u = if neglectTermVp then h else h - p * v + "Specific internal energy"; + + // + // Momentum balance + // + cfp_xMinus.p = fill(p, nPorts_cfp_xMinus) + "Total pressure at the port (i.e., homogenous volume)"; + cfp_xPlus.p = fill(p, nPorts_cfp_xPlus) + "Total pressure at the port (i.e., homogenous volume)"; + + // + // Mass balance + // + m = geometry.V / v + "Mass"; + + // + // Energy balance + // + U = m * u + "Internal energy"; + + cfp_xMinus.h_outflow = fill(h, nPorts_cfp_xMinus) + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + cfp_xPlus.h_outflow = fill(h, nPorts_cfp_xPlus) + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + + T_heatPorts = T + "Required for conditional component"; + + // + // Summary record + // + fluidProperties.p = p + "Pressure"; + fluidProperties.T = T + "Temperature"; + fluidProperties.v = v + "Specific volume"; + + fluidProperties.mc_flow_xMinus = sum(cfp_xMinus.m_flow) + "Total convective mass flow rate at port '-dx/2'"; + fluidProperties.mc_flow_xPlus = sum(cfp_xPlus.m_flow) + "Total convective mass flow rate at port '+dx/2'"; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle(extent={{-90,30},{30,-90}}, lineColor={0,0,0}), + Line(points={{-90,30},{-30,90}}, color={0,0,0}), + Line( + points={{-30,-30},{-90,-90}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line(points={{90,-30},{30,-90}}, color={0,0,0}), + Line(points={{90,90},{30,30}}, color={0,0,0}), + Line(points={{-30,90},{90,90},{90,-30}}, color={0,0,0}), + Line( + points={{90,-30},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line( + points={{-30,90},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash)}), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the base model of all fluid-based volumes. It defines the +volume geometry, heat ports in all spatial directions, and convective fluid ports +in x-direction. The required heat ports can be adjusted via the volume setup. The +implementation of the fluid ports follows the 'connectorSizing' principle. Furthermore, +this model defines fundamental variables for the momentum, mass, and energy balance, +as well as the initialization of these balances. +<br/><br/> +Models that inherit properties from this partial model must redeclare the fluid port +and may have to add further convective fluid ports (e.g., y- or z-direction) and +diffusive fluid ports in the required spatial direction. Furthermore, conservation +equations must be added. In this context, appropriate fluid property models are +required. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Temperature <i>T</i>. + </li> + <li> + Specific volume <i>v</i> and density <i>ρ</i>. + </li> + <li> + Specific enthalpy <i>h</i>. + </li> + <br/> + <li> + Mass balance using at least the variables <i>dm_dtau</i> and <i>mc_flow</i>. + </li> + <li> + Partial derivative of the overall mass w.r.t. time <i>dm_dtau</i>. + </li> + <li> + Sum of all convective mass flow rates <i>mc_flow</i>. + </li> + <br/> + <li> + Energy balance using at least the variables <i>dU_dtau</i>, <i>Hb_flow</i>, + and <i>Qb_flow</i>. + </li> + <li> + Partial derivative of the internal energy w.r.t. time <i>dU_dtau</i>. + </li> + <li> + Sum of all enthalpy flow rates across boundaries <i>Hb_flow</i>. + </li> + <li> + Sum of all heat flow rates across boundaries <i>Qb_flow</i>. + </li> + <br/> + <li> + Variables of the summary record except for pressure <i>p</i>, temperature <i>T</i>, + specific volume <i>v</i>, and mass flow rates in x-direction + <i>mc_flow_xMinus</i>/<i>mc_flow_xPlus</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 7, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialFluidVolume; diff --git a/SorpLib/Basics/Volumes/BaseClasses/PartialPhaseSeparatorVolume.mo b/SorpLib/Basics/Volumes/BaseClasses/PartialPhaseSeparatorVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..61d94cc8c784919adf31572eadb11d695519ec9a --- /dev/null +++ b/SorpLib/Basics/Volumes/BaseClasses/PartialPhaseSeparatorVolume.mo @@ -0,0 +1,413 @@ +within SorpLib.Basics.Volumes.BaseClasses; +partial model PartialPhaseSeparatorVolume + "Base model for all phase saprator volumes" + + // + // Definition of parameters describing media + // + parameter Integer no_components = 1 + "Number of components in the medium" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding classes + // + parameter Integer nPorts_cfp_xMinus=0 + "Number of ports at cfp_xMinus" + annotation (Dialog(connectorSizing=true), + HideResult=true); + parameter Integer nPorts_cfp_xPlus=0 + "Number of ports at cfp_xPlus" + annotation (Dialog(connectorSizing=true), + HideResult=true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.Temperature T_initial = 298.15 + "Initial value of temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + parameter Modelica.Units.SI.Density rho_initial = 200 + "Initial value of density" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + + parameter Modelica.Units.SI.MassFlowRate mc_flow_initialX = 1e-4 + "Start value for convective mass flow rate in x direction" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + extends SorpLib.Basics.Volumes.BaseClasses.PartialVolume( + redeclare replaceable SorpLib.Basics.Volumes.Records.PhaseSeparatorGeometry geometry + constrainedby SorpLib.Basics.Volumes.Records.PhaseSeparatorGeometry); + + // + // Definition of parameters regarding calculation setup + // + parameter Boolean calculateAdditionalProperties = false + "= true, if additional properties required for tranport models are calculated" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of advanced parameters + // + parameter SorpLib.Choices.BalanceEquations type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial + "Handling of the overall mass balance and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult=true); + + parameter Boolean useStateLimiter = true + "= true, if specific enthalpy of vapor or liquid is limited at ports (i.e., + vapor port is slightly overheated and liquid port is slightly supercooled)" + annotation (Dialog(tab = "Advanced", group = "Limits"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Modelica.Units.SI.SpecificEnthalpy dh = 10 + "Specific enthalpy used for superheating and supercooling" + annotation (Dialog(tab = "Advanced", group = "Limits", + enable = useStateLimiter), + HideResult = true); + + // + // Definition of ports + // + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_in[nPorts_cfp_xMinus] cfp_xMinus( + each final no_components=no_components, + m_flow(each start=mc_flow_initialX)) + "Convective fluid port at position '-dx/2' (i.e., liquid port)" + annotation (Placement(transformation(extent={{-46,14},{-38,22}}), + iconTransformation(extent={{-46,14},{-38,22}}))); + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_out[nPorts_cfp_xPlus] cfp_xPlus( + each final no_components=no_components, + m_flow(each start=-mc_flow_initialX)) + "Convective fluid port at position '+dx/2' (i.e., vapor port)" + annotation (Placement(transformation(extent={{74,14},{82,22}}), + iconTransformation(extent={{74,14},{82,22}}))); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p( + stateSelect=StateSelect.avoid) + "Pressure"; + Modelica.Units.SI.Temperature T( + start=T_initial, + stateSelect=StateSelect.prefer) + "Temperature"; + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + Modelica.Units.SI.Density rho( + start=rho_initial, + stateSelect=StateSelect.prefer) + "Density"; + + Modelica.Units.SI.SpecificEnthalpy h( + stateSelect=StateSelect.avoid) + "Specific enthalpy"; + Modelica.Units.SI.SpecificInternalEnergy u + "Specific internal energy"; + + Modelica.Units.SI.Density rho_liq + "Density at saturated liquid line"; + Modelica.Units.SI.Density rho_vap + "Density at saturated vapor line"; + Modelica.Units.SI.SpecificEnthalpy h_liq + "Specific enthalpy at saturated liquid line"; + Modelica.Units.SI.SpecificEnthalpy h_vap + "Specific enthalpy at saturated vapor line"; + Real q(unit="kg/kg") + "Vapor mass fraction in phase seperator"; + + Modelica.Units.SI.Length l_liq + "Height of liquid phase"; + Real l_liq_rel(unit="1") + "Relative height of liquid phase"; + + Modelica.Units.SI.Mass m + "Mass"; + Modelica.Units.SI.Mass m_liq + "Liquid mass"; + Modelica.Units.SI.Mass m_vap + "Vapor mass"; + + Modelica.Units.SI.MassFlowRate dm_dtau + "Derivative of mass w.r.t. time"; + Modelica.Units.SI.MassFlowRate mc_flow + "Sum of all convective mass flow rates across boundaries"; + + Modelica.Units.SI.InternalEnergy U + "Internal energy"; + + Real dU_dtau(final unit="W") + "Derivative of internal energy w.r.t. time"; + Modelica.Units.SI.EnthalpyFlowRate Hb_flow + "Sum of all enthalpy flow rates across boundaries"; + Modelica.Units.SI.HeatFlowRate Qb_flow + "Sum of all heat flow rates across boundaries"; + + SorpLib.Basics.Volumes.Records.PhaseSeparatorProperties phaseSepratorProperties( + final no_components=no_components) + "Properties of phase separator volume often required for calculation of + heat transfer"; + +initial equation + if type_overallMassBalance == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + rho = rho_initial + "Fixed initial value"; + + elseif type_overallMassBalance == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + der(rho) = 0 + "Steady-state initialisation of overall mass balance"; + + end if; + + if type_energyBalance == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + T = T_initial + "Fixed initial value"; + + elseif type_energyBalance == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + der(T) = 0 + "Steady-state initial value"; + + end if; + +equation + // + // Assertations + // + assert(no_components <= 1, + "The liquid volume model can only handel pure fluids (i.e., with one component)!", + level = AssertionLevel.error); + + assert(not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + // + // Property calculation + // + v = 1 / rho + "Specific volume"; + + h = h_liq + q * (h_vap - h_liq) + "Specific enthalpy"; + u = h - p * v + "Specific internal energy"; + + // + // Additional property calculation + // + q = (1/rho - 1/rho_liq) / (1/rho_vap - 1/rho_liq) + "Vapor mass fraction"; + + l_liq = m_liq / (rho_liq * geometry.A_base) + "Liquid filling height"; + l_liq_rel = l_liq / (geometry.V / geometry.A_base) + "Relative height of liquid phase"; + + // + // Momentum balance + // + cfp_xMinus.p = fill(p, nPorts_cfp_xMinus) + "Total pressure at the port (i.e., homogenous volume)"; + cfp_xPlus.p = fill(p, nPorts_cfp_xPlus) + "Total pressure at the port (i.e., homogenous volume)"; + + // + // Mass balance + // + m = geometry.V / v + "Mass"; + m_liq = (1 - q) * m + "Liquid mass"; + m_vap = q * m + "Vapor mass"; + + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + dm_dtau = geometry.V * der(rho) + "Transient overall mass balance"; + + end if; + + // + // Energy balance + // + U = m * u + "Internal energy"; + + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + phaseSepratorProperties.cv * der(T) + + 1/rho^2 * (-p + (h_vap - h_liq) / (1/rho_vap - 1/rho_liq)) * der(rho)) + "Transient energy balance"; + + end if; + + if useStateLimiter then + cfp_xMinus.h_outflow = fill(h_liq - dh, nPorts_cfp_xMinus) + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + cfp_xPlus.h_outflow = fill(h_vap + dh, nPorts_cfp_xPlus) + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + + else + cfp_xMinus.h_outflow = fill(h_liq, nPorts_cfp_xMinus) + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + cfp_xPlus.h_outflow = fill(h_vap, nPorts_cfp_xPlus) + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + + end if; + + T_heatPorts = T + "Required for conditional component"; + + // + // Summary record + // + phaseSepratorProperties.p = p + "Pressure"; + phaseSepratorProperties.T = T + "Temperature"; + phaseSepratorProperties.v = v + "Specific volume"; + + phaseSepratorProperties.l_liq = l_liq + "Height of liquid phase"; + phaseSepratorProperties.l_liq_rel = l_liq_rel + "Relative height of liquid phase"; + + phaseSepratorProperties.Pr = if calculateAdditionalProperties then + phaseSepratorProperties.eta * phaseSepratorProperties.cp / + phaseSepratorProperties.lambda else 0 + "Prandtl number"; + + phaseSepratorProperties.mc_flow_xMinus = sum(cfp_xMinus.m_flow) + "Total convective mass flow rate at port '-dx/2'"; + phaseSepratorProperties.mc_flow_xPlus = sum(cfp_xPlus.m_flow) + "Total convective mass flow rate at port '+dx/2'"; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle(extent={{-90,30},{30,-90}}, lineColor={0,0,0}), + Line(points={{-90,30},{-30,90}}, color={0,0,0}), + Line( + points={{-30,-30},{-90,-90}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line(points={{90,-30},{30,-90}}, color={0,0,0}), + Line(points={{90,90},{30,30}}, color={0,0,0}), + Line(points={{-30,90},{90,90},{90,-30}}, color={0,0,0}), + Line( + points={{90,-30},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line( + points={{-30,90},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Polygon( + points={{-90,-90},{-30,-30},{-30,90},{-90,30},{-90,-90}}, + lineColor={28,108,200}, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid)}), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the base model of all phase separatpr volumes. It defines the +volume geometry, heat ports in all spatial directions, and convective fluid ports +in x-direction. The required heat ports can be adjusted via the volume setup. The +implementation of the fluid ports follows the 'connectorSizing' principle. Furthermore, +this model defines fundamental variables for the momentum, mass, and energy balance, +as well as the initialization of these balances. +<br/><br/> +Models that inherit properties from this partial model may have to add further +convective fluid ports (e.g., y- or z-direction) and diffusive fluid ports in the +required spatial direction. Furthermore, conservation equations must be finalized. +In this context, appropriate fluid property models are required. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Pressure <i>p</i>. + </li> + <li> + Density at saturated liquid line <i>ρ<sub>liq</sub></i>. + </li> + <li> + Density at saturated vapor line <i>ρ<sub>vap</sub></i>. + </li> + <li> + Specific enthalpy at saturated liquid line <i>h<sub>liq</sub></i>. + </li> + <li> + Specific enthalpy at saturated vapor line <i>h<sub>vap</sub></i>. + </li> + <br/> + <li> + Mass balance using at least the variables <i>dm_dtau</i> and <i>mc_flow</i>. + </li> + <li> + Sum of all convective mass flow rates <i>mc_flow</i>. + </li> + <br/> + <li> + Energy balance using at least the variables <i>dU_dtau</i>, <i>Hb_flow</i>, + and <i>Qb_flow</i>. + </li> + <li> + Sum of all enthalpy flow rates across boundaries <i>Hb_flow</i>. + </li> + <li> + Sum of all heat flow rates across boundaries <i>Qb_flow</i>. + </li> + <br/> + <li> + Variables of the summary record except for pressure <i>p</i>, temperature <i>T</i>, + specific volume <i>v</i>, height of liquid phase <i>l_liq</i>, relative heigt of + liquid phase <i>l_liq_rel</i>, Prandtl number <i>Pr</i>, and mass flow rates in + x-direction <i>mc_flow_xMinus</i>/<i>mc_flow_xPlus</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 14, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 13, 2021, by Mirko Engelpracht:<br/> + Major revisions (e.g., object-oriented approach, options) after restructuring + of the library. + </li> + <li> + November 22, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end PartialPhaseSeparatorVolume; diff --git a/SorpLib/Basics/Volumes/BaseClasses/PartialPureComponentAdsorbateVolume.mo b/SorpLib/Basics/Volumes/BaseClasses/PartialPureComponentAdsorbateVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..e23fa32e637e5f409145954f14be3ab500b223f1 --- /dev/null +++ b/SorpLib/Basics/Volumes/BaseClasses/PartialPureComponentAdsorbateVolume.mo @@ -0,0 +1,389 @@ +within SorpLib.Basics.Volumes.BaseClasses; +partial model PartialPureComponentAdsorbateVolume + "Base model for all adsorbate models for pure component adsorption" + extends SorpLib.Basics.Volumes.BaseClasses.PartialAdsorbateVolume( + final no_components=Medium.nX, + final no_adsorptivs=1, + p(final start=p_initial, + final stateSelect= if independentStateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT then + StateSelect.prefer else StateSelect.avoid), + x(final start=x_initial, + final stateSelect= if independentStateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT then + StateSelect.prefer else StateSelect.avoid), + useHeatPorts=true, + useHeatPortsX=true, + type_adsorbentMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_adsorptMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of general parameters + // + parameter Integer nSorptionPorts = 0 + "Number of sorption ports" + annotation (Dialog(connectorSizing=true), + HideResult = true); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the fluid" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + constrainedby + SorpLib.Media.WorkingPairs.BaseClasses.PartialPureWorkingPairs + "Pure working pair model" + annotation (Dialog(tab="General", group="Media"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding calculation setup + // + parameter SorpLib.Choices.IndependentVariablesPureComponentWorkingPair independentStateVariables= + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT + "Independent state variables" + annotation (Dialog(tab="General", group="Calculation Setup"), + Evaluate=true, + HideResult = true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.Pressure p_initial = 2e3 + "Initial value of pressure" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=(independentStateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT))); + parameter SorpLib.Units.Uptake x_initial = 0.3 + "Initial value of uptake" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=(independentStateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT))); + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.FluidPorts.VLEPort_in[nSorptionPorts] fp_sorption + constrainedby SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort( + each final no_components=no_components, + each m_flow(start=ms_flow_initial)) + "Sorption fluid port" + annotation (Placement(transformation(extent={{-20,40},{-12,48}}), + iconTransformation(extent={{-20,40},{-12,48}}))); + + // + // Definition of variables + // + PureWorkingPairModel workingPair( + redeclare final package Medium = Medium, + final stateVariables=independentStateVariables, + final calcCaloricProperties=true, + final calcAdsorptAdsorbateState=calcUptakeAveragedProperties or + useAdsorbatePorts or useDiffusivePorts, + final calcDerivativesIsotherm=true, + final calcDerivativesMassEnergyBalance=true, + final p_adsorpt=p, + final x_adsorpt=x, + final T_adsorpt=T, + final avoidEvents=avoid_events) + "Thermodynamic properties and partial derivatives of the pure working pair"; + +initial equation + if type_adsorptMassBalance == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + if independentStateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT then + p = p_initial + "Fixed initial value"; + + else + x = x_initial + "Fixed initial value"; + + end if; + + elseif type_adsorptMassBalance == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + if independentStateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT then + der(p) = 0 + "Steady-state initialisation of overall mass balance"; + + else + der(x) = 0 + "Steady-state initialisation of overall mass balance"; + + end if; + end if; + +equation + // + // Assertations + // + assert(no_components <= 1, + "The VLE adsorbate volume model can only handel pure fluids (i.e., with one " + + "component)!", + level = AssertionLevel.error); + + assert(no_adsorptivs <= 1, + "The VLE adsorbate volume model can only handel one adsorptive!", + level = AssertionLevel.error); + + assert(not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + (type_adsorbentMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_adsorptMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial)), + "Steady-state mass balances combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + if useAdsorbatePorts then + assert(calcUptakeAveragedProperties, + "When using adsorbate ports, uptake-averaged properties must be calculated!", + level = AssertionLevel.error); + end if; + + if useDiffusivePorts then + assert(calcUptakeAveragedProperties, + "When using diffusive ports, uptake-averaged properties must be calculated!", + level = AssertionLevel.error); + end if; + + // + // Calculation of properties + // + h = workingPair.state_averageAdsorbate.h + "Uptake-averaged specific enthalpy: h_sor + x * h_avg_adsorpt"; + u = workingPair.state_averageAdsorbate.u + "Uptake-averaged specific internal energy: u_sor + x * u_avg_adsorpt"; + + // + // Momentum balance + // + dp_xMinus[1].x = x + "Loading at the port (i.e., homogenous volume)"; + dp_xPlus[1].x = x + "Loading at the port (i.e., homogenous volume)"; + + fp_sorption.p = fill(p, nSorptionPorts) + "Total pressure at the port (i.e., homogenous volume)"; + + // + // Mass balance + // + if type_adsorptMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_adsorpt_dtau = 0 + "Steady-state adsorpt mass balance"; + + else + if useAdsorbatePorts then + if independentStateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT then + dm_adsorpt_dtau = dm_sor_dtau * x + m_sor * ( + workingPair.derivatives_isotherm.dx_dp_T * der(p) + + workingPair.derivatives_isotherm.dx_dT_p * der(T)) + "Transient adsorpt mass balance"; + + else + dm_adsorpt_dtau = dm_sor_dtau * x + m_sor * der(x) + "Transient adsorpt mass balance"; + + end if; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT then + dm_adsorpt_dtau = m_sor * ( + workingPair.derivatives_isotherm.dx_dp_T * der(p) + + workingPair.derivatives_isotherm.dx_dT_p * der(T)) + "Transient adsorpt mass balance"; + + else + dm_adsorpt_dtau = m_sor * der(x) + "Transient adsorpt mass balance"; + + end if; + + end if; + end if; + + ap_xMinus.x_outflow = {x} + "Loading leaving the port (i.e., homogenous volume)"; + ap_xPlus.x_outflow = {x} + "Loading leaving the port (i.e., homogenous volume)"; + + // + // Energy balance + // + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if useAdsorbatePorts then + if independentStateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT then + dU_dtau = dm_sor_dtau * u + m_sor * der(T) * ( + (workingPair.derivatives_massEnergy.dh_sorbent_dT_p - + p * workingPair.derivatives_massEnergy.dv_sorbent_dT_p) + + (workingPair.derivatives_massEnergy.dxh_avg_adsorpt_dT_p - + p * workingPair.derivatives_massEnergy.dxv_avg_adsorpt_dT_p)) + + m_sor * der(p) * ( + (workingPair.derivatives_massEnergy.dh_sorbent_dp_T - + p * workingPair.derivatives_massEnergy.dv_sorbent_dp_T) + + (workingPair.derivatives_massEnergy.dxh_avg_adsorpt_dp_T - + p * workingPair.derivatives_massEnergy.dxv_avg_adsorpt_dp_T) - + (workingPair.state_sorbent.v + x * + workingPair.state_lastAdsorbedMolecule.v)) + "Transient energy balance"; + + else + dU_dtau = dm_sor_dtau * u + m_sor * der(T) * ( + (workingPair.derivatives_massEnergy.dh_sorbent_dT_x - + p * workingPair.derivatives_massEnergy.dv_sorbent_dT_x - + workingPair.state_sorbent.v * workingPair.derivatives_isotherm.dp_dT_x) + + (workingPair.derivatives_massEnergy.dxh_avg_adsorpt_dT_x - + p * workingPair.derivatives_massEnergy.dxv_avg_adsorpt_dT_x - + x * workingPair.state_lastAdsorbedMolecule.v * + workingPair.derivatives_isotherm.dp_dT_x)) + + m_sor * der(x) * ( + (workingPair.derivatives_massEnergy.dh_sorbent_dx_T - + p * workingPair.derivatives_massEnergy.dv_sorbent_dx_T - + workingPair.state_sorbent.v * workingPair.derivatives_isotherm.dp_dx_T) + + (workingPair.derivatives_massEnergy.dxh_avg_adsorpt_dx_T - + p * workingPair.derivatives_massEnergy.dxv_avg_adsorpt_dx_T - + x * workingPair.state_lastAdsorbedMolecule.v * + workingPair.derivatives_isotherm.dp_dx_T)) + "Transient energy balance"; + + end if; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT then + dU_dtau = m_sor * der(T) * ( + (workingPair.derivatives_massEnergy.dh_sorbent_dT_p - + p * workingPair.derivatives_massEnergy.dv_sorbent_dT_p) + + (workingPair.derivatives_massEnergy.dxh_avg_adsorpt_dT_p - + p * workingPair.derivatives_massEnergy.dxv_avg_adsorpt_dT_p)) + + m_sor * der(p) * ( + (workingPair.derivatives_massEnergy.dh_sorbent_dp_T - + p * workingPair.derivatives_massEnergy.dv_sorbent_dp_T) + + (workingPair.derivatives_massEnergy.dxh_avg_adsorpt_dp_T - + p * workingPair.derivatives_massEnergy.dxv_avg_adsorpt_dp_T) - + (workingPair.state_sorbent.v + x * + workingPair.state_lastAdsorbedMolecule.v)) + "Transient energy balance"; + + else + dU_dtau = m_sor * der(T) * ( + (workingPair.derivatives_massEnergy.dh_sorbent_dT_x - + p * workingPair.derivatives_massEnergy.dv_sorbent_dT_x - + workingPair.state_sorbent.v * workingPair.derivatives_isotherm.dp_dT_x) + + (workingPair.derivatives_massEnergy.dxh_avg_adsorpt_dT_x - + p * workingPair.derivatives_massEnergy.dxv_avg_adsorpt_dT_x - + x * workingPair.state_lastAdsorbedMolecule.v * + workingPair.derivatives_isotherm.dp_dT_x)) + + m_sor * der(x) * ( + (workingPair.derivatives_massEnergy.dh_sorbent_dx_T - + p * workingPair.derivatives_massEnergy.dv_sorbent_dx_T - + workingPair.state_sorbent.v * workingPair.derivatives_isotherm.dp_dx_T) + + (workingPair.derivatives_massEnergy.dxh_avg_adsorpt_dx_T - + p * workingPair.derivatives_massEnergy.dxv_avg_adsorpt_dx_T - + x * workingPair.state_lastAdsorbedMolecule.v * + workingPair.derivatives_isotherm.dp_dx_T)) + "Transient energy balance"; + + end if; + + end if; + end if; + + dp_xMinus[1].h_outflow = workingPair.state_averageAdsorpt.h + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + dp_xPlus[1].h_outflow = workingPair.state_averageAdsorpt.h + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + + fp_sorption.h_outflow = fill(workingPair.state_adsorptive.h, nSorptionPorts) + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + + // + // Summary record + // + adsorbateProperties.x_i[1] = x + "Loading of each component"; + + adsorbateProperties.cp = workingPair.cp_adsorpt + "Specific heat capacity"; + adsorbateProperties.dh_ads = workingPair.h_ads + "Specific enthalpy of adsorption"; + + adsorbateProperties.m_flow_sorption = ms_flow + "Total mass flow rate at port 'sorption'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model of all adsorbate volumes for pure component +adsorption. It defines the volume geometry, heat ports in all spatial directions, +as well as adsorbate and diffusive (i.e., adsorpt) ports in x-direction. The required +heat ports can be adjusted via the volume setup. Furthermore, this model defines +fundamental variables for the momentum, mass, and energy balance, as well as the +initialization of these balances. +<br/><br/> +Models that inherit properties from this partial model must redeclare the fluid port +and may have to add further adsorbate and diffusive (i.e., adsorpt) ports in the +required spatial direction (e.g., y- or z-direction). Furthermore, the working pair +model must be redeclared. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Sum of all adsorbent mass flow rates across adsorbate boundaries <i>masor_flow</i>. + </li> + <li> + Sum of all adsorpt mass flow rates across adsorbate boundaries <i>mas_flow</i>. + </li> + <li> + Sum of all sorption mass flow rates across sorption boundaries <i>ms_flow</i>. + </li> + <br/> + <li> + Sum of all enthalpy flow rates across boundaries <i>Hb_flow</i>. + </li> + <br/> + <li> + Variables of the summary record: Adsorbate mass flow rates in y-direction + <i>ma_flow_yMinus</i>/<i>ma_flow_yPlus</i> and in z-direction + <i>ma_flow_zMinus</i>/<i>ma_flow_zPlus</i>, as well as diffusive mass flow + rates in y-direction <i>md_flow_yMinus</i>/<i>md_flow_yPlus</i> and in + z-direction <i>md_flow_zMinus</i>/<i>md_flow_zPlus</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureComponentAdsorbateVolume; diff --git a/SorpLib/Basics/Volumes/BaseClasses/PartialVolume.mo b/SorpLib/Basics/Volumes/BaseClasses/PartialVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..3a76a8d6422e8cd9a05cb874a17c4b35e2c538c9 --- /dev/null +++ b/SorpLib/Basics/Volumes/BaseClasses/PartialVolume.mo @@ -0,0 +1,323 @@ +within SorpLib.Basics.Volumes.BaseClasses; +partial model PartialVolume + "Base model for all volumes" + + // + // Definition of parameters regarding volume setup + // + parameter Boolean useHeatPorts = false + " = true, if heat ports are required" + annotation (Dialog(tab="Volume Setup", group="Heat Ports"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useHeatPortsX = false + " = true, if heat ports are required in the x direction" + annotation (Dialog(tab="Volume Setup", group="Heat Ports", + enable=useHeatPorts), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useHeatPortsY = false + " = true, if heat ports are required in the y direction" + annotation (Dialog(tab="Volume Setup", group="Heat Ports", + enable=useHeatPorts), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useHeatPortsZ = false + " = true, if heat ports are required in the z direction" + annotation (Dialog(tab="Volume Setup", group="Heat Ports", + enable=useHeatPorts), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding geometry + // + replaceable parameter SorpLib.Basics.Volumes.Records.VolumeGeometry geometry + constrainedby SorpLib.Basics.Volumes.Records.VolumeGeometry + "Volume geometry" + annotation (Dialog(tab = "General", group = "Geometry"), + choicesAllMatching=true); + + // + // Definition of advanced parameters + // + parameter SorpLib.Choices.BalanceEquations type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial + "Handling of the energy balance and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult = true); + + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of ports + // + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_xMinus( + final T=T_xMinus, + final Q_flow=Q_flow_xMinus) if + useHeatPorts and useHeatPortsX + "Heat port at position '-dx/2'" + annotation (Placement(transformation(extent={{-66,-6},{-54,6}}), + iconTransformation(extent={{-66,-6},{-54,6}}))); + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_out hp_xPlus( + final T=T_xPlus, + final Q_flow=Q_flow_xPlus) if + useHeatPorts and useHeatPortsX + "Heat port at position '+dx/2'" + annotation (Placement(transformation(extent={{54,-6},{66,6}}), + iconTransformation(extent={{54,-6},{66,6}}))); + + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_yMinus( + final T=T_yMinus, + final Q_flow=Q_flow_yMinus) if + useHeatPorts and useHeatPortsY "Heat port at position '-dy/2'" + annotation (Placement(transformation(extent={{-6,-66},{6,-54}}), + iconTransformation(extent={{-6,-66},{6,-54}}))); + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_out hp_yPlus( + final T=T_yPlus, + final Q_flow=Q_flow_yPlus) if + useHeatPorts and useHeatPortsY + "Heat port at position '+dy/2'" + annotation (Placement(transformation(extent={{-6,54},{6,66}}), + iconTransformation(extent={{-6,54},{6,66}}))); + + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_zMinus( + final T=T_zMinus, + final Q_flow=Q_flow_zMinus) if + useHeatPorts and useHeatPortsZ + "Heat port at position '-dz/2'" + annotation (Placement(transformation(extent={{24,24},{36,36}}), + iconTransformation(extent={{24,24},{36,36}}))); + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_out hp_zPlus( + final T=T_zPlus, + final Q_flow=Q_flow_zPlus) if + useHeatPorts and useHeatPortsZ + "Heat port at position '+dz/2'" + annotation (Placement(transformation(extent={{-36,-36},{-24,-24}}), + iconTransformation(extent={{-36,-36},{-24,-24}}))); + + // + // Definition of protected variables + // +protected + Modelica.Units.SI.Temperature T_heatPorts + "Required for conditional connectors"; + + Modelica.Units.SI.Temperature T_xMinus + "Required for conditional connector"; + Modelica.Units.SI.Temperature T_xPlus + "Required for conditional connector"; + + Modelica.Units.SI.Temperature T_yMinus + "Required for conditional connector"; + Modelica.Units.SI.Temperature T_yPlus + "Required for conditional connector"; + + Modelica.Units.SI.Temperature T_zMinus + "Required for conditional connector"; + Modelica.Units.SI.Temperature T_zPlus + "Required for conditional connector"; + + Modelica.Units.SI.HeatFlowRate Q_flow_xMinus + "Required for conditional connector"; + Modelica.Units.SI.HeatFlowRate Q_flow_xPlus + "Required for conditional connector"; + + Modelica.Units.SI.HeatFlowRate Q_flow_yMinus + "Required for conditional connector"; + Modelica.Units.SI.HeatFlowRate Q_flow_yPlus + "Required for conditional connector"; + + Modelica.Units.SI.HeatFlowRate Q_flow_zMinus + "Required for conditional connector"; + Modelica.Units.SI.HeatFlowRate Q_flow_zPlus + "Required for conditional connector"; + +equation + // + // Assertations + // + if not useHeatPorts then + assert(not (useHeatPortsX or useHeatPortsY or useHeatPortsZ), + "Deactivate individual heat ports if heat ports are not considered!", + level = AssertionLevel.error); + end if; + + // + // Variables of heat ports + // + T_xMinus = T_heatPorts + "Required for conditional connector"; + T_xPlus = T_heatPorts + "Required for conditional connector"; + + T_yMinus = T_heatPorts + "Required for conditional connector"; + T_yPlus = T_heatPorts + "Required for conditional connector"; + + T_zMinus = T_heatPorts + "Required for conditional connector"; + T_zPlus = T_heatPorts + "Required for conditional connector"; + + if not useHeatPortsX then + Q_flow_xMinus = 0 + "Required for conditional connector"; + Q_flow_xPlus = 0 + "Required for conditional connector"; + end if; + + if not useHeatPortsY then + Q_flow_yMinus = 0 + "Required for conditional connector"; + Q_flow_yPlus = 0 + "Required for conditional connector"; + end if; + + if not useHeatPortsZ then + Q_flow_zMinus = 0 + "Required for conditional connector"; + Q_flow_zPlus = 0 + "Required for conditional connector"; + end if; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle(extent={{-90,30},{30,-90}}, lineColor={0,0,0}), + Line(points={{-90,30},{-30,90}}, color={0,0,0}), + Line( + points={{-30,-30},{-90,-90}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line(points={{90,-30},{30,-90}}, color={0,0,0}), + Line(points={{90,90},{30,30}}, color={0,0,0}), + Line(points={{-30,90},{90,90},{90,-30}}, color={0,0,0}), + Line( + points={{90,-30},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line( + points={{-30,90},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line( + points={{-60,-60},{60,-60},{60,60},{-60,60},{-60,-60}}, + color={0,0,0}, + pattern=LinePattern.Dot), + Line( + points={{30,-30},{-30,-90},{-30,30},{30,90},{30,30}}, + color={0,0,0}, + pattern=LinePattern.Dot), + Line( + points={{-30,30},{-90,-30},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dot), + Line( + points={{30,-30},{90,30},{30,30}}, + color={0,0,0}, + pattern=LinePattern.Dot)}), Diagram( + coordinateSystem(preserveAspectRatio=false), graphics={ + Line( + points={{80,-90},{100,-90}}, + color={0,0,0}, + arrow={Arrow.None,Arrow.Filled}), + Line( + points={{80,-90},{80,-70}}, + color={0,0,0}, + arrow={Arrow.None,Arrow.Filled}), + Line( + points={{80,-90},{70,-100}}, + color={0,0,0}, + arrow={Arrow.None,Arrow.Filled}), + Text( + extent={{96,-98},{100,-94}}, + lineColor={0,0,0}, + fontSize=24, + textString="x", + textStyle={TextStyle.Bold}), + Text( + extent={{84,-74},{88,-70}}, + lineColor={0,0,0}, + fontSize=24, + textStyle={TextStyle.Bold}, + textString="y"), + Text( + extent={{76,-100},{80,-96}}, + lineColor={0,0,0}, + fontSize=24, + textStyle={TextStyle.Bold}, + textString="z"), + Rectangle(extent={{-90,30},{30,-90}}, lineColor={0,0,0}), + Line(points={{-90,30},{-30,90}}, color={0,0,0}), + Line( + points={{-30,-30},{-90,-90}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line(points={{90,-30},{30,-90}}, color={0,0,0}), + Line(points={{90,90},{30,30}}, color={0,0,0}), + Line(points={{-30,90},{90,90},{90,-30}}, color={0,0,0}), + Line( + points={{90,-30},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line( + points={{-30,90},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line( + points={{-60,-60},{60,-60},{60,60},{-60,60},{-60,-60}}, + color={0,0,0}, + pattern=LinePattern.Dot), + Line( + points={{30,-30},{-30,-90},{-30,30},{30,90},{30,30}}, + color={0,0,0}, + pattern=LinePattern.Dot), + Line( + points={{-30,30},{-90,-30},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dot), + Line( + points={{30,-30},{90,30},{30,30}}, + color={0,0,0}, + pattern=LinePattern.Dot)}), + Documentation(info="<html> +<p> +This partial model is the base model of all finite volumes. It defines the volume +geometry and heat ports in all spatial directions. The required heat ports can be +adjusted via the volume setup. +<br/><br/> +Models that inherit properties from this partial model may have to add fluid ports +and corresponding parameters to specify the fluid port setup. Furthermore, conservation +equations and corresponding variables must be added. In this context, fluid property +models may be required. Finally, records summarizing thermodynamic volume properties +should be added. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + The variable <i>T_heatPorts</i> that defines the temperature at the heat ports. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 6, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialVolume; diff --git a/SorpLib/Basics/Volumes/BaseClasses/package.mo b/SorpLib/Basics/Volumes/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c9c6bc2f9d42ba272b5e1543cfbbfe7548179863 --- /dev/null +++ b/SorpLib/Basics/Volumes/BaseClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Basics.Volumes; +package BaseClasses "Base classes used to create new finite volume models" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial basic functions and models. These partial functions +and models contain fundamental definitions of all volume models. The content of +this package is only of interest when adding new volume models to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Basics/Volumes/BaseClasses/package.order b/SorpLib/Basics/Volumes/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..ea6049e748b6851373386886ce829a487a09c62a --- /dev/null +++ b/SorpLib/Basics/Volumes/BaseClasses/package.order @@ -0,0 +1,5 @@ +PartialVolume +PartialAdsorbateVolume +PartialPureComponentAdsorbateVolume +PartialFluidVolume +PartialPhaseSeparatorVolume diff --git a/SorpLib/Basics/Volumes/FluidVolumes/GasMixtureVolume.mo b/SorpLib/Basics/Volumes/FluidVolumes/GasMixtureVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..6d1350c3f15f8ecfa745fe68154a32202a2bdfd2 --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/GasMixtureVolume.mo @@ -0,0 +1,755 @@ +within SorpLib.Basics.Volumes.FluidVolumes; +model GasMixtureVolume "Homogenous volume of an ideal gas mixture" + extends SorpLib.Basics.Volumes.BaseClasses.PartialFluidVolume( + final no_components = Medium.nX, + final pressureNoStateVariable = Medium.singleState, + final neglectTermVp = false, + redeclare final connector FluidPortsIn = + SorpLib.Basics.Interfaces.FluidPorts.GasPort_in, + redeclare final connector FluidPortsOut = + SorpLib.Basics.Interfaces.FluidPorts.GasPort_out, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + useHeatPorts=true, + useHeatPortsY=true, + h_initial=Medium.specificEnthalpy_pTX(p=p_initial, T=T_initial, X=X_i_initial), + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture + "Medium model of the ideal gas mixture" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + parameter Integer no_adsorptivs(min=1, max=no_components) = 1 + "Number of adsorptivs (i.e., components that can be adsorbed/desorbed)" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true); + parameter Integer[no_adsorptivs] ind_adsorptivs= + fill(Medium.nX, no_adsorptivs) + "Indexes of adsorptivs in the ideal gas mixture" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true); + final parameter Integer[no_components] mapped_ind_adsorptivs= + SorpLib.Basics.Volumes.Utilities.mapSorptionFluidPorts( + no_components=no_components, + ind_adsorptivs=ind_adsorptivs) + "Indices of sorption fluid ports mapped to component indices: I.e., value of + zero if component cannot be adsorbed/desorbed; otherwise, value of sorption + fluid port" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding the calculation setup + // + parameter Boolean idealGasMixture = true + " = true, if medium is an ideal gas mixture and govering equations are + explicitly written for an ideal gas mixture" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.MassFraction[no_components] X_i_initial= + Medium.reference_X + "Initial values of mass fractions" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + + parameter Modelica.Units.SI.MassFlowRate md_flow_initialX = 1e-4 + "Start value for diffusive mass flow rates in x direction" + annotation (Dialog(tab="Initialisation", group="Start Values")); + parameter Modelica.Units.SI.MassFlowRate ms_flow_initial = 1e-4 + "Start value for sorption mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter SorpLib.Choices.BalanceEquations type_independentMassBalances= + type_overallMassBalance + "Handling of independent mass balances and corresponding initialisations" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult=true); + + // + // Definition of ports + // + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_sorption + "Sorption heat port" + annotation (Placement(transformation(extent={{10,-50},{22,-38}}), + iconTransformation(extent={{10,-50},{22,-38}}))); + + FluidPortsIn[no_components] dfp_xMinus( + each final no_components=1, + m_flow(each start=-md_flow_initialX)) + "Diffusive fluid port at position '-dx/2'" + annotation (Placement(transformation(extent={{-82,-22},{-74,-14}}), + iconTransformation(extent={{-82,-22},{-74,-14}}))); + FluidPortsOut[no_components] dfp_xPlus( + each final no_components=1, + m_flow(each start=md_flow_initialX)) + "Diffusive fluid port at position '+dx/2'" + annotation (Placement(transformation(extent={{38,-22},{46,-14}}), + iconTransformation(extent={{38,-22},{46,-14}}))); + + FluidPortsIn[no_adsorptivs] fp_sorption( + each final no_components=1, + m_flow(each start=ms_flow_initial)) + "Sorption fluid port" + annotation (Placement(transformation(extent={{-20,-80},{-12,-72}}), + iconTransformation(extent={{-20,-80},{-12,-72}}))); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure[no_components] p_i + "Partial pressures"; + Modelica.Units.SI.MassFraction[no_components] X_i( + start=X_i_initial, + each stateSelect=StateSelect.prefer) + "Mass fractions"; + + Modelica.Units.SI.SpecificEnthalpy[no_components] h_i + "Specific enthalpy of individual components"; + + Modelica.Units.SI.Mass[no_components] m_i + "Mass of individual components"; + + Modelica.Units.SI.MassFlowRate[no_components] dm_i_dtau + "Derivative of individual components' masses w.r.t. time"; + + Modelica.Units.SI.MassFlowRate[no_components] mc_i_flow + "Sum of all individual components' convective mass flow rates across + boundaries"; + Modelica.Units.SI.MassFlowRate md_flow + "Sum of all diffusive mass flow rates across boundaries"; + Modelica.Units.SI.MassFlowRate[no_components] md_i_flow + "Sum of all individual components' diffusive mass flow rates across + boundaries"; + Modelica.Units.SI.MassFlowRate ms_flow + "Sum of all sorption mass flow rates across boundaries"; + Modelica.Units.SI.MassFlowRate[no_components] ms_i_flow + "Sum of all individual components' sorption mass flow rates across + boundaries"; + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + +initial equation + if type_independentMassBalances == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + X_i = X_i_initial + "Fixed initial values"; + + elseif type_independentMassBalances == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + der(X_i) = zeros(no_components) + "Steady-state initialisation of independent mass balances"; + + end if; + +equation + // + // Assertations + // + assert(pressureNoStateVariable or not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + // + // Calculation of properties + // + if independentStateVariables == + SorpLib.Choices.IndependentVariablesVolume.pTX then + state = Medium.setState_pTX(p=p, T=T, X=X_i) + "Thermodynamic state required to calculate medium properties"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + else + state = Medium.setState_phX(p=p, h=h, X=X_i) + "Thermodynamic state required to calculate medium properties"; + T = Medium.temperature(state=state) + "Temperature"; + + end if; + + p_i = Medium.partialPressures(state=state) + "Partial pressures"; + v = 1 / rho + "Specific volume"; + rho = Medium.density(state=state) + "Density"; + + for ind in 1:no_components loop + h_i[ind] = Medium.specificEnthalpy_i_T(ind_component=ind, T=T) + "Specific enthalpy of individual components"; + end for; + + // + // Momentum balance + // + dfp_xMinus.p = p_i + "Partial pressures at the port (i.e., homogenous volume)"; + dfp_xPlus.p = p_i + "Partial pressures at the port (i.e., homogenous volume)"; + + for ind in 1:no_adsorptivs loop + fp_sorption[ind].p = p_i[ind_adsorptivs[ind]] + "Partial pressures at the port (i.e., homogenous volume)"; + end for; + + // + // Mass balance + // + m_i = m .* X_i + "Mass of individual components"; + + dm_dtau = mc_flow + md_flow + ms_flow + "Overall mass balance"; + dm_i_dtau = mc_i_flow + md_i_flow + ms_i_flow + "Individual components' mass balances"; + + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dm_dtau = geometry.V * (Medium.density_derX(state=state) * der(X_i) + + rho * (fluidProperties.kappa *der(p) - fluidProperties.beta * der(T))) + "Transient overall mass balance"; + + else + if idealGasMixture then + dm_dtau = geometry.V * (rho * (fluidProperties.kappa * der(p) - + fluidProperties.beta / fluidProperties.cp * der(h)) + + (Medium.density_derX(state=state) .+ rho .* fluidProperties.beta .* + h_i ./ fluidProperties.cp) * der(X_i)) + "Transient overall mass balance"; + + else + dm_dtau = geometry.V * (rho * ((fluidProperties.kappa - + fluidProperties.beta * fluidProperties.my) * der(p) - + fluidProperties.beta / fluidProperties.cp * der(h)) + + (Medium.density_derX(state=state) .+ rho .* fluidProperties.beta .* + h_i ./ fluidProperties.cp) * der(X_i)) + "Transient overall mass balance"; + + end if; + end if; + end if; + + if type_independentMassBalances== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_i_dtau = zeros(no_components) + "Steady-state independent mass balances"; + + else + dm_i_dtau = X_i .* dm_dtau .+ m .* der(X_i) + "Transient independent mass balances"; + + end if; + + mc_flow = sum(cfp_xMinus.m_flow) + sum(cfp_xPlus.m_flow) + "Sum of all convective mass flow rates across boundaries"; + md_flow = sum(dfp_xMinus.m_flow) + sum(dfp_xPlus.m_flow) + "Sum of all diffusive mass flow rates across boundaries"; + ms_flow = sum(fp_sorption.m_flow) + "Sum of all sorption mass flow rates across boundaries"; + + if avoid_events then + for ind_comp in 1:no_components loop + if ind_comp <> no_components then + mc_i_flow[ind_comp] = + sum(cfp_xMinus[ind_port].m_flow * + noEvent(actualStream(cfp_xMinus[ind_port].Xi_outflow[ind_comp])) + for ind_port in 1:nPorts_cfp_xMinus) + + sum(cfp_xPlus[ind_port].m_flow * + noEvent(actualStream(cfp_xPlus[ind_port].Xi_outflow[ind_comp])) + for ind_port in 1:nPorts_cfp_xPlus) + "Sum of all convective mass flow rates of component ind_comp across + boundaries"; + + else + mc_i_flow[ind_comp] = mc_flow - sum(mc_i_flow[1:no_components-1]) + "Sum of all convective mass flow rates of last component across + boundaries"; + + end if; + end for; + + else + for ind_comp in 1:no_components loop + if ind_comp <> no_components then + mc_i_flow[ind_comp] = + sum(cfp_xMinus[ind_port].m_flow * + actualStream(cfp_xMinus[ind_port].Xi_outflow[ind_comp]) + for ind_port in 1:nPorts_cfp_xMinus) + + sum(cfp_xPlus[ind_port].m_flow * + actualStream(cfp_xPlus[ind_port].Xi_outflow[ind_comp]) + for ind_port in 1:nPorts_cfp_xPlus) + "Sum of all convective mass flow rates of component ind_comp across + boundaries"; + + else + mc_i_flow[ind_comp] = mc_flow - sum(mc_i_flow[1:no_components-1]) + "Sum of all convective mass flow rates of last component across + boundaries"; + + end if; + end for; + end if; + + md_i_flow = dfp_xMinus.m_flow .+ dfp_xPlus.m_flow + "Sum of all individual components' diffusive mass flow rates across + boundaries"; + + for ind in 1:no_components loop + ms_i_flow[ind] = if mapped_ind_adsorptivs[ind] == 0 then 0 else + fp_sorption[mapped_ind_adsorptivs[ind]].m_flow + "Sum of all individual components' sorption mass flow rates across + boundaries"; + end for; + + for ind in 1:nPorts_cfp_xMinus loop + cfp_xMinus[ind].Xi_outflow = X_i[1:no_components-1] + "Independent mass fractions leaving the port (i.e., homogenous volume)"; + end for; + for ind in 1:nPorts_cfp_xPlus loop + cfp_xPlus[ind].Xi_outflow = X_i[1:no_components-1] + "Independent mass fractions leaving the port (i.e., homogenous volume)"; + end for; + + // + // Energy balance + // + dU_dtau = Hb_flow + Qb_flow + "Energy balane"; + + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + if idealGasMixture then + dU_dtau = u * dm_dtau + m * ( + (fluidProperties.cp - p * v * fluidProperties.beta) * der(T) + + (h_i .+ p .* v.^2 .* Medium.density_derX(state=state)) * der(X_i)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + v * (p * fluidProperties.kappa - T * fluidProperties.beta) * der(p) + + (fluidProperties.cp - p * v * fluidProperties.beta) * der(T) + + (h_i .+ p .* v.^2 .* Medium.density_derX(state=state)) * der(X_i)) + "Transient energy balance"; + + end if; + + else + if idealGasMixture then + dU_dtau = u * dm_dtau + m * ( + (1 - p * v * fluidProperties.beta / fluidProperties.cp) * der(h) + + p .* v.^2 .* (Medium.density_derX(state=state) .+ rho .* + fluidProperties.beta .* h_i ./ fluidProperties.cp) * der(X_i)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + (1 - p * v * fluidProperties.beta / fluidProperties.cp) * der(h) + + v * (p * (fluidProperties.kappa - fluidProperties.beta * + fluidProperties.my) - 1) * der(p) + + p .* v.^2 .* (Medium.density_derX(state=state) .+ rho .* + fluidProperties.beta .* h_i ./ fluidProperties.cp) * der(X_i)) + "Transient energy balance"; + + end if; + end if; + end if; + + if avoid_events then + Hb_flow = + sum(cfp_xMinus.m_flow .* noEvent(actualStream(cfp_xMinus.h_outflow))) + + sum(cfp_xPlus.m_flow .* noEvent(actualStream(cfp_xPlus.h_outflow))) + + sum(dfp_xMinus.m_flow .* noEvent(actualStream(dfp_xMinus.h_outflow))) + + sum(dfp_xPlus.m_flow .* noEvent(actualStream(dfp_xPlus.h_outflow))) + + sum(fp_sorption.m_flow .* noEvent(actualStream(fp_sorption.h_outflow))) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + sum(cfp_xMinus.m_flow .* actualStream(cfp_xMinus.h_outflow)) + + sum(cfp_xPlus.m_flow .* actualStream(cfp_xPlus.h_outflow)) + + sum(dfp_xMinus.m_flow .* actualStream(dfp_xMinus.h_outflow)) + + sum(dfp_xPlus.m_flow .* actualStream(dfp_xPlus.h_outflow)) + + sum(fp_sorption.m_flow .* actualStream(fp_sorption.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + + Qb_flow = Q_flow_xMinus + Q_flow_xPlus + + Q_flow_yMinus + Q_flow_yPlus + + Q_flow_zMinus + Q_flow_zPlus + + hp_sorption.Q_flow + "Sum of all heat flow rates across boundaries"; + + dfp_xMinus.h_outflow = h_i + "Specific enthalpies leaving the port (i.e., homogenous volume)"; + dfp_xPlus.h_outflow = h_i + "Specific enthalpies leaving the port (i.e., homogenous volume)"; + + for ind in 1:no_adsorptivs loop + fp_sorption[ind].h_outflow = h_i[ind_adsorptivs[ind]] + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + end for; + + hp_sorption.T = T + "Temperature at sorption heat port"; + + // + // Summary record + // + fluidProperties.cp = if (calculateAdditionalProperties or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + fluidProperties.lambda = if calculateAdditionalProperties then + Medium.thermalConductivity(state=state) else 0 + "Thermal conductivity"; + fluidProperties.eta = if calculateAdditionalProperties then + Medium.dynamicViscosity(state=state) else 0 + "Dynamic viscosity"; + + fluidProperties.beta = if (calculateAdditionalProperties or + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + fluidProperties.kappa = if (calculateAdditionalProperties or + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + fluidProperties.my = if (calculateAdditionalProperties or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)))) then + v / fluidProperties.cp * (fluidProperties.beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + fluidProperties.Pr = if calculateAdditionalProperties then + fluidProperties.eta * fluidProperties.cp / fluidProperties.lambda else 0 + "Prandtl number"; + + fluidProperties.m_flow_sorption = ms_flow + "Total mass flow rate at port 'sorption'"; + + fluidProperties.mc_flow_yMinus = 0 + "Convective mass flow rate at port '-dy/2'"; + fluidProperties.mc_flow_yPlus = 0 + "Convective mass flow rate at port '+dy/2'"; + fluidProperties.mc_flow_zMinus = 0 + "Convective mass flow rate at port '-dz/2'"; + fluidProperties.mc_flow_zPlus = 0 + "Convective mass flow rate at port '+dz/2'"; + + fluidProperties.md_flow_xMinus = dfp_xMinus.m_flow + "Diffusive mass flow rate at port '-dx/2'"; + fluidProperties.md_flow_xPlus = dfp_xPlus.m_flow + "Diffusive mass flow rate at port '+dx/2'"; + fluidProperties.md_flow_yMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dy/2'"; + fluidProperties.md_flow_yPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dy/2'"; + fluidProperties.md_flow_zMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dz/2'"; + fluidProperties.md_flow_zPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a gas-mixture volume, applying a lumped modeling approach. +Depending on the volume setup, this model may have up to seven heat ports (i.e., two +for each spatial direction of a cartesian coordinate system and one for an adsorbate +volume). Furthermore, this model has convective fluid ports in y-direction, following +the 'connectorSizing' principle, diffusive fluid ports in y-direction, and a sorption +fluid port. These ports allow for the combination of several fluid volumes to create a +spatially distributed model. +</p> + +<h4>Main equations</h4> +<p> +The most important equations are the momentum, mass, and energy balance. According to +the staggered grid approach, the momentum balance is not solved within the volume but +at the volume's boundaries via so-called +<a href=\"Modelica://SorpLib.Components.Fittings\">flow models</a>. Hennce, no pressure +losses occur within the volume: +</p> +<pre> + p = cfp_xMinus.p; +</pre> +<pre> + p = cfp_xPlus.p; +</pre> +<p> +The pressure at the diffusive fluid ports and sorption fluid ports correspnds to the +correct partial pressure: +</p> +<pre> + p_i[i] = dfp_xMinus[i].p; +</pre> +<pre> + p_i[i] = dfp_xPlus[i].p; +</pre> +<pre> + p_i[i] = fp_sorption[i].p; +</pre> + +<br/> +<p> +Regarding the mass and energy balances, either steady-state or tansient balnaces can be +selected. When using the pressure <i>p</i>, temperature <i>T</i>, and mass fractions +<i>X<sub>i</sub></i> as independent states, the overall mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = V * [ρ * (κ * (dp/dτ) - β * (dT/dτ)) + ∑ (∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) * (dX<sub>i</sub>/dτ)] = ∑ m<sub>c,flow</sub> + ∑ m<sub>d,flow</sub>+ ∑ m<sub>s,flow</sub>; +</pre> +<p> +the component-specific mass balances are defined as +</p> +<pre> + (dm<sub>i</sub>/dτ) = X<sub>i</sub> * (dm/dτ) + m * (dX<sub>i</sub>/dτ) = ∑ m<sub>c,i,flow</sub> + ∑ m<sub>d,i,flow</sub>+ ∑ m<sub>s,i,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [v * (p * κ - T * β) * (dp/dτ) + (c<sub>p</sub> - p * v * β) * (dT/dτ) + ∑ ((∂h/∂X<sub>i</sub>|<sub>p,T</sub>) + p * v<sup>2</sup> * (∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>)) * (dX<sub>i</sub>/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<br/> +<p> +When using the pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions +<i>X<sub>i</sub></i> as independent states, the overall mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = V * [ρ * ((κ - β * μ) * (dp/dτ) - β / c<sub>p</sub> * (dh/dτ)) + ∑ ((∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) + ρ * β * (∂h/∂X<sub>i</sub>|<sub>p,T</sub>) / c<sub>p</sub>) * (dX<sub>i</sub>/dτ)] = ∑ m<sub>c,flow</sub> + ∑ m<sub>d,flow</sub>+ ∑ m<sub>s,flow</sub>; +</pre> +<p> +the component-specific mass balances are defined as +</p> +<pre> + (dm<sub>i</sub>/dτ) = X<sub>i</sub> * (dm/dτ) + m * (dX<sub>i</sub>/dτ) = ∑ m<sub>c,i,flow</sub> + ∑ m<sub>d,i,flow</sub>+ ∑ m<sub>s,i,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [v * (p * (κ - β * μ) - 1) * (dp/dτ) + (1 - p * v * β / c<sub>p</sub>) * (dh/dτ) + ∑ p * v<sup>2</sup> * ((∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) + ρ * β * (∂h/∂X<sub>i</sub>|<sub>p,T</sub>) / c<sub>p</sub>) * (dX<sub>i</sub>/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<br/> +<p> +Herein, <i>(dm/dτ)</i> is the derivative of the mass w.r.t. time, <i>(dU/dτ)</i> +is the derivative of the internal energy w.r.t. time, <i>(dρ/dτ)</i> is the +derivative of the density w.r.t. time, <i>(du/dτ)</i> is the derivative of the specific +internal energy w.r.t.time, <i>(dp/dτ)</i> is the derivative of the pressure w.r.t. +time, <i>(dT/dτ)</i> is the derivative of the temperature w.r.t. time, <i>(dh/dτ)</i> +is the derivative of the specific enthalpy w.r.t. time, <i>(dX<sub>i</sub>/dτ)</i> are the +derivatives of the mass fractions w.r.t. time, <i>(∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>)</i> is +the partial derivative of the density w.r.t. mass fractions at constant pressure and temperatre, +<i>(∂h/∂X<sub>i</sub>|<sub>p,T</sub>)</i> is the partial derivative of the specific enthaly w.r.t. +mass fractions at constant pressure and temperature, <i>V</i> is the volume, <i>m</i> is the mass, +<i>v</i> is the specific volume, <i>ρ</i> is the density, <i>κ</i> is the isothermal +compressibility, <i>β</i> is the isobaric expansion coefficient, <i>μ</i> is the Joule-Thomson +coefficient, <i>c<sub>p</sub></i> is the specific heat capacity at constant pressure, +<i>m<sub>c,flow</sub></i> is the sum of the convective mass flow rates, <i>m<sub>d,flow</sub></i> is +the sum of the diffusive mass flow rates, <i>m<sub>s,flow</sub></i> is the sum of the sorption mass +flow rates, <i>H<sub>b,flow</sub></i> is the sum of the enthalpy flow rates, and <i>Q<sub>b,flow</sub></i> +is the sum of the heat flow rates. Mass flow rates with index <i>i</i> describe component-specific +mass flow rates. +</p> + +<h4>Main equations for an ideal gas mixture</h4> +<p> +For an ideal gas mixture, the isothermal compressibility <i>κ</i> is <i>1/p</i> and the +isbaric expansion coefficient <i>β</i> is <i>1/T</i>, leading to a Joule-Thomson coefficient +<i>μ</i> of zero. Hence, the overall mass and energy balances can be simplified. When using the +pressure <i>p</i>, temperature <i>T</i>, and mass fractions <i>X<sub>i</sub></i> as independent +states, the overall mass balance still reads as +</p> +<pre> + (dm/dτ) = V * [ρ * (κ * (dp/dτ) - β * (dT/dτ)) + ∑ (∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) * (dX<sub>i</sub>/dτ)] = ∑ m<sub>c,flow</sub> + ∑ m<sub>d,flow</sub>+ ∑ m<sub>s,flow</sub>; +</pre> +<p> +but the energy balance now reads as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * [(c<sub>p</sub> - p * v * β) * (dT/dτ) + ∑ ((∂h/∂X<sub>i</sub>|<sub>p,T</sub>) + p * v<sup>2</sup> * (∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>)) * (dX<sub>i</sub>/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<br/> +<p> +When using the pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions +<i>X<sub>i</sub></i> as independent states, the overall mass balance now reads as +</p> +<pre> + (dm/dτ) = V * [ρ * (κ * (dp/dτ) - β / c<sub>p</sub> * (dh/dτ)) + ∑ ((∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) + ρ * β * (∂h/∂X<sub>i</sub>|<sub>p,T</sub>) / c<sub>p</sub>) * (dX<sub>i</sub>/dτ)] = ∑ m<sub>c,flow</sub> + ∑ m<sub>d,flow</sub>+ ∑ m<sub>s,flow</sub>; +</pre> +<p> +and the energy balance now reads as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * [(1 - p * v * β / c<sub>p</sub>) * (dh/dτ) + ∑ p * v<sup>2</sup> * ((∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) + ρ * β * (∂h/∂X<sub>i</sub>|<sub>p,T</sub>) / c<sub>p</sub>) * (dX<sub>i</sub>/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> + <li> + Ideal gas mixture + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to model the adsorptive of open adsorption systems. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useHeatPorts</i>: + Defines if heat ports in the spatial direction <i>i</i> are required. + </li> + <li> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <li> + <i>idealGasMixture</i>: + Defines if the medium is an ideal gas mixture and, thus, the governing equations + can be simplified. + </li> + <li> + <i>calculateAdditionalProperties</i>: + Defines if additional properties like transport properties shall be calculated. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_independentMassBalances</i>: + Defines the type of the independent mass balances. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has two dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i>, temperature <i>T</i>, and mass fractions <i>X<sub>i</sub></i> (recommended), or + </li> + <li> + pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions <i>X<sub>i</sub></i>. + </li> +</ul> +<p> +</p> +</html>", revisions="<html> +<ul> + <li> + December 12, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasMixtureVolume; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/GasVaporMixtureVolume.mo b/SorpLib/Basics/Volumes/FluidVolumes/GasVaporMixtureVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..e5799752aac19048ca17a823769923c6e4eb778f --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/GasVaporMixtureVolume.mo @@ -0,0 +1,791 @@ +within SorpLib.Basics.Volumes.FluidVolumes; +model GasVaporMixtureVolume "Homogenous volume of an ideal gas-vapor mixture" + extends SorpLib.Basics.Volumes.BaseClasses.PartialFluidVolume( + final no_components = Medium.nX, + final pressureNoStateVariable = Medium.singleState, + final neglectTermVp = false, + redeclare final connector FluidPortsIn = + SorpLib.Basics.Interfaces.FluidPorts.GasPort_in, + redeclare final connector FluidPortsOut = + SorpLib.Basics.Interfaces.FluidPorts.GasPort_out, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + useHeatPorts=true, + useHeatPortsY=true, + h_initial=Medium.specificEnthalpy_pTX(p=p_initial, T=T_initial, X=X_i_initial), + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture + "Medium model of the ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + parameter Integer no_adsorptivs(min=1, max=no_components) = 1 + "Number of adsorptivs (i.e., components that can be adsorbed/desorbed)" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true); + parameter Integer[no_adsorptivs] ind_adsorptivs= + fill(Medium.nX, no_adsorptivs) + "Indexes of adsorptivs in the ideal gas mixture" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true); + final parameter Integer[no_components] mapped_ind_adsorptivs= + SorpLib.Basics.Volumes.Utilities.mapSorptionFluidPorts( + no_components=no_components, + ind_adsorptivs=ind_adsorptivs) + "Indices of sorption fluid ports mapped to component indices: I.e., value of + zero if component cannot be adsorbed/desorbed; otherwise, value of sorption + fluid port" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding the calculation setup + // + parameter Boolean idealGasVaporMixture = true + " = true, if medium is an ideal gas-vapoor mixture and govering equations are + explicitly written for an ideal gas mixture (i.e., unsaturated air)" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.MassFraction[no_components] X_i_initial= + Medium.reference_X + "Initial values of mass fractions" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + + parameter Modelica.Units.SI.MassFlowRate md_flow_initialX = 1e-4 + "Start value for diffusive mass flow rates in x direction" + annotation (Dialog(tab="Initialisation", group="Start Values")); + parameter Modelica.Units.SI.MassFlowRate ms_flow_initial = 1e-4 + "Start value for sorption mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter SorpLib.Choices.BalanceEquations type_independentMassBalances= + type_overallMassBalance + "Handling of independent mass balances and corresponding initialisations" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult=true); + + // + // Definition of ports + // + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_sorption + "Sorption heat port" + annotation (Placement(transformation(extent={{10,-50},{22,-38}}), + iconTransformation(extent={{10,-50},{22,-38}}))); + + FluidPortsIn[no_components] dfp_xMinus( + each final no_components=1, + m_flow(each start=-md_flow_initialX)) + "Diffusive fluid port at position '-dx/2'" + annotation (Placement(transformation(extent={{-82,-22},{-74,-14}}), + iconTransformation(extent={{-82,-22},{-74,-14}}))); + FluidPortsOut[no_components] dfp_xPlus( + each final no_components=1, + m_flow(each start=md_flow_initialX)) + "Diffusive fluid port at position '+dx/2'" + annotation (Placement(transformation(extent={{38,-22},{46,-14}}), + iconTransformation(extent={{38,-22},{46,-14}}))); + + FluidPortsIn[no_adsorptivs] fp_sorption( + each final no_components=1, + m_flow(each start=ms_flow_initial)) + "Sorption fluid port" + annotation (Placement(transformation(extent={{-20,-80},{-12,-72}}), + iconTransformation(extent={{-20,-80},{-12,-72}}))); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure[no_components] p_i + "Partial pressures"; + Modelica.Units.SI.MassFraction[no_components] X_i( + start=X_i_initial, + each stateSelect=StateSelect.prefer) + "Mass fractions"; + + Modelica.Units.SI.SpecificEnthalpy[no_components] h_i + "Specific enthalpy of individual components"; + + Modelica.Units.SI.Mass[no_components] m_i + "Mass of individual components"; + + Modelica.Units.SI.MassFlowRate[no_components] dm_i_dtau + "Derivative of individual components' masses w.r.t. time"; + + Modelica.Units.SI.MassFlowRate[no_components] mc_i_flow + "Sum of all individual components' convective mass flow rates across + boundaries"; + Modelica.Units.SI.MassFlowRate md_flow + "Sum of all diffusive mass flow rates across boundaries"; + Modelica.Units.SI.MassFlowRate[no_components] md_i_flow + "Sum of all individual components' diffusive mass flow rates across + boundaries"; + Modelica.Units.SI.MassFlowRate ms_flow + "Sum of all sorption mass flow rates across boundaries"; + Modelica.Units.SI.MassFlowRate[no_components] ms_i_flow + "Sum of all individual components' sorption mass flow rates across + boundaries"; + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + +initial equation + if type_independentMassBalances == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + X_i = X_i_initial + "Fixed initial values"; + + elseif type_independentMassBalances == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + der(X_i) = zeros(no_components) + "Steady-state initialisation of independent mass balances"; + + end if; + +equation + // + // Assertations + // + assert(pressureNoStateVariable or not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + if idealGasVaporMixture then + assert(Medium.relativeHumidity(state=state) < 1.0, + "Govering equations according to ideal gas mixture can only be applied if " + + "dry air is not saturatred! Results may not be reasonable!", + level = AssertionLevel.warning); + + end if; + + // + // Calculation of properties + // + if independentStateVariables == + SorpLib.Choices.IndependentVariablesVolume.pTX then + state = Medium.setState_pTX(p=p, T=T, X=X_i) + "Thermodynamic state required to calculate medium properties"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + else + state = Medium.setState_phX(p=p, h=h, X=X_i) + "Thermodynamic state required to calculate medium properties"; + T = Medium.temperature(state=state) + "Temperature"; + + end if; + + p_i = Medium.partialPressures(state=state) + "Partial pressures"; + v = 1 / rho + "Specific volume"; + rho = Medium.density(state=state) + "Density"; + + for ind in 1:no_components loop + h_i[ind] = Medium.specificEnthalpy_i(ind_component=ind, state=state) + "Specific enthalpy of individual components"; + end for; + + // + // Momentum balance + // + dfp_xMinus.p = p_i + "Partial pressures at the port (i.e., homogenous volume)"; + dfp_xPlus.p = p_i + "Partial pressures at the port (i.e., homogenous volume)"; + + for ind in 1:no_adsorptivs loop + fp_sorption[ind].p = p_i[ind_adsorptivs[ind]] + "Partial pressures at the port (i.e., homogenous volume)"; + end for; + + // + // Mass balance + // + m_i = m .* X_i + "Mass of individual components"; + + dm_dtau = mc_flow + md_flow + ms_flow + "Overall mass balance"; + dm_i_dtau = mc_i_flow + md_i_flow + ms_i_flow + "Individual components' mass balances"; + + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dm_dtau = geometry.V * (Medium.density_derX(state=state) * der(X_i) + + rho * (fluidProperties.kappa *der(p) - fluidProperties.beta * der(T))) + "Transient overall mass balance"; + /*dm_dtau = geometry.V * (Medium.density_derp_T(state=state) * der(p) + + Medium.density_derT_p(state=state) * der(T) + + Medium.density_derX(state=state) * der(X_i)) + "Transient overall mass balance";*/ + + else + if idealGasVaporMixture then + dm_dtau = geometry.V * (rho * (fluidProperties.kappa * der(p) - + fluidProperties.beta / fluidProperties.cp * der(h)) + + (Medium.density_derX(state=state) .+ rho .* fluidProperties.beta .* + Medium.dh_dX_pT(state=state) ./ fluidProperties.cp) * der(X_i)) + "Transient overall mass balance"; + + else + dm_dtau = geometry.V * (rho * ((fluidProperties.kappa - + fluidProperties.beta * fluidProperties.my) * der(p) - + fluidProperties.beta / fluidProperties.cp * der(h)) + + (Medium.density_derX(state=state) .+ rho .* fluidProperties.beta .* + Medium.dh_dX_pT(state=state) ./ fluidProperties.cp) * der(X_i)) + "Transient overall mass balance"; + /*dm_dtau = geometry.V * (Medium.density_derp_h(state=state) * der(p) + + Medium.density_derh_p(state=state) * der(h) + + Medium.drho_dX_ph(state=state) * der(X_i)) + "Transient overall mass balance";*/ + + end if; + end if; + end if; + + if type_independentMassBalances== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_i_dtau = zeros(no_components) + "Steady-state independent mass balances"; + + else + dm_i_dtau = X_i .* dm_dtau .+ m .* der(X_i) + "Transient independent mass balances"; + + end if; + + mc_flow = sum(cfp_xMinus.m_flow) + sum(cfp_xPlus.m_flow) + "Sum of all convective mass flow rates across boundaries"; + md_flow = sum(dfp_xMinus.m_flow) + sum(dfp_xPlus.m_flow) + "Sum of all diffusive mass flow rates across boundaries"; + ms_flow = sum(fp_sorption.m_flow) + "Sum of all sorption mass flow rates across boundaries"; + + if avoid_events then + for ind_comp in 1:no_components loop + if ind_comp <> no_components then + mc_i_flow[ind_comp] = + sum(cfp_xMinus[ind_port].m_flow * + noEvent(actualStream(cfp_xMinus[ind_port].Xi_outflow[ind_comp])) + for ind_port in 1:nPorts_cfp_xMinus) + + sum(cfp_xPlus[ind_port].m_flow * + noEvent(actualStream(cfp_xPlus[ind_port].Xi_outflow[ind_comp])) + for ind_port in 1:nPorts_cfp_xPlus) + "Sum of all convective mass flow rates of component ind_comp across + boundaries"; + + else + mc_i_flow[ind_comp] = mc_flow - sum(mc_i_flow[1:no_components-1]) + "Sum of all convective mass flow rates of last component across + boundaries"; + + end if; + end for; + + else + for ind_comp in 1:no_components loop + if ind_comp <> no_components then + mc_i_flow[ind_comp] = + sum(cfp_xMinus[ind_port].m_flow * + actualStream(cfp_xMinus[ind_port].Xi_outflow[ind_comp]) + for ind_port in 1:nPorts_cfp_xMinus) + + sum(cfp_xPlus[ind_port].m_flow * + actualStream(cfp_xPlus[ind_port].Xi_outflow[ind_comp]) + for ind_port in 1:nPorts_cfp_xPlus) + "Sum of all convective mass flow rates of component ind_comp across + boundaries"; + + else + mc_i_flow[ind_comp] = mc_flow - sum(mc_i_flow[1:no_components-1]) + "Sum of all convective mass flow rates of last component across + boundaries"; + + end if; + end for; + end if; + + md_i_flow = dfp_xMinus.m_flow .+ dfp_xPlus.m_flow + "Sum of all individual components' diffusive mass flow rates across + boundaries"; + + for ind in 1:no_components loop + ms_i_flow[ind] = if mapped_ind_adsorptivs[ind] == 0 then 0 else + fp_sorption[mapped_ind_adsorptivs[ind]].m_flow + "Sum of all individual components' sorption mass flow rates across + boundaries"; + end for; + + for ind in 1:nPorts_cfp_xMinus loop + cfp_xMinus[ind].Xi_outflow = X_i[1:no_components-1] + "Independent mass fractions leaving the port (i.e., homogenous volume)"; + end for; + for ind in 1:nPorts_cfp_xPlus loop + cfp_xPlus[ind].Xi_outflow = X_i[1:no_components-1] + "Independent mass fractions leaving the port (i.e., homogenous volume)"; + end for; + + // + // Energy balance + // + dU_dtau = Hb_flow + Qb_flow + "Energy balane"; + + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + if idealGasVaporMixture then + dU_dtau = u * dm_dtau + m * ( + (fluidProperties.cp - p * v * fluidProperties.beta) * der(T) + + (Medium.dh_dX_pT(state=state) .+ p .* v.^2 .* + Medium.density_derX(state=state)) * der(X_i)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + v * (p * fluidProperties.kappa - T * fluidProperties.beta) * der(p) + + (fluidProperties.cp - p * v * fluidProperties.beta) * der(T) + + (Medium.dh_dX_pT(state=state) .+ p .* v.^2 .* + Medium.density_derX(state=state)) * der(X_i)) + "Transient energy balance"; + /*dU_dtau = u * dm_dtau + m * ( + (Medium.dh_dp_TX(state=state) * der(p) + + Medium.dh_dT_pX(state=state) * der(T) + + Medium.dh_dX_pT(state=state) * der(X_i)) - + 1 / rho * der(p) + + p / rho^2 * (Medium.density_derp_T(state=state) * der(p) + + Medium.density_derT_p(state=state) * der(T) + + Medium.density_derX(state=state) * der(X_i))) + "Transient energy balance";*/ + + end if; + + else + if idealGasVaporMixture then + dU_dtau = u * dm_dtau + m * ( + (1 - p * v * fluidProperties.beta / fluidProperties.cp) * der(h) + + p .* v.^2 .* (Medium.density_derX(state=state) .+ rho .* + fluidProperties.beta .* Medium.dh_dX_pT(state=state) ./ + fluidProperties.cp) * der(X_i)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + (1 - p * v * fluidProperties.beta / fluidProperties.cp) * der(h) + + v * (p * (fluidProperties.kappa - fluidProperties.beta * + fluidProperties.my) - 1) * der(p) + + p .* v.^2 .* (Medium.density_derX(state=state) .+ rho .* + fluidProperties.beta .* Medium.dh_dX_pT(state=state) ./ + fluidProperties.cp) * der(X_i)) + "Transient energy balance"; + /*dU_dtau = u * dm_dtau + m * ( + der(h) - + 1 / rho * der(p) + + p / rho^2 * (Medium.density_derp_h(state=state) * der(p) + + Medium.density_derh_p(state=state) * der(h) + + Medium.drho_dX_ph(state=state) * der(X_i))) + "Transient energy balance";*/ + + end if; + end if; + end if; + + if avoid_events then + Hb_flow = + sum(cfp_xMinus.m_flow .* noEvent(actualStream(cfp_xMinus.h_outflow))) + + sum(cfp_xPlus.m_flow .* noEvent(actualStream(cfp_xPlus.h_outflow))) + + sum(dfp_xMinus.m_flow .* noEvent(actualStream(dfp_xMinus.h_outflow))) + + sum(dfp_xPlus.m_flow .* noEvent(actualStream(dfp_xPlus.h_outflow))) + + sum(fp_sorption.m_flow .* noEvent(actualStream(fp_sorption.h_outflow))) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + sum(cfp_xMinus.m_flow .* actualStream(cfp_xMinus.h_outflow)) + + sum(cfp_xPlus.m_flow .* actualStream(cfp_xPlus.h_outflow)) + + sum(dfp_xMinus.m_flow .* actualStream(dfp_xMinus.h_outflow)) + + sum(dfp_xPlus.m_flow .* actualStream(dfp_xPlus.h_outflow)) + + sum(fp_sorption.m_flow .* actualStream(fp_sorption.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + + Qb_flow = Q_flow_xMinus + Q_flow_xPlus + + Q_flow_yMinus + Q_flow_yPlus + + Q_flow_zMinus + Q_flow_zPlus + + hp_sorption.Q_flow + "Sum of all heat flow rates across boundaries"; + + dfp_xMinus.h_outflow = h_i + "Specific enthalpies leaving the port (i.e., homogenous volume)"; + dfp_xPlus.h_outflow = h_i + "Specific enthalpies leaving the port (i.e., homogenous volume)"; + + for ind in 1:no_adsorptivs loop + fp_sorption[ind].h_outflow = h_i[ind_adsorptivs[ind]] + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + end for; + + hp_sorption.T = T + "Temperature at sorption heat port"; + + // + // Summary record + // + fluidProperties.cp = if (calculateAdditionalProperties or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + fluidProperties.lambda = if calculateAdditionalProperties then + Medium.thermalConductivity(state=state) else 0 + "Thermal conductivity"; + fluidProperties.eta = if calculateAdditionalProperties then + Medium.dynamicViscosity(state=state) else 0 + "Dynamic viscosity"; + + fluidProperties.beta = if (calculateAdditionalProperties or + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + fluidProperties.kappa = if (calculateAdditionalProperties or + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + fluidProperties.my = if (calculateAdditionalProperties or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)))) then + v / fluidProperties.cp * (fluidProperties.beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + fluidProperties.Pr = if calculateAdditionalProperties then + fluidProperties.eta * fluidProperties.cp / fluidProperties.lambda else 0 + "Prandtl number"; + + fluidProperties.m_flow_sorption = ms_flow + "Total mass flow rate at port 'sorption'"; + + fluidProperties.mc_flow_yMinus = 0 + "Convective mass flow rate at port '-dy/2'"; + fluidProperties.mc_flow_yPlus = 0 + "Convective mass flow rate at port '+dy/2'"; + fluidProperties.mc_flow_zMinus = 0 + "Convective mass flow rate at port '-dz/2'"; + fluidProperties.mc_flow_zPlus = 0 + "Convective mass flow rate at port '+dz/2'"; + + fluidProperties.md_flow_xMinus = dfp_xMinus.m_flow + "Diffusive mass flow rate at port '-dx/2'"; + fluidProperties.md_flow_xPlus = dfp_xPlus.m_flow + "Diffusive mass flow rate at port '+dx/2'"; + fluidProperties.md_flow_yMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dy/2'"; + fluidProperties.md_flow_yPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dy/2'"; + fluidProperties.md_flow_zMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dz/2'"; + fluidProperties.md_flow_zPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a gas-vapor-mixture volume, applying a lumped modeling approach. +Depending on the volume setup, this model may have up to seven heat ports (i.e., two +for each spatial direction of a cartesian coordinate system and one for an adsorbate +volume). Furthermore, this model has convective fluid ports in y-direction, following +the 'connectorSizing' principle, diffusive fluid ports in y-direction, and a sorption +fluid port. These ports allow for the combination of several fluid volumes to create a +spatially distributed model. +</p> + +<h4>Main equations</h4> +<p> +The most important equations are the momentum, mass, and energy balance. According to +the staggered grid approach, the momentum balance is not solved within the volume but +at the volume's boundaries via so-called +<a href=\"Modelica://SorpLib.Components.Fittings\">flow models</a>. Hennce, no pressure +losses occur within the volume: +</p> +<pre> + p = cfp_xMinus.p; +</pre> +<pre> + p = cfp_xPlus.p; +</pre> +<p> +The pressure at the diffusive fluid ports and sorption fluid ports correspnds to the +correct partial pressure: +</p> +<pre> + p_i[i] = dfp_xMinus[i].p; +</pre> +<pre> + p_i[i] = dfp_xPlus[i].p; +</pre> +<pre> + p_i[i] = fp_sorption[i].p; +</pre> + +<br/> +<p> +Regarding the mass and energy balances, either steady-state or tansient balnaces can be +selected. When using the pressure <i>p</i>, temperature <i>T</i>, and mass fractions +<i>X<sub>i</sub></i> as independent states, the overall mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = V * [ρ * (κ * (dp/dτ) - β * (dT/dτ)) + ∑ (∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) * (dX<sub>i</sub>/dτ)] = ∑ m<sub>c,flow</sub> + ∑ m<sub>d,flow</sub>+ ∑ m<sub>s,flow</sub>; +</pre> +<p> +the component-specific mass balances are defined as +</p> +<pre> + (dm<sub>i</sub>/dτ) = X<sub>i</sub> * (dm/dτ) + m * (dX<sub>i</sub>/dτ) = ∑ m<sub>c,i,flow</sub> + ∑ m<sub>d,i,flow</sub>+ ∑ m<sub>s,i,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [v * (p * κ - T * β) * (dp/dτ) + (c<sub>p</sub> - p * v * β) * (dT/dτ) + ∑ ((∂h/∂X<sub>i</sub>|<sub>p,T</sub>) + p * v<sup>2</sup> * (∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>)) * (dX<sub>i</sub>/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<br/> +<p> +When using the pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions +<i>X<sub>i</sub></i> as independent states, the overall mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = V * [ρ * ((κ - β * μ) * (dp/dτ) - β / c<sub>p</sub> * (dh/dτ)) + ∑ ((∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) + ρ * β * (∂h/∂X<sub>i</sub>|<sub>p,T</sub>) / c<sub>p</sub>) * (dX<sub>i</sub>/dτ)] = ∑ m<sub>c,flow</sub> + ∑ m<sub>d,flow</sub>+ ∑ m<sub>s,flow</sub>; +</pre> +<p> +the component-specific mass balances are defined as +</p> +<pre> + (dm<sub>i</sub>/dτ) = X<sub>i</sub> * (dm/dτ) + m * (dX<sub>i</sub>/dτ) = ∑ m<sub>c,i,flow</sub> + ∑ m<sub>d,i,flow</sub>+ ∑ m<sub>s,i,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [v * (p * (κ - β * μ) - 1) * (dp/dτ) + (1 - p * v * β / c<sub>p</sub>) * (dh/dτ) + ∑ p * v<sup>2</sup> * ((∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) + ρ * β * (∂h/∂X<sub>i</sub>|<sub>p,T</sub>) / c<sub>p</sub>) * (dX<sub>i</sub>/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<br/> +<p> +Herein, <i>(dm/dτ)</i> is the derivative of the mass w.r.t. time, <i>(dU/dτ)</i> +is the derivative of the internal energy w.r.t. time, <i>(dρ/dτ)</i> is the +derivative of the density w.r.t. time, <i>(du/dτ)</i> is the derivative of the specific +internal energy w.r.t.time, <i>(dp/dτ)</i> is the derivative of the pressure w.r.t. +time, <i>(dT/dτ)</i> is the derivative of the temperature w.r.t. time, <i>(dh/dτ)</i> +is the derivative of the specific enthalpy w.r.t. time, <i>(dX<sub>i</sub>/dτ)</i> are the +derivatives of the mass fractions w.r.t. time, <i>(∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>)</i> is +the partial derivative of the density w.r.t. mass fractions at constant pressure and temperatre, +<i>(∂h/∂X<sub>i</sub>|<sub>p,T</sub>)</i> is the partial derivative of the specific enthaly w.r.t. +mass fractions at constant pressure and temperature, <i>V</i> is the volume, <i>m</i> is the mass, +<i>v</i> is the specific volume, <i>ρ</i> is the density, <i>κ</i> is the isothermal +compressibility, <i>β</i> is the isobaric expansion coefficient, <i>μ</i> is the Joule-Thomson +coefficient, <i>c<sub>p</sub></i> is the specific heat capacity at constant pressure, +<i>m<sub>c,flow</sub></i> is the sum of the convective mass flow rates, <i>m<sub>d,flow</sub></i> is +the sum of the diffusive mass flow rates, <i>m<sub>s,flow</sub></i> is the sum of the sorption mass +flow rates, <i>H<sub>b,flow</sub></i> is the sum of the enthalpy flow rates, and <i>Q<sub>b,flow</sub></i> +is the sum of the heat flow rates. Mass flow rates with index <i>i</i> describe component-specific +mass flow rates. +</p> + +<h4>Main equations for an ideal gas mixture</h4> +<p> +For an ideal gas mixture, the isothermal compressibility <i>κ</i> is <i>1/p</i> and the +isbaric expansion coefficient <i>β</i> is <i>1/T</i>, leading to a Joule-Thomson coefficient +<i>μ</i> of zero. Hence, the overall mass and energy balances can be simplified. When using the +pressure <i>p</i>, temperature <i>T</i>, and mass fractions <i>X<sub>i</sub></i> as independent +states, the overall mass balance still reads as +</p> +<pre> + (dm/dτ) = V * [ρ * (κ * (dp/dτ) - β * (dT/dτ)) + ∑ (∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) * (dX<sub>i</sub>/dτ)] = ∑ m<sub>c,flow</sub> + ∑ m<sub>d,flow</sub>+ ∑ m<sub>s,flow</sub>; +</pre> +<p> +but the energy balance now reads as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * [(c<sub>p</sub> - p * v * β) * (dT/dτ) + ∑ ((∂h/∂X<sub>i</sub>|<sub>p,T</sub>) + p * v<sup>2</sup> * (∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>)) * (dX<sub>i</sub>/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<br/> +<p> +When using the pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions +<i>X<sub>i</sub></i> as independent states, the overall mass balance now reads as +</p> +<pre> + (dm/dτ) = V * [ρ * (κ * (dp/dτ) - β / c<sub>p</sub> * (dh/dτ)) + ∑ ((∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) + ρ * β * (∂h/∂X<sub>i</sub>|<sub>p,T</sub>) / c<sub>p</sub>) * (dX<sub>i</sub>/dτ)] = ∑ m<sub>c,flow</sub> + ∑ m<sub>d,flow</sub>+ ∑ m<sub>s,flow</sub>; +</pre> +<p> +and the energy balance now reads as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * [(1 - p * v * β / c<sub>p</sub>) * (dh/dτ) + ∑ p * v<sup>2</sup> * ((∂ρ/∂X<sub>i</sub>|<sub>p,T</sub>) + ρ * β * (∂h/∂X<sub>i</sub>|<sub>p,T</sub>) / c<sub>p</sub>) * (dX<sub>i</sub>/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> + <li> + Ideal gas-vapor mixture + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to model the adsorptive of open adsorption systems. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useHeatPorts</i>: + Defines if heat ports in the spatial direction <i>i</i> are required. + </li> + <li> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <li> + <i>idealGasVaporMixture</i>: + Defines if the medium is an ideal gas-vapor mixture and, thus, the governing + equations can be simplified. + </li> + <li> + <i>calculateAdditionalProperties</i>: + Defines if additional properties like transport properties shall be calculated. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_independentMassBalances</i>: + Defines the type of the independent mass balances. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has two dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i>, temperature <i>T</i>, and mass fractions <i>X<sub>i</sub></i> (recommended), or + </li> + <li> + pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions <i>X<sub>i</sub></i>. + </li> +</ul> +<p> +</p> +</html>", revisions="<html> +<ul> + <li> + December 13, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasVaporMixtureVolume; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/GasVolume.mo b/SorpLib/Basics/Volumes/FluidVolumes/GasVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..7ea8547abd427d8dde708f2a689422ec738a5ecf --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/GasVolume.mo @@ -0,0 +1,510 @@ +within SorpLib.Basics.Volumes.FluidVolumes; +model GasVolume "Homogenous volume of an ideal gas" + extends SorpLib.Basics.Volumes.BaseClasses.PartialFluidVolume( + final no_components = Medium.nX, + final pressureNoStateVariable = Medium.singleState, + final neglectTermVp = false, + redeclare final connector FluidPortsIn = + SorpLib.Basics.Interfaces.FluidPorts.GasPort_in, + redeclare final connector FluidPortsOut = + SorpLib.Basics.Interfaces.FluidPorts.GasPort_out, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + useHeatPorts=true, + useHeatPortsY=true, + h_initial=Medium.specificEnthalpy_pTX(p=p_initial, T=T_initial, X=Medium.reference_X), + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = SorpLib.Media.IdealGases.N2 + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium model of the ideal gas" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the calculation setup + // + parameter Boolean idealGas = true + " = true, if medium is an ideal gas and govering equations are explicitly + written for an ideal gas" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.MassFlowRate ms_flow_initial = 1e-4 + "Start value for sorption mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of ports + // + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_sorption + "Sorption heat port" + annotation (Placement(transformation(extent={{10,-50},{22,-38}}), + iconTransformation(extent={{10,-50},{22,-38}}))); + + FluidPortsIn fp_sorption( + final no_components=no_components, + m_flow(start=ms_flow_initial)) + "Sorption fluid port" + annotation (Placement(transformation(extent={{-20,-80},{-12,-72}}), + iconTransformation(extent={{-20,-80},{-12,-72}}))); + + // + // Definition of variables + // + Modelica.Units.SI.MassFlowRate ms_flow + "Sum of all sorption mass flow rates across boundaries"; + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + +equation + // + // Assertations + // + assert(no_components <= 1, + "The gas volume model can only handel pure fluids (i.e., with one component)!", + level = AssertionLevel.error); + + assert(pressureNoStateVariable or not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + // + // Calculation of properties + // + if independentStateVariables == + SorpLib.Choices.IndependentVariablesVolume.pTX then + state = Medium.setState_pTX(p=p, T=T, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + else + state = Medium.setState_phX(p=p, h=h, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + T = Medium.temperature(state=state) + "Temperature"; + + end if; + + v = 1 / rho + "Specific volume"; + rho = Medium.density(state=state) + "Density"; + + // + // Momentum balance + // + fp_sorption.p = p + "Total pressure at the port (i.e., homogenous volume)"; + + // + // Mass balance + // + dm_dtau = mc_flow + ms_flow + "Overall mass balance"; + + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dm_dtau = geometry.V * rho * + (fluidProperties.kappa *der(p) - fluidProperties.beta * der(T)) + "Transient overall mass balance"; + + else + if idealGas then + dm_dtau = geometry.V * rho * ( + fluidProperties.kappa * der(p) - + fluidProperties.beta / fluidProperties.cp * der(h)) + "Transient overall mass balance"; + + else + dm_dtau = geometry.V * rho * ((fluidProperties.kappa - + fluidProperties.beta * fluidProperties.my) * der(p) - + fluidProperties.beta / fluidProperties.cp * der(h)) + "Transient overall mass balance"; + + end if; + end if; + end if; + + mc_flow = sum(cfp_xMinus.m_flow) + sum(cfp_xPlus.m_flow) + "Sum of all convective mass flow rates across boundaries"; + ms_flow = fp_sorption.m_flow + "Sum of all sorption mass flow rates across boundaries"; + + // + // Energy balance + // + dU_dtau = Hb_flow + Qb_flow + "Energy balane"; + + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + if idealGas then + dU_dtau = u * dm_dtau + m * ( + (fluidProperties.cp - p * v * fluidProperties.beta) * der(T)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + v * (p * fluidProperties.kappa - T * fluidProperties.beta) * der(p) + + (fluidProperties.cp - p * v * fluidProperties.beta) * der(T)) + "Transient energy balance"; + + end if; + + else + if idealGas then + dU_dtau = u * dm_dtau + m * ( + (1 - p * v * fluidProperties.beta / fluidProperties.cp) * der(h)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + (1 - p * v * fluidProperties.beta / fluidProperties.cp) * der(h) + + v * (p * (fluidProperties.kappa - fluidProperties.beta * + fluidProperties.my) - 1) * der(p)) + "Transient energy balance"; + + end if; + end if; + end if; + + if avoid_events then + Hb_flow = + sum(cfp_xMinus.m_flow .* noEvent(actualStream(cfp_xMinus.h_outflow))) + + sum(cfp_xPlus.m_flow .* noEvent(actualStream(cfp_xPlus.h_outflow))) + + fp_sorption.m_flow * noEvent(actualStream(fp_sorption.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + sum(cfp_xMinus.m_flow .* actualStream(cfp_xMinus.h_outflow)) + + sum(cfp_xPlus.m_flow .* actualStream(cfp_xPlus.h_outflow)) + + fp_sorption.m_flow * actualStream(fp_sorption.h_outflow) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + + Qb_flow = Q_flow_xMinus + Q_flow_xPlus + + Q_flow_yMinus + Q_flow_yPlus + + Q_flow_zMinus + Q_flow_zPlus + + hp_sorption.Q_flow + "Sum of all heat flow rates across boundaries"; + + fp_sorption.h_outflow = h + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + + hp_sorption.T = T + "Temperature at sorption heat port"; + + // + // Summary record + // + fluidProperties.cp = if (calculateAdditionalProperties or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + fluidProperties.lambda = if calculateAdditionalProperties then + Medium.thermalConductivity(state=state) else 0 + "Thermal conductivity"; + fluidProperties.eta = if calculateAdditionalProperties then + Medium.dynamicViscosity(state=state) else 0 + "Dynamic viscosity"; + + fluidProperties.beta = if (calculateAdditionalProperties or + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + fluidProperties.kappa = if (calculateAdditionalProperties or + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + fluidProperties.my = if (calculateAdditionalProperties or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)))) then + v / fluidProperties.cp * (fluidProperties.beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + fluidProperties.Pr = if calculateAdditionalProperties then + fluidProperties.eta * fluidProperties.cp / fluidProperties.lambda else 0 + "Prandtl number"; + + fluidProperties.m_flow_sorption = ms_flow + "Total mass flow rate at port 'sorption'"; + + fluidProperties.mc_flow_yMinus = 0 + "Convective mass flow rate at port '-dy/2'"; + fluidProperties.mc_flow_yPlus = 0 + "Convective mass flow rate at port '+dy/2'"; + fluidProperties.mc_flow_zMinus = 0 + "Convective mass flow rate at port '-dz/2'"; + fluidProperties.mc_flow_zPlus = 0 + "Convective mass flow rate at port '+dz/2'"; + + fluidProperties.md_flow_xMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dx/2'"; + fluidProperties.md_flow_xPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dx/2'"; + fluidProperties.md_flow_yMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dy/2'"; + fluidProperties.md_flow_yPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dy/2'"; + fluidProperties.md_flow_zMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dz/2'"; + fluidProperties.md_flow_zPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a gas volume, applying a lumped modeling approach. Depending +on the volume setup, this model may have up to seven heat ports (i.e., two for each +spatial direction of a cartesian coordinate system and one for an adsorbate volume). +Furthermore, this model has convective fluid ports in y-direction, following the +'connectorSizing' principle, and a sorption fluid port. These ports allow for the +combination of several fluid volumes to create a spatially distributed model. +</p> + +<h4>Main equations</h4> +<p> +The most important equations are the momentum, mass, and energy balance. According to +the staggered grid approach, the momentum balance is not solved within the volume but +at the volume's boundaries via so-called +<a href=\"Modelica://SorpLib.Components.Fittings\">flow models</a>. Hennce, no pressure +losses occur within the volume: +</p> +<pre> + p = cfp_xMinus.p; +</pre> +<pre> + p = cfp_xPlus.p; +</pre> +<pre> + p = fp_sorption.p; +</pre> + +<p> +Regarding the mass and energy balances, either steady-state or tansient balnaces +can be selected. When using the pressure <i>p</i> and temperature <i>T</i> as +independent states, the mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = V * ρ * [κ * (dp/dτ) - β * (dT/dτ)] = ∑ m<sub>c,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [v * (p * κ - T * β) * (dp/dτ) + (c<sub>p</sub> - p * v * β) * (dT/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +When using the pressure <i>p</i> and specific enthalpy <i>h</i> as independent +states, the mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = V * ρ * [(κ - β * μ) * (dp/dτ) - β / c<sub>p</sub> * (dh/dτ)] = ∑ m<sub>c,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [v * (p * (κ - β * μ) - 1) * (dp/dτ) + (1 - p * v * β / c<sub>p</sub>) * (dh/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +Herein, <i>(dm/dτ)</i> is the derivative of the mass w.r.t. time, <i>(dU/dτ)</i> +is the derivative of the internal energy w.r.t. time, <i>(dρ/dτ)</i> is the +derivative of the density w.r.t. time, <i>(du/dτ)</i> is the derivative of the specific +internal energy w.r.t.time, <i>(dp/dτ)</i> is the derivative of the pressure w.r.t. +time, <i>(dT/dτ)</i> is the derivative of the temperature w.r.t. time, <i>(dh/dτ)</i> +is the derivative of the specific enthalpy w.r.t. time, <i>V</i> is the volume, <i>m</i> is +the mass, <i>v</i> is the specific volume, <i>ρ</i> is the density, <i>κ</i> is +the isothermal compressibility, <i>β</i> is the isobaric expansion coefficient, <i>μ</i> +is the Joule-Thomson coefficient, <i>c<sub>p</sub></i> is the specific heat capacity at +constant pressure,<i>m<sub>c,flow</sub></i> is the sum of the convective mass flow rates, +<i>H<sub>b,flow</sub></i> is the sum of the enthalpy flow rates, and <i>Q<sub>b,flow</sub></i> +is the sum of the heat flow rates. +</p> + +<h4>Main equations for an ideal gas</h4> +<p> +For an ideal gas, the isothermal compressibility <i>κ</i> is <i>1/p</i> and the +isbaric expansion coefficient <i>β</i> is <i>1/T</i>, leading to a Joule-Thomson +coefficient <i>μ</i> of zero. Hence, the mass and energy balances can be simplified. +When using the pressure <i>p</i> and temperature <i>T</i> as independent states, the mass +balance still reads as +</p> +<pre> + (dm/dτ) = V * ρ * [κ * (dp/dτ) - β * (dT/dτ)] = ∑ m<sub>c,flow</sub>; +</pre> +<p> +but the energy balance now reads as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (c<sub>p</sub> - p * v * β) * (dT/dτ) = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +When using the pressure <i>p</i> and specific enthalpy <i>h</i> as independent +states, the mass balance now reads as +</p> +<pre> + (dm/dτ) = V * ρ * [κ * (dp/dτ) - β / c<sub>p</sub> * (dh/dτ)] = ∑ m<sub>c,flow</sub>; +</pre> +<p> +and the energy balance now reads as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (1 - p * v * β / c<sub>p</sub>) * (dh/dτ) = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> + <li> + Ideal gas + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to model the adsorptive of open adsorption systems. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useHeatPorts</i>: + Defines if heat ports in the spatial direction <i>i</i> are required. + </li> + <li> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <li> + <i>idealGas</i>: + Defines if the medium is an ideal gas and, thus, the governing equations can + be simplified. + </li> + <li> + <i>calculateAdditionalProperties</i>: + Defines if additional properties like transport properties shall be calculated. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has two dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i> and temperature <i>T</i> (recommended), or + </li> + <li> + pressure <i>p</i> and specific enthalpy <i>h</i>. + </li> +</ul> +<p> +Note that this model does not have the pressure <i>p</i> as dynamic state if the +fluid property model is a single state model. +</p> +</html>", revisions="<html> +<ul> + <li> + December 11, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasVolume; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/LiquidVolume.mo b/SorpLib/Basics/Volumes/FluidVolumes/LiquidVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..f50d23e5c08281c8362f184554e74a0ba0aa0618 --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/LiquidVolume.mo @@ -0,0 +1,494 @@ +within SorpLib.Basics.Volumes.FluidVolumes; +model LiquidVolume "Homogenous (ideal) liquid volume" + extends SorpLib.Basics.Volumes.BaseClasses.PartialFluidVolume( + final no_components = Medium.nX, + final pressureNoStateVariable = Medium.singleState, + redeclare final connector FluidPortsIn = + SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_in, + redeclare final connector FluidPortsOut = + SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_out, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + useHeatPorts=true, + useHeatPortsY=true, + h_initial= + Medium.specificEnthalpy_pTX(p=p_initial, T=T_initial, X=Medium.reference_X), + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the calculation setup + // + parameter Boolean incompressibleLiquid = Medium.singleState + " = true, if medium is incompressible (i.e., partial derivative of specific + volume w.r.t. pressure at constant temperature is constant) and govering + equations are explicitly written for an incompressible fluid" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + +equation + // + // Assertations + // + assert(no_components <= 1, + "The liquid volume model can only handel pure fluids (i.e., with one component)!", + level = AssertionLevel.error); + + assert(pressureNoStateVariable or not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + // + // Calculation of properties + // + if independentStateVariables == + SorpLib.Choices.IndependentVariablesVolume.pTX then + state = Medium.setState_pTX(p=p, T=T, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + else + state = Medium.setState_phX(p=p, h=h, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + T = Medium.temperature(state=state) + "Temperature"; + + end if; + + v = 1 / rho + "Specific volume"; + rho = Medium.density(state=state) + "Density"; + + // + // Mass balance + // + dm_dtau = mc_flow + "Overall mass balance"; + + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + if incompressibleLiquid then + dm_dtau = -geometry.V * rho * fluidProperties.beta * der(T) + "Transient overall mass balance"; + + else + dm_dtau = geometry.V * rho * ( + fluidProperties.kappa *der(p) - fluidProperties.beta * der(T)) + "Transient overall mass balance"; + + end if; + + else + if incompressibleLiquid then + dm_dtau = -geometry.V * rho * fluidProperties.beta * ( + fluidProperties.my * der(p) + + 1 / fluidProperties.cp * der(h)) + "Transient overall mass balance"; + + else + dm_dtau = geometry.V * rho * ((fluidProperties.kappa - + fluidProperties.beta * fluidProperties.my) * der(p) - + fluidProperties.beta / fluidProperties.cp * der(h)) + "Transient overall mass balance"; + + end if; + end if; + end if; + + mc_flow = sum(cfp_xMinus.m_flow) + sum(cfp_xPlus.m_flow) + "Sum of all convective mass flow rates across boundaries"; + + // + // Energy balance + // + dU_dtau = Hb_flow + Qb_flow + "Energy balane"; + + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + if neglectTermVp then + dU_dtau = u * dm_dtau + m * ( + v * (1 - T * fluidProperties.beta) * der(p) + + fluidProperties.cp * der(T)) + "Transient energy balance"; + + else + if incompressibleLiquid then + dU_dtau = u * dm_dtau + m * ( + -v * T * fluidProperties.beta * der(p) + + (fluidProperties.cp - p * v * fluidProperties.beta) * der(T)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + v * (p * fluidProperties.kappa - T * fluidProperties.beta) * der(p) + + (fluidProperties.cp - p * v * fluidProperties.beta) * der(T)) + "Transient energy balance"; + + end if; + end if; + + else + if neglectTermVp then + dU_dtau = u * dm_dtau + m * der(h) + "Transient energy balance"; + + else + if incompressibleLiquid then + dU_dtau = u * dm_dtau + m * ( + (1 - p * v * fluidProperties.beta / fluidProperties.cp) * der(h) - + v * (p * fluidProperties.beta * fluidProperties.my + 1) * der(p)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + (1 - p * v * fluidProperties.beta / fluidProperties.cp) * der(h) + + v * (p * (fluidProperties.kappa - fluidProperties.beta * + fluidProperties.my) - 1) * der(p)) + "Transient energy balance"; + + end if; + end if; + end if; + end if; + + if avoid_events then + Hb_flow = + sum(cfp_xMinus.m_flow .* noEvent(actualStream(cfp_xMinus.h_outflow))) + + sum(cfp_xPlus.m_flow .* noEvent(actualStream(cfp_xPlus.h_outflow))) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + sum(cfp_xMinus.m_flow .* actualStream(cfp_xMinus.h_outflow)) + + sum(cfp_xPlus.m_flow .* actualStream(cfp_xPlus.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + + Qb_flow = Q_flow_xMinus + Q_flow_xPlus + + Q_flow_yMinus + Q_flow_yPlus + + Q_flow_zMinus + Q_flow_zPlus + "Sum of all heat flow rates across boundaries"; + + // + // Summary record + // + fluidProperties.cp = if (calculateAdditionalProperties or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + fluidProperties.lambda = if calculateAdditionalProperties then + Medium.thermalConductivity(state=state) else 0 + "Thermal conductivity"; + fluidProperties.eta = if calculateAdditionalProperties then + Medium.dynamicViscosity(state=state) else 0 + "Dynamic viscosity"; + + fluidProperties.beta = if (calculateAdditionalProperties or + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + fluidProperties.kappa = if (not incompressibleLiquid and + (calculateAdditionalProperties or + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp))) then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + fluidProperties.my = if (calculateAdditionalProperties or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)))) then + v / fluidProperties.cp * (fluidProperties.beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + fluidProperties.Pr = if calculateAdditionalProperties then + fluidProperties.eta * fluidProperties.cp / fluidProperties.lambda else 0 + "Prandtl number"; + + fluidProperties.m_flow_sorption = 0 + "Total mass flow rate at port 'sorption'"; + + fluidProperties.mc_flow_yMinus = 0 + "Total convective mass flow rate at port '-dy/2'"; + fluidProperties.mc_flow_yPlus = 0 + "Total convective mass flow rate at port '+dy/2'"; + fluidProperties.mc_flow_zMinus = 0 + "Total convective mass flow rate at port '-dz/2'"; + fluidProperties.mc_flow_zPlus = 0 + "Total convective mass flow rate at port '+dz/2'"; + + fluidProperties.md_flow_xMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dx/2'"; + fluidProperties.md_flow_xPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dx/2'"; + fluidProperties.md_flow_yMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dy/2'"; + fluidProperties.md_flow_yPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dy/2'"; + fluidProperties.md_flow_zMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dz/2'"; + fluidProperties.md_flow_zPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a liquid volume, applying a lumped modeling approach. Depending +on the volume setup, this model may have up to six heat ports (i.e., two for each +spatial direction of a cartesian coordinate system). Furthermore, this model has +convective fluid ports in y-direction, following the 'connectorSizing' principle. +These ports allow for the combination of several fluid volumes to create a spatially +distributed model. +</p> + +<h4>Main equations</h4> +<p> +The most important equations are the momentum, mass, and energy balance. According to +the staggered grid approach, the momentum balance is not solved within the volume but +at the volume's boundaries via so-called +<a href=\"Modelica://SorpLib.Components.Fittings\">flow models</a>. Hennce, no pressure +losses occur within the volume: +</p> +<pre> + p = cfp_xMinus.p; +</pre> +<pre> + p = cfp_xPlus.p; +</pre> + +<p> +Regarding the mass and energy balances, either steady-state or tansient balnaces +can be selected. When using the pressure <i>p</i> and temperature <i>T</i> as +independent states, the mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = V * ρ * [κ * (dp/dτ) - β * (dT/dτ)] = ∑ m<sub>c,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [v * (p * κ - T * β) * (dp/dτ) + (c<sub>p</sub> - p * v * β) * (dT/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +When using the pressure <i>p</i> and specific enthalpy <i>h</i> as independent +states, the mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = V * ρ * [(κ - β * μ) * (dp/dτ) - β / c<sub>p</sub> * (dh/dτ)] = ∑ m<sub>c,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [v * (p * (κ - β * μ) - 1) * (dp/dτ) + (1 - p * v * β / c<sub>p</sub>) * (dh/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +Herein, <i>(dm/dτ)</i> is the derivative of the mass w.r.t. time, <i>(dU/dτ)</i> +is the derivative of the internal energy w.r.t. time, <i>(dρ/dτ)</i> is the +derivative of the density w.r.t. time, <i>(du/dτ)</i> is the derivative of the specific +internal energy w.r.t.time, <i>(dp/dτ)</i> is the derivative of the pressure w.r.t. +time, <i>(dT/dτ)</i> is the derivative of the temperature w.r.t. time, <i>(dh/dτ)</i> +is the derivative of the specific enthalpy w.r.t. time, <i>V</i> is the volume, <i>m</i> is +the mass, <i>v</i> is the specific volume, <i>ρ</i> is the density, <i>κ</i> is +the isothermal compressibility, <i>β</i> is the isobaric expansion coefficient, <i>μ</i> +is the Joule-Thomson coefficient, <i>c<sub>p</sub></i> is the specific heat capacity at +constant pressure,<i>m<sub>c,flow</sub></i> is the sum of the convective mass flow rates, +<i>H<sub>b,flow</sub></i> is the sum of the enthalpy flow rates, and <i>Q<sub>b,flow</sub></i> +is the sum of the heat flow rates. +</p> + +<h4>Main equations for an ideal liquid</h4> +<p> +The liquid is incompressible when using the fluid property model of an ideal liquid. +In this case, the isothermal compressibility <i>κ</i> is zero (see option +'incompressibleLiquid'), and the mass and energy balances can be simplified. When using +the pressure <i>p</i> and temperature <i>T</i> as independent states, the mass balance +reads now as +</p> +<pre> + (dm/dτ) = -V * ρ * β * (dT/dτ) = ∑ m<sub>c,flow</sub>; +</pre> +<p> +and the energy balance reads now as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * [-v * T * β * (dp/dτ) + (c<sub>p</sub> - p * v * β) * (dT/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +When using the pressure <i>p</i> and specific enthalpy <i>h</i> as independent states, +the mass balance reads now as +</p> +<pre> + (dm/dτ) = -V * ρ * β * [μ * (dp/dτ) + 1/c<sub>p</sub> * (dh/dτ)] = ∑ m<sub>c,flow</sub>; +</pre> +<p> +and the energy balance reads now as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * [-v * (p * β * μ + 1) * (dp/dτ) + (1 - p * v * β / c<sub>p</sub>) * (dh/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to model the heat transfer fluid of a a pipe or heat +exchanger. In this context, the liquid is often modelled as an ideal liquid. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useHeatPorts</i>: + Defines if heat ports in the spatial direction <i>i</i> are required. + </li> + <li> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <li> + <i>incompressibleLiquid</i>: + Defines if the medium is incompressible and the partial derivative of specific + volume w.r.t. pressure at constant temperature is constant, thus leading to + simplified governing equations. + </li> + <li> + <i>neglectTermVp</i>: + Defines if the term 'p*V' is neglected to calculate specific internal energy. + </li> + <li> + <i>calculateAdditionalProperties</i>: + Defines if additional properties like transport properties shall be calculated. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has two dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i> and temperature <i>T</i> (recommended), or + </li> + <li> + pressure <i>p</i> and specific enthalpy <i>h</i>. + </li> +</ul> +<p> +Note that this model does not have the pressure <i>p</i> as dynamic state if the +fluid property model is a single state model. +</p> +</html>", revisions="<html> +<ul> + <li> + December 7, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end LiquidVolume; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_GasMixtureVolume.mo b/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_GasMixtureVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..93a5edbd09f22d9e054300ea60a3ad9eba8d8979 --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_GasMixtureVolume.mo @@ -0,0 +1,235 @@ +within SorpLib.Basics.Volumes.FluidVolumes.Tester; +model Test_GasMixtureVolume "Tester for gas mixture volume" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture + "Medium model of the ideal gas mixture" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of liquid models + // + SorpLib.Basics.Volumes.FluidVolumes.GasMixtureVolume + gas_pTX_transientMassBalance_transientEnergyBalance( + no_adsorptivs=2, + ind_adsorptivs={3,4}, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + p_initial=25000, + T_initial=293.15, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_independentMassBalances=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "Gas-mixture volume with p, T, and X as independent states, transient mass + balance with fixed initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + + SorpLib.Basics.Volumes.FluidVolumes.GasMixtureVolume + gas_phX_transientMassBalance_transientEnergyBalance( + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + no_adsorptivs=2, + ind_adsorptivs={3,4}, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + p_initial=25000, + h_initial=295427, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_independentMassBalances=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "Gas-mixture volume with p, h, and X as independent states, transient mass + balance with fixed initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{40,-10},{60,10}}))); + + // + // Definition of fluid boundaries + // +protected + SorpLib.Basics.Sources.Fluids.GasSource + inlet_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{-72,-10},{-52,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource + outlet_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=1e-3, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{-28,-10},{-48,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource + inlet_pTX_transientMassBalance_transientEnergyBalance_ads1( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-1e-6, + T_fixed=393.15, + redeclare package Medium = Media.IdealGases.CO2) + "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{-76,-12},{-56,8}}))); + SorpLib.Basics.Sources.Fluids.GasSource + inlet_pTX_transientMassBalance_transientEnergyBalance_ads2( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-1e-5, + T_fixed=393.15, + redeclare package Medium = Media.IdealGases.H2O) + "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{-80,-14},{-60,6}}))); + + SorpLib.Basics.Sources.Fluids.GasSource + inlet_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{28,-10},{48,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource + outlet_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=1e-3, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{72,-10},{52,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource + inlet_phX_transientMassBalance_transientEnergyBalance_ads1( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-1e-6, + T_fixed=393.15, + redeclare package Medium = Media.IdealGases.CO2) + "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{24,-12},{44,8}}))); + SorpLib.Basics.Sources.Fluids.GasSource + inlet_phX_transientMassBalance_transientEnergyBalance_ads2( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-1e-5, + T_fixed=393.15, + redeclare package Medium = Media.IdealGases.H2O) + "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{20,-14},{40,6}}))); + + // + // Definition of thermal boundaries + // + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_transientMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for Gas-mixture volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-40,-12}))); + + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_transientMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for Gas-mixture volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={60,-12}))); + +equation + // + // Connections + // + connect(inlet_pTX_transientMassBalance_transientEnergyBalance.port, + gas_pTX_transientMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{-62,0},{-60,0},{-60,1.8},{-54.2,1.8}}, + color={244,125,35}, + thickness=1)); + connect(outlet_pTX_transientMassBalance_transientEnergyBalance.port, + gas_pTX_transientMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,0},{-40,0},{-40,1.8},{-42.2,1.8}}, + color={244,125,35}, + thickness=1)); + connect(inlet_phX_transientMassBalance_transientEnergyBalance.port, + gas_phX_transientMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,0},{40,0},{40,1.8},{45.8,1.8}}, + color={244,125,35}, + thickness=1)); + connect(outlet_phX_transientMassBalance_transientEnergyBalance.port, + gas_phX_transientMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,0},{60,0},{60,1.8},{57.8,1.8}}, + color={244,125,35}, + thickness=1)); + connect(inlet_pTX_transientMassBalance_transientEnergyBalance_ads1.port, + gas_pTX_transientMassBalance_transientEnergyBalance.fp_sorption[1]) + annotation (Line( + points={{-66,-2},{-64,-2},{-64,-10},{-51.6,-10},{-51.6,-7.8}}, + color={244,125,35}, + thickness=1)); + connect(inlet_pTX_transientMassBalance_transientEnergyBalance_ads2.port, + gas_pTX_transientMassBalance_transientEnergyBalance.fp_sorption[2]) + annotation (Line( + points={{-70,-4},{-68,-4},{-68,-12},{-51.6,-12},{-51.6,-7.4}}, + color={244,125,35}, + thickness=1)); + connect(inlet_phX_transientMassBalance_transientEnergyBalance_ads1.port, + gas_phX_transientMassBalance_transientEnergyBalance.fp_sorption[1]) + annotation (Line( + points={{34,-2},{36,-2},{36,-10},{48.4,-10},{48.4,-7.8}}, + color={244,125,35}, + thickness=1)); + connect(inlet_phX_transientMassBalance_transientEnergyBalance_ads2.port, + gas_phX_transientMassBalance_transientEnergyBalance.fp_sorption[2]) + annotation (Line( + points={{30,-4},{32,-4},{32,-12},{48.4,-12},{48.4,-7.4}}, + color={244,125,35}, + thickness=1)); + + connect(heatSource_pTX_transientMassBalance_transientEnergyBalance.port, + gas_pTX_transientMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{-40,-12},{-40,-8},{-50,-8},{-50,-6}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_transientMassBalance_transientEnergyBalance.port, + gas_phX_transientMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{60,-12},{60,-8},{50,-8},{50,-6}}, + color={238,46,47}, + thickness=1)); + + // + // Annotations + // + annotation (experiment(StopTime=25), Documentation(info="<html> +<p> +This model checks the gas mixture volume model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 25 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 12, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasMixtureVolume; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_GasVaporMixtureVolume.mo b/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_GasVaporMixtureVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..005425170801e46c18996b41cf81478be822323e --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_GasVaporMixtureVolume.mo @@ -0,0 +1,307 @@ +within SorpLib.Basics.Volumes.FluidVolumes.Tester; +model Test_GasVaporMixtureVolume "Tester for gas-vapor-mixture volume" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture + "Medium model of the ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of liquid models + // + SorpLib.Basics.Volumes.FluidVolumes.GasVaporMixtureVolume + gas_pTX_transientMassBalance_transientEnergyBalance( + no_adsorptivs=2, + ind_adsorptivs={1,3}, + idealGasVaporMixture=false, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + p_initial=15000, + T_initial=293.15, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_independentMassBalances=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "Gas-mixture volume with p, T, and X as independent states, transient mass + balance with fixed initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + + SorpLib.Basics.Volumes.FluidVolumes.GasVaporMixtureVolume + gas_phX_transientMassBalance_transientEnergyBalance( + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + no_adsorptivs=2, + ind_adsorptivs={1,3}, + idealGasVaporMixture=false, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + p_initial=15000, + h_initial=20223.1, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_independentMassBalances=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "Gas-mixture volume with p, h, and X as independent states, transient mass + balance with fixed initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{40,-10},{60,10}}))); + + // + // Definition of fluid boundaries + // +protected + Modelica.Blocks.Sources.Sine input_m_N2_flow( + amplitude=1e-5, + f=1/5) + "Input signal for mass flow rate of N2" + annotation (Placement(transformation(extent={{-100,60},{-80,80}}))); + Modelica.Blocks.Sources.Sine input_m_CO2_flow( + amplitude=1e-8, + f=1/5) + "Input signal for mass flow rate of CO2" + annotation (Placement(transformation(extent={{-100,20},{-80,40}}))); + Modelica.Blocks.Sources.Ramp input_m_flow( + height=-1e-4, + duration=15, + offset=-1e-3, + startTime=10) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{100,10},{80,30}}))); + Modelica.Blocks.Sources.Sine input_T( + amplitude=40, + f=1/5, + offset=273.15 + 50) + "Input signal for temperature" + annotation (Placement(transformation(extent={{100,50},{80,70}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource + inlet_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + use_mFlowInput=true, + m_flow_fixed=-0.001, + use_TInput=true, + T_fixed=323.15, + X_fixed={0.6,0.1,0.1,0.2}, + redeclare package Medium = Medium) "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{-72,-10},{-52,10}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource + outlet_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=1e-3, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{-28,-10},{-48,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource + inlet_pTX_transientMassBalance_transientEnergyBalance_ads1( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + m_flow_fixed=-1e-6, + T_fixed=393.15, + redeclare package Medium = Media.IdealGases.N2) + "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{-82,-12},{-62,8}}))); + SorpLib.Basics.Sources.Fluids.GasSource + inlet_pTX_transientMassBalance_transientEnergyBalance_ads2( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + m_flow_fixed=-1e-5, + T_fixed=393.15, + redeclare package Medium = Media.IdealGases.CO2) + "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{-86,-14},{-66,6}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource + inlet_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + boundaryTypeStreamMassFractions=SorpLib.Choices.BoundaryFluidStreamMassFractions.MassFractions, + use_mFlowInput=true, + m_flow_fixed=-0.001, + use_TInput=true, + T_fixed=323.15, + X_fixed={0.6,0.1,0.1,0.2}, + redeclare package Medium = Medium) + "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{28,-10},{48,10}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource + outlet_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=1e-3, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{72,-10},{52,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource + inlet_phX_transientMassBalance_transientEnergyBalance_ads1( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + m_flow_fixed=-1e-6, + T_fixed=393.15, + redeclare package Medium = Media.IdealGases.N2) + "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{18,-12},{38,8}}))); + SorpLib.Basics.Sources.Fluids.GasSource + inlet_phX_transientMassBalance_transientEnergyBalance_ads2( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + m_flow_fixed=-1e-5, + T_fixed=393.15, + redeclare package Medium = Media.IdealGases.CO2) + "Inlet for Gas-mixture volume" + annotation (Placement(transformation(extent={{14,-14},{34,6}}))); + + // + // Definition of thermal boundaries + // + Modelica.Blocks.Sources.Sine input_Q_flow(amplitude=25, f=1/5) + "Input signal for heat flow rate" + annotation (Placement(transformation(extent={{-100,-40},{-80,-20}}))); + + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_transientMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + use_QFlowInput=true, + Q_flow_fixed=-25) + "Heat source for Gas-mixture volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-40,-12}))); + + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_transientMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + use_QFlowInput=true, + Q_flow_fixed=-25) + "Heat source for Gas-mixture volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={60,-12}))); + +equation + // + // Connections + // + connect(inlet_pTX_transientMassBalance_transientEnergyBalance.port, + gas_pTX_transientMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{-62,0},{-60,0},{-60,1.8},{-54.2,1.8}}, + color={244,125,35}, + thickness=1)); + connect(outlet_pTX_transientMassBalance_transientEnergyBalance.port, + gas_pTX_transientMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,0},{-40,0},{-40,1.8},{-42.2,1.8}}, + color={244,125,35}, + thickness=1)); + connect(inlet_phX_transientMassBalance_transientEnergyBalance.port, + gas_phX_transientMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,0},{40,0},{40,1.8},{45.8,1.8}}, + color={244,125,35}, + thickness=1)); + connect(outlet_phX_transientMassBalance_transientEnergyBalance.port, + gas_phX_transientMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,0},{60,0},{60,1.8},{57.8,1.8}}, + color={244,125,35}, + thickness=1)); + connect(inlet_pTX_transientMassBalance_transientEnergyBalance_ads1.port, + gas_pTX_transientMassBalance_transientEnergyBalance.fp_sorption[1]) + annotation (Line( + points={{-72,-2},{-70,-2},{-70,-10},{-51.6,-10},{-51.6,-7.8}}, + color={244,125,35}, + thickness=1)); + connect(inlet_pTX_transientMassBalance_transientEnergyBalance_ads2.port, + gas_pTX_transientMassBalance_transientEnergyBalance.fp_sorption[2]) + annotation (Line( + points={{-76,-4},{-74,-4},{-74,-12},{-51.6,-12},{-51.6,-7.4}}, + color={244,125,35}, + thickness=1)); + connect(inlet_phX_transientMassBalance_transientEnergyBalance_ads1.port, + gas_phX_transientMassBalance_transientEnergyBalance.fp_sorption[1]) + annotation (Line( + points={{28,-2},{30,-2},{30,-10},{48.4,-10},{48.4,-7.8}}, + color={244,125,35}, + thickness=1)); + connect(inlet_phX_transientMassBalance_transientEnergyBalance_ads2.port, + gas_phX_transientMassBalance_transientEnergyBalance.fp_sorption[2]) + annotation (Line( + points={{24,-4},{26,-4},{26,-12},{48.4,-12},{48.4,-7.4}}, + color={244,125,35}, + thickness=1)); + + connect(heatSource_pTX_transientMassBalance_transientEnergyBalance.port, + gas_pTX_transientMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{-40,-12},{-40,-8},{-50,-8},{-50,-6}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_transientMassBalance_transientEnergyBalance.port, + gas_phX_transientMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{60,-12},{60,-8},{50,-8},{50,-6}}, + color={238,46,47}, + thickness=1)); + + connect(input_Q_flow.y, + heatSource_pTX_transientMassBalance_transientEnergyBalance.Q_flow_input) + annotation (Line(points={{-79,-30},{-35,-30},{-35,-13}}, color={0,0,127})); + connect(input_Q_flow.y, + heatSource_phX_transientMassBalance_transientEnergyBalance.Q_flow_input) + annotation (Line(points={{-79,-30},{65,-30},{65,-13}}, color={0,0,127})); + connect(input_m_N2_flow.y, + inlet_pTX_transientMassBalance_transientEnergyBalance_ads1.m_flow_input) + annotation (Line(points={{-79,70},{-73.2,70},{-73.2,0}}, color={0,0,127})); + connect(input_m_N2_flow.y, + inlet_phX_transientMassBalance_transientEnergyBalance_ads1.m_flow_input) + annotation (Line(points={{-79,70},{26.8,70},{26.8,0}}, color={0,0,127})); + connect(input_m_CO2_flow.y, + inlet_pTX_transientMassBalance_transientEnergyBalance_ads2.m_flow_input) + annotation (Line(points={{-79,30},{-77.2,30},{-77.2,-2}}, color={0,0,127})); + connect(input_m_CO2_flow.y, + inlet_phX_transientMassBalance_transientEnergyBalance_ads2.m_flow_input) + annotation (Line(points={{-79,30},{22.8,30},{22.8,-2}}, color={0,0,127})); + connect(input_m_flow.y, inlet_phX_transientMassBalance_transientEnergyBalance.m_flow_input) + annotation (Line(points={{79,20},{36.8,20},{36.8,2}}, color={0,0,127})); + connect(input_m_flow.y, inlet_pTX_transientMassBalance_transientEnergyBalance.m_flow_input) + annotation (Line(points={{79,20},{-63.2,20},{-63.2,2}}, color={0,0,127})); + connect(input_T.y, inlet_phX_transientMassBalance_transientEnergyBalance.T_input) + annotation (Line(points={{79,60},{34,60},{34,-2},{36.8,-2}}, color={0,0,127})); + connect(input_T.y, inlet_pTX_transientMassBalance_transientEnergyBalance.T_input) + annotation (Line(points={{79,60},{-66,60},{-66,-2},{-63.2,-2}}, color={0,0,127})); + // + // Annotations + // + annotation (experiment( + StopTime=25, + Tolerance=1e-06), Documentation(info="<html> +<p> +This model checks the gas-vapor-mixture volume model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 25 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 13, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasVaporMixtureVolume; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_GasVolume.mo b/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_GasVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..01d9bf430ba02c2b3970866d35790cd6cc552af6 --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_GasVolume.mo @@ -0,0 +1,429 @@ +within SorpLib.Basics.Volumes.FluidVolumes.Tester; +model Test_GasVolume "Tester for gas volume" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = SorpLib.Media.IdealGases.N2 + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium model of the ideal gas" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of gas models + // + SorpLib.Basics.Volumes.FluidVolumes.GasVolume + gas_pTX_transientMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + p_initial=1000, + T_initial=293.15, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "Gas volume with p, T, and X as independent states, transient mass + balance with fixed initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{-60,40},{-40,60}}))); + + SorpLib.Basics.Volumes.FluidVolumes.GasVolume + gas_pTX_steadyStateMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + T_initial=293.15, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Gas volume with p, T, and X as independent states, steady-state mass + balance with free initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + + SorpLib.Basics.Volumes.FluidVolumes.GasVolume + gas_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + T_initial=293.15, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Gas volume with p, T, and X as independent states, steady-state mass + balance with free initial values, and steady-state mass balance with free + initial values" + annotation (Placement(transformation(extent={{-60,-60},{-40,-40}}))); + + SorpLib.Basics.Volumes.FluidVolumes.GasVolume + gas_phX_transientMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + p_initial=1000, + h_initial=304300.38, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "Gas volume with p, h, and X as independent states, transient mass + balance with fixed initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{40,40},{60,60}}))); + + SorpLib.Basics.Volumes.FluidVolumes.GasVolume + gas_phX_steadyStateMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + h_initial=304300.38, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Gas volume with p, h, and X as independent states, steady-state mass + balance with free initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{40,-10},{60,10}}))); + + SorpLib.Basics.Volumes.FluidVolumes.GasVolume + gas_phX_steadyStateMassBalance_steadyStateEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + h_initial=360495.72, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + type_energyBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Gas volume with p, h, and X as independent states, steady-state mass + balance with free initial values, and steady-state mass balance with free + initial values" + annotation (Placement(transformation(extent={{40,-60},{60,-40}}))); + + // + // Definition of fluid boundaries + // +protected + SorpLib.Basics.Sources.Fluids.GasSource + inlet_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) "Inlet for gas volume" + annotation (Placement(transformation(extent={{-72,40},{-52,60}}))); + SorpLib.Basics.Sources.Fluids.GasSource + outlet_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=1e-3, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for gas volume" + annotation (Placement(transformation(extent={{-28,40},{-48,60}}))); + Sources.Fluids.GasSource sorption_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.00001, + T_fixed=423.15, + redeclare package Medium = Medium) "Sorption inlet for gas volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-60,38}))); + + SorpLib.Basics.Sources.Fluids.GasSource + inlet_pTX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for gas volume" + annotation (Placement(transformation(extent={{-72,-10},{-52,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource + outlet_pTX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=10000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for gas volume" + annotation (Placement(transformation(extent={{-28,-10},{-48,10}}))); + + SorpLib.Basics.Sources.Fluids.GasSource + inlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for gas volume" + annotation (Placement(transformation(extent={{-72,-60},{-52,-40}}))); + SorpLib.Basics.Sources.Fluids.GasSource + outlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=10000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for gas volume" + annotation (Placement(transformation(extent={{-28,-60},{-48,-40}}))); + + SorpLib.Basics.Sources.Fluids.GasSource + inlet_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for gas volume" + annotation (Placement(transformation(extent={{28,40},{48,60}}))); + SorpLib.Basics.Sources.Fluids.GasSource + outlet_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for gas volume" + annotation (Placement(transformation(extent={{72,40},{52,60}}))); + SorpLib.Basics.Sources.Fluids.GasSource + sorption_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.00001, + T_fixed=423.15, + redeclare package Medium = Medium) + "Sorption inlet for gas volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={40,38}))); + + SorpLib.Basics.Sources.Fluids.GasSource + inlet_phX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for gas volume" + annotation (Placement(transformation(extent={{28,-10},{48,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource + outlet_phX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=10000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for gas volume" + annotation (Placement(transformation(extent={{72,-10},{52,10}}))); + + SorpLib.Basics.Sources.Fluids.GasSource + inlet_phX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for gas volume" + annotation (Placement(transformation(extent={{28,-60},{48,-40}}))); + SorpLib.Basics.Sources.Fluids.GasSource + outlet_phX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=10000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for gas volume" + annotation (Placement(transformation(extent={{72,-60},{52,-40}}))); + + // + // Definition of thermal boundaries + // + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_transientMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for gas volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-40,38}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_steadyStateMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for gas volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-40,-12}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for gas volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-40,-62}))); + + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_transientMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for gas volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={60,38}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_steadyStateMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for gas volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={60,-12}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for gas volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={60,-62}))); + +equation + // + // Connections + // + connect(inlet_pTX_transientMassBalance_transientEnergyBalance.port, + gas_pTX_transientMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{-62,50},{-60,50},{-60,51.8},{-54.2,51.8}}, + color={244,125,35}, + thickness=1)); + connect(outlet_pTX_transientMassBalance_transientEnergyBalance.port, + gas_pTX_transientMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,50},{-40,50},{-40,51.8},{-42.2,51.8}}, + color={244,125,35}, + thickness=1)); + connect(gas_pTX_steadyStateMassBalance_transientEnergyBalance.cfp_xMinus[1], + inlet_pTX_steadyStateMassBalance_transientEnergyBalance.port) annotation ( + Line( + points={{-54.2,1.8},{-60,1.8},{-60,0},{-62,0}}, + color={244,125,35}, + thickness=1)); + connect(outlet_pTX_steadyStateMassBalance_transientEnergyBalance.port, + gas_pTX_steadyStateMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,0},{-40,0},{-40,1.8},{-42.2,1.8}}, + color={244,125,35}, + thickness=1)); + connect(gas_pTX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xMinus[1], + inlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance.port) annotation ( + Line( + points={{-54.2,-48.2},{-60,-48.2},{-60,-50},{-62,-50}}, + color={244,125,35}, + thickness=1)); + connect(outlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance.port, + gas_pTX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,-50},{-40,-50},{-40,-48.2},{-42.2,-48.2}}, + color={244,125,35}, + thickness=1)); + connect(inlet_phX_transientMassBalance_transientEnergyBalance.port, + gas_phX_transientMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,50},{40,50},{40,51.8},{45.8,51.8}}, + color={244,125,35}, + thickness=1)); + connect(outlet_phX_transientMassBalance_transientEnergyBalance.port, + gas_phX_transientMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,50},{60,50},{60,51.8},{57.8,51.8}}, + color={244,125,35}, + thickness=1)); + connect(inlet_phX_steadyStateMassBalance_transientEnergyBalance.port, + gas_phX_steadyStateMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,0},{40,0},{40,1.8},{45.8,1.8}}, + color={244,125,35}, + thickness=1)); + connect(outlet_phX_steadyStateMassBalance_transientEnergyBalance.port, + gas_phX_steadyStateMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,0},{60,0},{60,1.8},{57.8,1.8}}, + color={244,125,35}, + thickness=1)); + connect(inlet_phX_steadyStateMassBalance_steadyStateEnergyBalance.port, + gas_phX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,-50},{40,-50},{40,-48.2},{45.8,-48.2}}, + color={244,125,35}, + thickness=1)); + connect(outlet_phX_steadyStateMassBalance_steadyStateEnergyBalance.port, + gas_phX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,-50},{60,-50},{60,-48.2},{57.8,-48.2}}, + color={244,125,35}, + thickness=1)); + connect(sorption_pTX_transientMassBalance_transientEnergyBalance.port, + gas_pTX_transientMassBalance_transientEnergyBalance.fp_sorption) + annotation (Line( + points={{-60,38},{-60,42.4},{-51.6,42.4}}, + color={244,125,35}, + thickness=1)); + connect(sorption_phX_transientMassBalance_transientEnergyBalance.port, + gas_phX_transientMassBalance_transientEnergyBalance.fp_sorption) + annotation (Line( + points={{40,38},{40,42.4},{48.4,42.4}}, + color={244,125,35}, + thickness=1)); + + connect(heatSource_pTX_transientMassBalance_transientEnergyBalance.port, + gas_pTX_transientMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{-40,38},{-40,42},{-50,42},{-50,44}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_pTX_steadyStateMassBalance_transientEnergyBalance.port, + gas_pTX_steadyStateMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{-40,-12},{-40,-8},{-50,-8},{-50,-6}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_pTX_steadyStateMassBalance_steadyStateEnergyBalance.port, + gas_pTX_steadyStateMassBalance_steadyStateEnergyBalance.hp_yMinus) + annotation (Line( + points={{-40,-62},{-40,-58},{-50,-58},{-50,-56}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_steadyStateMassBalance_steadyStateEnergyBalance.port, + gas_phX_steadyStateMassBalance_steadyStateEnergyBalance.hp_yMinus) + annotation (Line( + points={{60,-62},{60,-58},{50,-58},{50,-56}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_steadyStateMassBalance_transientEnergyBalance.port, + gas_phX_steadyStateMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{60,-12},{60,-8},{50,-8},{50,-6}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_transientMassBalance_transientEnergyBalance.port, + gas_phX_transientMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{60,38},{60,42},{50,42},{50,44}}, + color={238,46,47}, + thickness=1)); + + // + // Annotations + // + annotation (experiment(StopTime=25), Documentation(info="<html> +<p> +This model checks the gas volume model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 25 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 11, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasVolume; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_LiquidVolume.mo b/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_LiquidVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..bba85fa4f147dfc9213f5eb04d70cb9b37cebf2e --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_LiquidVolume.mo @@ -0,0 +1,769 @@ +within SorpLib.Basics.Volumes.FluidVolumes.Tester; +model Test_LiquidVolume "Tester for liquid volume" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of liquid models + // + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_pTX_transientMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + T_initial=293.15, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "Liquid volume with p, T, and X as independent states, transient mass + balance with fixed initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{-60,70},{-40,90}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_pTX_steadyStateMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + T_initial=293.15, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Liquid volume with p, T, and X as independent states, steady-state mass + balance with free initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{-60,40},{-40,60}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + T_initial=293.15, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Liquid volume with p, T, and X as independent states, steady-state mass + balance with free initial values, and steady-state mass balance with free + initial values" + annotation (Placement(transformation(extent={{-60,10},{-40,30}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_pTX_transientMassBalance_transientEnergyBalance_woVp( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + T_initial=293.15, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + neglectTermVp=true, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "Liquid volume with p, T, and X as independent states, transient mass + balance with fixed initial values, transient mass balance with fixed + initial values, and assumption that u = h" + annotation (Placement(transformation(extent={{-62,-30},{-42,-10}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_pTX_steadyStateMassBalance_transientEnergyBalance_woVp( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + T_initial=293.15, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + neglectTermVp=true, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Liquid volume with p, T, and X as independent states, steady-state mass + balance with free initial values, transient mass balance with fixed + initial values, and assumption that u = h" + annotation (Placement(transformation(extent={{-62,-60},{-42,-40}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_pTX_steadyStateMassBalance_steadyStateEnergyBalance_woVp( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + T_initial=293.15, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + neglectTermVp=true, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Liquid volume with p, T, and X as independent states, steady-state mass + balance with free initial values, steady-state mass balance with free + initial values, and assumption that u = h" + annotation (Placement(transformation(extent={{-62,-90},{-42,-70}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_phX_transientMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + h_initial=84011.8, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "Liquid volume with p, h, and X as independent states, transient mass + balance with fixed initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{40,70},{60,90}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_phX_steadyStateMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + h_initial=84011.8, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Liquid volume with p, h, and X as independent states, steady-state mass + balance with free initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{40,40},{60,60}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_phX_steadyStateMassBalance_steadyStateEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + h_initial=84011.8, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + type_energyBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Liquid volume with p, h, and X as independent states, steady-state mass + balance with free initial values, and steady-state mass balance with free + initial values" + annotation (Placement(transformation(extent={{40,10},{60,30}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_phX_transientMassBalance_transientEnergyBalance_woVp( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + h_initial=84011.8, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + neglectTermVp=true, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "Liquid volume with p, T, and X as independent states, transient mass + balance with fixed initial values, transient mass balance with fixed + initial values, and assumption that u = h" + annotation (Placement(transformation(extent={{40,-30},{60,-10}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_phX_steadyStateMassBalance_transientEnergyBalance_woVp( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + h_initial=84011.8, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + neglectTermVp=true, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Liquid volume with p, T, and X as independent states, steady-state mass + balance with free initial values, transient mass balance with fixed + initial values, and assumption that u = h" + annotation (Placement(transformation(extent={{40,-60},{60,-40}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume + liquid_phX_steadyStateMassBalance_steadyStateEnergyBalance_woVp( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + h_initial=84011.8, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + neglectTermVp=true, + type_energyBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "Liquid volume with p, T, and X as independent states, steady-state mass + balance with free initial values, steady-state mass balance with free + initial values, and assumption that u = h" + annotation (Placement(transformation(extent={{40,-90},{60,-70}}))); + + // + // Definition of fluid boundaries + // +protected + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{-72,70},{-52,90}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{-28,70},{-48,90}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_pTX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{-72,40},{-52,60}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_pTX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=1e5, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{-28,40},{-48,60}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{-72,10},{-52,30}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=1e5, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{-28,10},{-48,30}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_pTX_transientMassBalance_transientEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{-74,-30},{-54,-10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_pTX_transientMassBalance_transientEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{-30,-30},{-50,-10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_pTX_steadyStateMassBalance_transientEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{-74,-60},{-54,-40}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_pTX_steadyStateMassBalance_transientEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=100000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{-30,-60},{-50,-40}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{-74,-90},{-54,-70}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=100000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{-30,-90},{-50,-70}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{28,70},{48,90}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{72,70},{52,90}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_phX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{28,40},{48,60}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_phX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=1e5, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{72,40},{52,60}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_phX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{28,10},{48,30}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_phX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=1e5, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{72,10},{52,30}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_phX_transientMassBalance_transientEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{28,-30},{48,-10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_phX_transientMassBalance_transientEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{72,-30},{52,-10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_phX_steadyStateMassBalance_transientEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{28,-60},{48,-40}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_phX_steadyStateMassBalance_transientEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=100000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{72,-60},{52,-40}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource + inlet_phX_steadyStateMassBalance_steadyStateEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for liquid volume" + annotation (Placement(transformation(extent={{28,-90},{48,-70}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource + outlet_phX_steadyStateMassBalance_steadyStateEnergyBalance_woVp( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=100000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for liquid volume" + annotation (Placement(transformation(extent={{72,-90},{52,-70}}))); + + // + // Definition of thermal boundaries + // + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_transientMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-50,68}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_steadyStateMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-50,38}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-50,8}))); + + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_transientMassBalance_transientEnergyBalance_woVp( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-52,-32}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_steadyStateMassBalance_transientEnergyBalance_woVp( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-52,-62}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_steadyStateMassBalance_steadyStateEnergyBalance_woVp( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-52,-92}))); + + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_transientMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={50,68}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_steadyStateMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={50,38}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={50,8}))); + + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_transientMassBalance_transientEnergyBalance_woVp( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={50,-32}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_steadyStateMassBalance_transientEnergyBalance_woVp( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={50,-62}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_steadyStateMassBalance_steadyStateEnergyBalance_woVp( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for liquid volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={50,-92}))); + +equation + // + // Connections + // + connect(inlet_pTX_transientMassBalance_transientEnergyBalance.port, + liquid_pTX_transientMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{-62,80},{-60,80},{-60,81.8},{-54.2,81.8}}, + color={28,108,200}, + thickness=1)); + connect(outlet_pTX_transientMassBalance_transientEnergyBalance.port, + liquid_pTX_transientMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,80},{-40,80},{-40,81.8},{-42.2,81.8}}, + color={28,108,200}, + thickness=1)); + connect(liquid_pTX_steadyStateMassBalance_transientEnergyBalance.cfp_xMinus[1], + inlet_pTX_steadyStateMassBalance_transientEnergyBalance.port) annotation ( + Line( + points={{-54.2,51.8},{-60,51.8},{-60,50},{-62,50}}, + color={28,108,200}, + thickness=1)); + connect(outlet_pTX_steadyStateMassBalance_transientEnergyBalance.port, + liquid_pTX_steadyStateMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,50},{-40,50},{-40,51.8},{-42.2,51.8}}, + color={28,108,200}, + thickness=1)); + connect(liquid_pTX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xMinus[1], + inlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance.port) annotation ( + Line( + points={{-54.2,21.8},{-60,21.8},{-60,20},{-62,20}}, + color={28,108,200}, + thickness=1)); + connect(outlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance.port, + liquid_pTX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,20},{-40,20},{-40,21.8},{-42.2,21.8}}, + color={28,108,200}, + thickness=1)); + connect(inlet_pTX_transientMassBalance_transientEnergyBalance_woVp.port, + liquid_pTX_transientMassBalance_transientEnergyBalance_woVp.cfp_xMinus[1]) + annotation (Line( + points={{-64,-20},{-62,-20},{-62,-18.2},{-56.2,-18.2}}, + color={28,108,200}, + thickness=1)); + connect(outlet_pTX_transientMassBalance_transientEnergyBalance_woVp.port, + liquid_pTX_transientMassBalance_transientEnergyBalance_woVp.cfp_xPlus[1]) + annotation (Line( + points={{-40,-20},{-42,-20},{-42,-18.2},{-44.2,-18.2}}, + color={28,108,200}, + thickness=1)); + connect(liquid_pTX_steadyStateMassBalance_transientEnergyBalance_woVp.cfp_xMinus[1], + inlet_pTX_steadyStateMassBalance_transientEnergyBalance_woVp.port) + annotation (Line( + points={{-56.2,-48.2},{-62,-48.2},{-62,-50},{-64,-50}}, + color={28,108,200}, + thickness=1)); + connect(outlet_pTX_steadyStateMassBalance_transientEnergyBalance_woVp.port, + liquid_pTX_steadyStateMassBalance_transientEnergyBalance_woVp.cfp_xPlus[1]) + annotation (Line( + points={{-40,-50},{-42,-50},{-42,-48.2},{-44.2,-48.2}}, + color={28,108,200}, + thickness=1)); + connect(liquid_pTX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.cfp_xMinus[1], + inlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.port) + annotation (Line( + points={{-56.2,-78.2},{-62,-78.2},{-62,-80},{-64,-80}}, + color={28,108,200}, + thickness=1)); + connect(outlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.port, + liquid_pTX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.cfp_xPlus[1]) + annotation (Line( + points={{-40,-80},{-42,-80},{-42,-78.2},{-44.2,-78.2}}, + color={28,108,200}, + thickness=1)); + connect(inlet_phX_transientMassBalance_transientEnergyBalance.port, + liquid_phX_transientMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,80},{40,80},{40,81.8},{45.8,81.8}}, + color={28,108,200}, + thickness=1)); + connect(outlet_phX_transientMassBalance_transientEnergyBalance.port, + liquid_phX_transientMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,80},{60,80},{60,81.8},{57.8,81.8}}, + color={28,108,200}, + thickness=1)); + connect(inlet_phX_steadyStateMassBalance_transientEnergyBalance.port, + liquid_phX_steadyStateMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,50},{40,50},{40,51.8},{45.8,51.8}}, + color={28,108,200}, + thickness=1)); + connect(outlet_phX_steadyStateMassBalance_transientEnergyBalance.port, + liquid_phX_steadyStateMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,50},{60,50},{60,51.8},{57.8,51.8}}, + color={28,108,200}, + thickness=1)); + connect(inlet_phX_steadyStateMassBalance_steadyStateEnergyBalance.port, + liquid_phX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,20},{40,20},{40,21.8},{45.8,21.8}}, + color={28,108,200}, + thickness=1)); + connect(outlet_phX_steadyStateMassBalance_steadyStateEnergyBalance.port, + liquid_phX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,20},{60,20},{60,21.8},{57.8,21.8}}, + color={28,108,200}, + thickness=1)); + connect(inlet_phX_transientMassBalance_transientEnergyBalance_woVp.port, + liquid_phX_transientMassBalance_transientEnergyBalance_woVp.cfp_xMinus[1]) + annotation (Line( + points={{38,-20},{40,-20},{40,-18.2},{45.8,-18.2}}, + color={28,108,200}, + thickness=1)); + connect(outlet_phX_transientMassBalance_transientEnergyBalance_woVp.port, + liquid_phX_transientMassBalance_transientEnergyBalance_woVp.cfp_xPlus[1]) + annotation (Line( + points={{62,-20},{60,-20},{60,-18.2},{57.8,-18.2}}, + color={28,108,200}, + thickness=1)); + connect(inlet_phX_steadyStateMassBalance_transientEnergyBalance_woVp.port, + liquid_phX_steadyStateMassBalance_transientEnergyBalance_woVp.cfp_xMinus[1]) + annotation (Line( + points={{38,-50},{40,-50},{40,-48.2},{45.8,-48.2}}, + color={28,108,200}, + thickness=1)); + connect(outlet_phX_steadyStateMassBalance_transientEnergyBalance_woVp.port, + liquid_phX_steadyStateMassBalance_transientEnergyBalance_woVp.cfp_xPlus[1]) + annotation (Line( + points={{62,-50},{60,-50},{60,-48.2},{57.8,-48.2}}, + color={28,108,200}, + thickness=1)); + connect(inlet_phX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.port, + liquid_phX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.cfp_xMinus[1]) + annotation (Line( + points={{38,-80},{40,-80},{40,-78.2},{45.8,-78.2}}, + color={28,108,200}, + thickness=1)); + connect(outlet_phX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.port, + liquid_phX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.cfp_xPlus[1]) + annotation (Line( + points={{62,-80},{60,-80},{60,-78.2},{57.8,-78.2}}, + color={28,108,200}, + thickness=1)); + + connect(heatSource_pTX_transientMassBalance_transientEnergyBalance.port, + liquid_pTX_transientMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{-50,68},{-50,74}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_pTX_steadyStateMassBalance_transientEnergyBalance.port, + liquid_pTX_steadyStateMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{-50,38},{-50,38},{-50,44}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_pTX_steadyStateMassBalance_steadyStateEnergyBalance.port, + liquid_pTX_steadyStateMassBalance_steadyStateEnergyBalance.hp_yMinus) + annotation (Line( + points={{-50,8},{-50,14}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_pTX_transientMassBalance_transientEnergyBalance_woVp.port, + liquid_pTX_transientMassBalance_transientEnergyBalance_woVp.hp_yMinus) + annotation (Line( + points={{-52,-32},{-52,-26}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_pTX_steadyStateMassBalance_transientEnergyBalance_woVp.port, + liquid_pTX_steadyStateMassBalance_transientEnergyBalance_woVp.hp_yMinus) + annotation (Line( + points={{-52,-62},{-52,-56}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_pTX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.port, + liquid_pTX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.hp_yMinus) + annotation (Line( + points={{-52,-92},{-52,-86}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_steadyStateMassBalance_steadyStateEnergyBalance.port, + liquid_phX_steadyStateMassBalance_steadyStateEnergyBalance.hp_yMinus) + annotation (Line( + points={{50,8},{50,14}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_steadyStateMassBalance_transientEnergyBalance.port, + liquid_phX_steadyStateMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{50,38},{50,44}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_transientMassBalance_transientEnergyBalance.port, + liquid_phX_transientMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{50,68},{50,74},{50,74}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_transientMassBalance_transientEnergyBalance_woVp.port, + liquid_phX_transientMassBalance_transientEnergyBalance_woVp.hp_yMinus) + annotation (Line( + points={{50,-32},{50,-26},{50,-26}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_steadyStateMassBalance_transientEnergyBalance_woVp.port, + liquid_phX_steadyStateMassBalance_transientEnergyBalance_woVp.hp_yMinus) + annotation (Line( + points={{50,-62},{50,-56}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.port, + liquid_phX_steadyStateMassBalance_steadyStateEnergyBalance_woVp.hp_yMinus) + annotation (Line( + points={{50,-92},{50,-86}}, + color={238,46,47}, + thickness=1)); + + // + // Annotations + // + annotation (experiment(StopTime=25), Documentation(info="<html> +<p> +This model checks the liquid volume model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 25 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 7, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_LiquidVolume; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_VLEVolume.mo b/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_VLEVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..68e04fa63285d217cf105fd055a91edca0a37a5e --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/Tester/Test_VLEVolume.mo @@ -0,0 +1,431 @@ +within SorpLib.Basics.Volumes.FluidVolumes.Tester; +model Test_VLEVolume "Tester for VLE volume" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the VLE liquid" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of VLE models + // + SorpLib.Basics.Volumes.FluidVolumes.VLEVolume + vle_pTX_transientMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + p_initial=1000, + T_initial=293.15, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "VLE volume with p, T, and X as independent states, transient mass + balance with fixed initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{-60,40},{-40,60}}))); + + SorpLib.Basics.Volumes.FluidVolumes.VLEVolume + vle_pTX_steadyStateMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + T_initial=293.15, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "VLE volume with p, T, and X as independent states, steady-state mass + balance with free initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + + SorpLib.Basics.Volumes.FluidVolumes.VLEVolume + vle_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + T_initial=293.15, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + type_energyBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "VLE volume with p, T, and X as independent states, steady-state mass + balance with free initial values, and steady-state mass balance with free + initial values" + annotation (Placement(transformation(extent={{-60,-60},{-40,-40}}))); + + SorpLib.Basics.Volumes.FluidVolumes.VLEVolume + vle_phX_transientMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + p_initial=1000, + h_initial=2538185.5, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium) "VLE volume with p, h, and X as independent states, transient mass + balance with fixed initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{40,40},{60,60}}))); + + SorpLib.Basics.Volumes.FluidVolumes.VLEVolume + vle_phX_steadyStateMassBalance_transientEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + h_initial=83927.11, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "VLE volume with p, h, and X as independent states, steady-state mass + balance with free initial values, and transient mass balance with fixed + initial values" + annotation (Placement(transformation(extent={{40,-10},{60,10}}))); + + SorpLib.Basics.Volumes.FluidVolumes.VLEVolume + vle_phX_steadyStateMassBalance_steadyStateEnergyBalance( + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + h_initial=2616993.5, + type_energyBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium) "VLE volume with p, h, and X as independent states, steady-state mass + balance with free initial values, and steady-state mass balance with free + initial values" + annotation (Placement(transformation(extent={{40,-60},{60,-40}}))); + + // + // Definition of fluid boundaries + // +protected + SorpLib.Basics.Sources.Fluids.VLESource + inlet_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) "Inlet for VLE volume" + annotation (Placement(transformation(extent={{-72,40},{-52,60}}))); + SorpLib.Basics.Sources.Fluids.VLESource + outlet_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=1e-3, + T_fixed=323.15, + redeclare package Medium = Medium) "Outlet for VLE volume" + annotation (Placement(transformation(extent={{-28,40},{-48,60}}))); + Sources.Fluids.VLESource sorption_pTX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.000001, + T_fixed=423.15, + redeclare package Medium = Medium) "Sorption inlet for VLE volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-60,38}))); + + SorpLib.Basics.Sources.Fluids.VLESource + inlet_pTX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for VLE volume" + annotation (Placement(transformation(extent={{-72,-10},{-52,10}}))); + SorpLib.Basics.Sources.Fluids.VLESource + outlet_pTX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=10000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for VLE volume" + annotation (Placement(transformation(extent={{-28,-10},{-48,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource + inlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for VLE volume" + annotation (Placement(transformation(extent={{-72,-60},{-52,-40}}))); + SorpLib.Basics.Sources.Fluids.VLESource + outlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=10000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for VLE volume" + annotation (Placement(transformation(extent={{-28,-60},{-48,-40}}))); + + SorpLib.Basics.Sources.Fluids.VLESource + inlet_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for VLE volume" + annotation (Placement(transformation(extent={{28,40},{48,60}}))); + SorpLib.Basics.Sources.Fluids.VLESource + outlet_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for VLE volume" + annotation (Placement(transformation(extent={{72,40},{52,60}}))); + SorpLib.Basics.Sources.Fluids.VLESource + sorption_phX_transientMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.000001, + T_fixed=423.15, + redeclare package Medium = Medium) + "Sorption inlet for VLE volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={40,38}))); + + SorpLib.Basics.Sources.Fluids.VLESource + inlet_phX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for VLE volume" + annotation (Placement(transformation(extent={{28,-10},{48,10}}))); + SorpLib.Basics.Sources.Fluids.VLESource + outlet_phX_steadyStateMassBalance_transientEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=10000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for VLE volume" + annotation (Placement(transformation(extent={{72,-10},{52,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource + inlet_phX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + m_flow_fixed=-0.001, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet for VLE volume" + annotation (Placement(transformation(extent={{28,-60},{48,-40}}))); + SorpLib.Basics.Sources.Fluids.VLESource + outlet_phX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=10000, + T_fixed=323.15, + redeclare package Medium = Medium) + "Outlet for VLE volume" + annotation (Placement(transformation(extent={{72,-60},{52,-40}}))); + + // + // Definition of thermal boundaries + // + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_transientMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) "Heat source for VLE volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-40,38}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_steadyStateMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for VLE volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-40,-12}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_pTX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for VLE volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={-40,-62}))); + + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_transientMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for VLE volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={60,38}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_steadyStateMassBalance_transientEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for VLE volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={60,-12}))); + SorpLib.Basics.Sources.Thermal.HeatSource + heatSource_phX_steadyStateMassBalance_steadyStateEnergyBalance( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + Q_flow_fixed=-25) + "Heat source for VLE volume" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, rotation=90, + origin={60,-62}))); + +equation + // + // Connections + // + connect(inlet_pTX_transientMassBalance_transientEnergyBalance.port, + vle_pTX_transientMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{-62,50},{-60,50},{-60,51.8},{-54.2,51.8}}, + color={0,140,72}, + thickness=1)); + connect(outlet_pTX_transientMassBalance_transientEnergyBalance.port, + vle_pTX_transientMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,50},{-40,50},{-40,51.8},{-42.2,51.8}}, + color={0,140,72}, + thickness=1)); + connect(vle_pTX_steadyStateMassBalance_transientEnergyBalance.cfp_xMinus[1], + inlet_pTX_steadyStateMassBalance_transientEnergyBalance.port) annotation ( + Line( + points={{-54.2,1.8},{-60,1.8},{-60,0},{-62,0}}, + color={0,140,72}, + thickness=1)); + connect(outlet_pTX_steadyStateMassBalance_transientEnergyBalance.port, + vle_pTX_steadyStateMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,0},{-40,0},{-40,1.8},{-42.2,1.8}}, + color={0,140,72}, + thickness=1)); + connect(vle_pTX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xMinus[1], + inlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance.port) annotation ( + Line( + points={{-54.2,-48.2},{-60,-48.2},{-60,-50},{-62,-50}}, + color={0,140,72}, + thickness=1)); + connect(outlet_pTX_steadyStateMassBalance_steadyStateEnergyBalance.port, + vle_pTX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{-38,-50},{-40,-50},{-40,-48.2},{-42.2,-48.2}}, + color={0,140,72}, + thickness=1)); + connect(inlet_phX_transientMassBalance_transientEnergyBalance.port, + vle_phX_transientMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,50},{40,50},{40,51.8},{45.8,51.8}}, + color={0,140,72}, + thickness=1)); + connect(outlet_phX_transientMassBalance_transientEnergyBalance.port, + vle_phX_transientMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,50},{60,50},{60,51.8},{57.8,51.8}}, + color={0,140,72}, + thickness=1)); + connect(inlet_phX_steadyStateMassBalance_transientEnergyBalance.port, + vle_phX_steadyStateMassBalance_transientEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,0},{40,0},{40,1.8},{45.8,1.8}}, + color={0,140,72}, + thickness=1)); + connect(outlet_phX_steadyStateMassBalance_transientEnergyBalance.port, + vle_phX_steadyStateMassBalance_transientEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,0},{60,0},{60,1.8},{57.8,1.8}}, + color={0,140,72}, + thickness=1)); + connect(inlet_phX_steadyStateMassBalance_steadyStateEnergyBalance.port, + vle_phX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xMinus[1]) + annotation (Line( + points={{38,-50},{40,-50},{40,-48.2},{45.8,-48.2}}, + color={0,140,72}, + thickness=1)); + connect(outlet_phX_steadyStateMassBalance_steadyStateEnergyBalance.port, + vle_phX_steadyStateMassBalance_steadyStateEnergyBalance.cfp_xPlus[1]) + annotation (Line( + points={{62,-50},{60,-50},{60,-48.2},{57.8,-48.2}}, + color={0,140,72}, + thickness=1)); + connect(sorption_pTX_transientMassBalance_transientEnergyBalance.port, + vle_pTX_transientMassBalance_transientEnergyBalance.fp_sorption) + annotation (Line( + points={{-60,38},{-60,42.4},{-51.6,42.4}}, + color={0,140,72}, + thickness=1)); + connect(sorption_phX_transientMassBalance_transientEnergyBalance.port, + vle_phX_transientMassBalance_transientEnergyBalance.fp_sorption) + annotation (Line( + points={{40,38},{40,42.4},{48.4,42.4}}, + color={0,140,72}, + thickness=1)); + + connect(heatSource_pTX_transientMassBalance_transientEnergyBalance.port, + vle_pTX_transientMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{-40,38},{-40,42},{-50,42},{-50,44}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_pTX_steadyStateMassBalance_transientEnergyBalance.port, + vle_pTX_steadyStateMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{-40,-12},{-40,-8},{-50,-8},{-50,-6}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_pTX_steadyStateMassBalance_steadyStateEnergyBalance.port, + vle_pTX_steadyStateMassBalance_steadyStateEnergyBalance.hp_yMinus) + annotation (Line( + points={{-40,-62},{-40,-58},{-50,-58},{-50,-56}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_steadyStateMassBalance_steadyStateEnergyBalance.port, + vle_phX_steadyStateMassBalance_steadyStateEnergyBalance.hp_yMinus) + annotation (Line( + points={{60,-62},{60,-58},{50,-58},{50,-56}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_steadyStateMassBalance_transientEnergyBalance.port, + vle_phX_steadyStateMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{60,-12},{60,-8},{50,-8},{50,-6}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_phX_transientMassBalance_transientEnergyBalance.port, + vle_phX_transientMassBalance_transientEnergyBalance.hp_yMinus) + annotation (Line( + points={{60,38},{60,42},{50,42},{50,44}}, + color={238,46,47}, + thickness=1)); + + // + // Annotations + // + annotation (experiment(StopTime=25), Documentation(info="<html> +<p> +This model checks the VLE volume model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 25 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 8, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_VLEVolume; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/Tester/package.mo b/SorpLib/Basics/Volumes/FluidVolumes/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..3f3637c5051de63da2c732d1f8dc5e0a0ffc2092 --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/Tester/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Basics.Volumes.FluidVolumes; +package Tester "Models to test and varify models of fluid volumes" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented fluid volumes. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/Tester/package.order b/SorpLib/Basics/Volumes/FluidVolumes/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..3722cdad08088c2eaec3fc965de79820ef10f190 --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/Tester/package.order @@ -0,0 +1,5 @@ +Test_LiquidVolume +Test_GasVolume +Test_GasMixtureVolume +Test_GasVaporMixtureVolume +Test_VLEVolume diff --git a/SorpLib/Basics/Volumes/FluidVolumes/VLEVolume.mo b/SorpLib/Basics/Volumes/FluidVolumes/VLEVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..c4e375b96198b6a12bee563df9e89de05d138646 --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/VLEVolume.mo @@ -0,0 +1,444 @@ +within SorpLib.Basics.Volumes.FluidVolumes; +model VLEVolume + "Homogenous volume of a real fluid (i.e., with a two-phase regime)" + extends SorpLib.Basics.Volumes.BaseClasses.PartialFluidVolume( + final no_components = Medium.nX, + final pressureNoStateVariable = Medium.singleState, + final neglectTermVp = false, + redeclare final connector FluidPortsIn = + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_in, + redeclare final connector FluidPortsOut = + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_out, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + useHeatPorts=true, + useHeatPortsY=true, + h_initial= + Medium.specificEnthalpy_pTX(p=p_initial, T=T_initial, X=Medium.reference_X), + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with a two-phase regime)" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.MassFlowRate ms_flow_initial = 1e-4 + "Start value for sorption mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of ports + // + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_sorption + "Sorption heat port" + annotation (Placement(transformation(extent={{10,-50},{22,-38}}), + iconTransformation(extent={{10,-50},{22,-38}}))); + + FluidPortsIn fp_sorption( + final no_components=no_components, + m_flow(start=ms_flow_initial)) + "Sorption fluid port" + annotation (Placement(transformation(extent={{-20,-80},{-12,-72}}), + iconTransformation(extent={{-20,-80},{-12,-72}}))); + + // + // Definition of variables + // + Modelica.Units.SI.MassFlowRate ms_flow + "Sum of all sorption mass flow rates across boundaries"; + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + +equation + // + // Assertations + // + assert(no_components <= 1, + "The VLE volume model can only handel pure fluids (i.e., with one component)!", + level = AssertionLevel.error); + + assert(pressureNoStateVariable or not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + // + // Calculation of properties + // + if independentStateVariables == + SorpLib.Choices.IndependentVariablesVolume.pTX then + state = Medium.setState_pTX(p=p, T=T, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + else + state = Medium.setState_phX(p=p, h=h, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + T = Medium.temperature(state=state) + "Temperature"; + + end if; + + v = 1 / rho + "Specific volume"; + rho = Medium.density(state=state) + "Density"; + + // + // Momentum balance + // + fp_sorption.p = p + "Total pressure at the port (i.e., homogenous volume)"; + + // + // Mass balance + // + dm_dtau = mc_flow + ms_flow + "Overall mass balance"; + + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dm_dtau = geometry.V * rho * + (fluidProperties.kappa *der(p) - fluidProperties.beta * der(T)) + "Transient overall mass balance"; + + else + dm_dtau = geometry.V * rho * ((fluidProperties.kappa - + fluidProperties.beta * fluidProperties.my) * der(p) - + fluidProperties.beta / fluidProperties.cp * der(h)) + "Transient overall mass balance"; + + end if; + end if; + + mc_flow = sum(cfp_xMinus.m_flow) + sum(cfp_xPlus.m_flow) + "Sum of all convective mass flow rates across boundaries"; + ms_flow = fp_sorption.m_flow + "Sum of all sorption mass flow rates across boundaries"; + + // + // Energy balance + // + dU_dtau = Hb_flow + Qb_flow + "Energy balane"; + + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dU_dtau = u * dm_dtau + m * ( + v * (p * fluidProperties.kappa - T * fluidProperties.beta) * der(p) + + (fluidProperties.cp - p * v * fluidProperties.beta) * der(T)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + (1 - p * v * fluidProperties.beta / fluidProperties.cp) * der(h) + + v * (p * (fluidProperties.kappa - fluidProperties.beta * + fluidProperties.my) - 1) * der(p)) + "Transient energy balance"; + + end if; + end if; + + if avoid_events then + Hb_flow = + sum(cfp_xMinus.m_flow .* noEvent(actualStream(cfp_xMinus.h_outflow))) + + sum(cfp_xPlus.m_flow .* noEvent(actualStream(cfp_xPlus.h_outflow))) + + fp_sorption.m_flow * noEvent(actualStream(fp_sorption.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + sum(cfp_xMinus.m_flow .* actualStream(cfp_xMinus.h_outflow)) + + sum(cfp_xPlus.m_flow .* actualStream(cfp_xPlus.h_outflow)) + + fp_sorption.m_flow * actualStream(fp_sorption.h_outflow) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + + Qb_flow = Q_flow_xMinus + Q_flow_xPlus + + Q_flow_yMinus + Q_flow_yPlus + + Q_flow_zMinus + Q_flow_zPlus + + hp_sorption.Q_flow + "Sum of all heat flow rates across boundaries"; + + fp_sorption.h_outflow = h + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + + hp_sorption.T = T + "Temperature at sorption heat port"; + + // + // Summary record + // + fluidProperties.cp = if (calculateAdditionalProperties or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + fluidProperties.lambda = if calculateAdditionalProperties then + Medium.thermalConductivity(state=state) else 0 + "Thermal conductivity"; + fluidProperties.eta = if calculateAdditionalProperties then + Medium.dynamicViscosity(state=state) else 0 + "Dynamic viscosity"; + + fluidProperties.beta = if (calculateAdditionalProperties or + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + fluidProperties.kappa = if (calculateAdditionalProperties or + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + fluidProperties.my = if (calculateAdditionalProperties or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)))) then + v / fluidProperties.cp * (fluidProperties.beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + fluidProperties.Pr = if calculateAdditionalProperties then + fluidProperties.eta * fluidProperties.cp / fluidProperties.lambda else 0 + "Prandtl number"; + + fluidProperties.m_flow_sorption = ms_flow + "Total mass flow rate at port 'sorption'"; + + fluidProperties.mc_flow_yMinus = 0 + "Convective mass flow rate at port '-dy/2'"; + fluidProperties.mc_flow_yPlus = 0 + "Convective mass flow rate at port '+dy/2'"; + fluidProperties.mc_flow_zMinus = 0 + "Convective mass flow rate at port '-dz/2'"; + fluidProperties.mc_flow_zPlus = 0 + "Convective mass flow rate at port '+dz/2'"; + + fluidProperties.md_flow_xMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dx/2'"; + fluidProperties.md_flow_xPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dx/2'"; + fluidProperties.md_flow_yMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dy/2'"; + fluidProperties.md_flow_yPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dy/2'"; + fluidProperties.md_flow_zMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dz/2'"; + fluidProperties.md_flow_zPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a VLE volume, applying a lumped modeling approach. Depending +on the volume setup, this model may have up to seven heat ports (i.e., two for each +spatial direction of a cartesian coordinate system and one for a adsorbate volume). +Furthermore, this model has convective fluid ports in y-direction, following the +'connectorSizing' principle, and a sorption fluid port. These ports allow for the +combination of several fluid volumes to create a spatially distributed model. +</p> + +<h4>Main equations</h4> +<p> +The most important equations are the momentum, mass, and energy balance. According to +the staggered grid approach, the momentum balance is not solved within the volume but +at the volume's boundaries via so-called +<a href=\"Modelica://SorpLib.Components.Fittings\">flow models</a>. Hennce, no pressure +losses occur within the volume: +</p> +<pre> + p = cfp_xMinus.p; +</pre> +<pre> + p = cfp_xPlus.p; +</pre> +<pre> + p = fp_sorption.p; +</pre> + +<p> +Regarding the mass and energy balances, either steady-state or tansient balnaces +can be selected. When using the pressure <i>p</i> and temperature <i>T</i> as +independent states, the mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = V * ρ * [κ * (dp/dτ) - β * (dT/dτ)] = ∑ m<sub>c,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [v * (p * κ - T * β) * (dp/dτ) + (c<sub>p</sub> - p * v * β) * (dT/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +When using the pressure <i>p</i> and specific enthalpy <i>h</i> as independent +states, the mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = V * ρ * [(κ - β * μ) * (dp/dτ) - β / c<sub>p</sub> * (dh/dτ)] = ∑ m<sub>c,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [v * (p * (κ - β * μ) - 1) * (dp/dτ) + (1 - p * v * β / c<sub>p</sub>) * (dh/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +Herein, <i>(dm/dτ)</i> is the derivative of the mass w.r.t. time, <i>(dU/dτ)</i> +is the derivative of the internal energy w.r.t. time, <i>(dρ/dτ)</i> is the +derivative of the density w.r.t. time, <i>(du/dτ)</i> is the derivative of the specific +internal energy w.r.t.time, <i>(dp/dτ)</i> is the derivative of the pressure w.r.t. +time, <i>(dT/dτ)</i> is the derivative of the temperature w.r.t. time, <i>(dh/dτ)</i> +is the derivative of the specific enthalpy w.r.t. time, <i>V</i> is the volume, <i>m</i> is +the mass, <i>v</i> is the specific volume, <i>ρ</i> is the density, <i>κ</i> is +the isothermal compressibility, <i>β</i> is the isobaric expansion coefficient, <i>μ</i> +is the Joule-Thomson coefficient, <i>c<sub>p</sub></i> is the specific heat capacity at +constant pressure,<i>m<sub>c,flow</sub></i> is the sum of the convective mass flow rates, +<i>H<sub>b,flow</sub></i> is the sum of the enthalpy flow rates, and <i>Q<sub>b,flow</sub></i> +is the sum of the heat flow rates. +</p> + + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to model the adsorptive at vapor phase within +adsorber modules. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useHeatPorts</i>: + Defines if heat ports in the spatial direction <i>i</i> are required. + </li> + <li> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <li> + <i>calculateAdditionalProperties</i>: + Defines if additional properties like transport properties shall be calculated. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has two dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i> and temperature <i>T</i>, or + </li> + <li> + pressure <i>p</i> and specific enthalpy <i>h</i> (recommended). + </li> +</ul> +<p> +Note that this model does not have the pressure <i>p</i> as dynamic state if the +fluid property model is a single state model. +</p> +</html>", revisions="<html> +<ul> + <li> + December 8, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end VLEVolume; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/package.mo b/SorpLib/Basics/Volumes/FluidVolumes/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..6fb9c620268178729fbeabe77251c61492636ad8 --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Basics.Volumes; +package FluidVolumes "Package containing finte volume models of fluids" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains finite volume models of fluids. This package calculates +fluid properties based on the open-source Modelica Standard Library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end FluidVolumes; diff --git a/SorpLib/Basics/Volumes/FluidVolumes/package.order b/SorpLib/Basics/Volumes/FluidVolumes/package.order new file mode 100644 index 0000000000000000000000000000000000000000..fc9cb2b4ba0e586d93c0f5e97cd70d8ca301a3b0 --- /dev/null +++ b/SorpLib/Basics/Volumes/FluidVolumes/package.order @@ -0,0 +1,6 @@ +LiquidVolume +GasVolume +GasMixtureVolume +GasVaporMixtureVolume +VLEVolume +Tester diff --git a/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/PhaseSeparatorVolume.mo b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/PhaseSeparatorVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..68f65c8d27e1f03a39e49f6f85a7dc70e53245ba --- /dev/null +++ b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/PhaseSeparatorVolume.mo @@ -0,0 +1,279 @@ +within SorpLib.Basics.Volumes.PhaseSeparatorVolumes; +model PhaseSeparatorVolume + "Homogenous phase separator of a real fluid (i.e., with a two-phase regime)" + extends SorpLib.Basics.Volumes.BaseClasses.PartialPhaseSeparatorVolume( + final no_components = Medium.nX, + useHeatPorts=true, + useHeatPortsY=true, + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with a two-phase regime)" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + Medium.SaturationProperties stateSaturation + "Thermodynamic saturation state required to calculate medium properties"; + +equation + // + // Calculation of properties + // + state = Medium.setState_dTX(d=rho, T=T, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + stateSaturation = Medium.setSat_T(T=T) + "Thermodynamic saturation state required to calculate medium properties"; + + p = Medium.saturationPressure_sat(sat=stateSaturation) + "Pressure"; + + rho_liq = Medium.bubbleDensity(sat=stateSaturation) + "Density at saturated liquid line"; + rho_vap = Medium.dewDensity(sat=stateSaturation) + "Density at saturated vapor line"; + h_liq = Medium.bubbleEnthalpy(sat=stateSaturation) + "Specific enthalpy at saturated liquid line"; + h_vap = Medium.dewEnthalpy(sat=stateSaturation) + "Specific enthalpy at saturated vapor line"; + + // + // Mass balance + // + dm_dtau = mc_flow + "Overall mass balance"; + + mc_flow = sum(cfp_xMinus.m_flow) + sum(cfp_xPlus.m_flow) + "Sum of all convective mass flow rates across boundaries"; + + // + // Energy balance + // + dU_dtau = Hb_flow + Qb_flow + "Energy balane"; + + if avoid_events then + Hb_flow = + sum(cfp_xMinus.m_flow .* noEvent(actualStream(cfp_xMinus.h_outflow))) + + sum(cfp_xPlus.m_flow .* noEvent(actualStream(cfp_xPlus.h_outflow))) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + sum(cfp_xMinus.m_flow .* actualStream(cfp_xMinus.h_outflow)) + + sum(cfp_xPlus.m_flow .* actualStream(cfp_xPlus.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + + Qb_flow = Q_flow_xMinus + Q_flow_xPlus + + Q_flow_yMinus + Q_flow_yPlus + + Q_flow_zMinus + Q_flow_zPlus + "Sum of all heat flow rates across boundaries"; + + // + // Summary record + // + phaseSepratorProperties.cp = if calculateAdditionalProperties then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + phaseSepratorProperties.cv = + Medium.specificHeatCapacityCv(state=state) + "Specific heat capacity"; + phaseSepratorProperties.lambda = if calculateAdditionalProperties then + Medium.thermalConductivity(state=state) else 0 + "Thermal conductivity"; + phaseSepratorProperties.eta = if calculateAdditionalProperties then + Medium.dynamicViscosity(state=state) else 0 + "Dynamic viscosity"; + + phaseSepratorProperties.beta = if calculateAdditionalProperties then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + phaseSepratorProperties.kappa = if calculateAdditionalProperties then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + phaseSepratorProperties.my = if calculateAdditionalProperties then + v / phaseSepratorProperties.cp * (phaseSepratorProperties.beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + phaseSepratorProperties.mc_flow_yMinus = 0 + "Convective mass flow rate at port '-dy/2'"; + phaseSepratorProperties.mc_flow_yPlus = 0 + "Convective mass flow rate at port '+dy/2'"; + phaseSepratorProperties.mc_flow_zMinus = 0 + "Convective mass flow rate at port '-dz/2'"; + phaseSepratorProperties.mc_flow_zPlus = 0 + "Convective mass flow rate at port '+dz/2'"; + + phaseSepratorProperties.md_flow_xMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dx/2'"; + phaseSepratorProperties.md_flow_xPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dx/2'"; + phaseSepratorProperties.md_flow_yMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dy/2'"; + phaseSepratorProperties.md_flow_yPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dy/2'"; + phaseSepratorProperties.md_flow_zMinus = zeros(no_components) + "Diffusive mass flow rate at port '-dz/2'"; + phaseSepratorProperties.md_flow_zPlus = zeros(no_components) + "Diffusive mass flow rate at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a phase separator volume, applying a lumped modeling approach. +Depending on the volume setup, this model may have up to six heat ports (i.e., two +for each spatial direction of a cartesian coordinate system). Furthermore, this model +has convective fluid ports in y-direction, following the 'connectorSizing' principle. +The fluid port at position 'cfp_xMinus' is used as liquid fluid port, meaning that the +outflowing fluid is set at saturated liquid state. In contrast, the fluid port at +position 'cfp_XPlus' is used as vapor fluid port, meaning that the outflowing fluid is +set to saturated vapor state. +</p> + +<h4>Main equations</h4> +<p> +The most important equations are the momentum, mass, and energy balance. According to +the staggered grid approach, the momentum balance is not solved within the volume but +at the volume's boundaries via so-called +<a href=\"Modelica://SorpLib.Components.Fittings\">flow models</a>. Hennce, no pressure +losses occur within the volume: +</p> +<pre> + p = cfp_xMinus.p; +</pre> +<pre> + p = cfp_xPlus.p; +</pre> + +<p> +Regarding the mass and energy balances, either steady-state or tansient balnaces +can be selected. The mass balance is defined as +</p> +<pre> + (dm/dτ) = V * (dρ/dτ) = ∑ m<sub>c,flow</sub>; +</pre> +<p> +and the energy balance is defined as +</p> +<pre> + (dU/dτ) = u * (dm/dτ) + m * (du/dτ) = u * (dm/dτ) + m * [c<sub>v</sub> * (dT/dτ) + 1/ρ<sup>2</sup> * (-p + (h<sub>vap</sub> - h<sub>liq</sub>) / (1/ρ<sub>vap</sub> - 1/ρ<sub>liq</sub>)) (dρ/dτ)] = ∑ H<sub>b,flow</sub> + ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +Herein, <i>(dm/dτ)</i> is the derivative of the mass w.r.t. time, <i>(dU/dτ)</i> +is the derivative of the internal energy w.r.t. time, <i>(du/dτ)</i> is the derivative +of the specific internal energy w.r.t.time, <i>(dT/dτ)</i> is the derivative of the +temperature w.r.t. time, <i>(dρ/dτ)</i> is the derivative of the density w.r.t. +time, <i>V</i> is the volume, <i>m</i> is the mass, <i>p</i> ist the pressure, <i>ρ</i> +is the density, <i>ρ<sub>liq</sub></i> is the density at the saturated liquid line, +<i>ρ<sub>vap</sub></i> is the density at the saturated vapor line, <i>h<sub>liq</sub></i> +is the specific enthalpy at the saturated liquid line, <i>h<sub>vap</sub></i> is the specific +enthalpy at the saturated vapor line, <i>u</i> is the specific internal energy, <i>c<sub>v</sub></i> +is the specific heat capacity at constant volume,<i>m<sub>c,flow</sub></i> is the sum of the +convective mass flow rates, <i>H<sub>b,flow</sub></i> is the sum of the enthalpy flow rates, +and <i>Q<sub>b,flow</sub></i> is the sum of the heat flow rates. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> + <li> + Mechanical, thermal, and chemical equilibrium between the liquid and vapor phase + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used as ideal phase saperator to model an evaporator od condenser. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useHeatPorts</i>: + Defines if heat ports in the spatial direction <i>i</i> are required. + </li> + <li> + <i>calculateAdditionalProperties</i>: + Defines if additional properties like transport properties shall be calculated. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>useStateLimiter</i>: + Defines if specific enthalpy of vapor or liquid is limited at ports (i.e., vapor port is + slightly overheated and liquid port is slightly supercooled) to increase numerical stability. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has two dynamic states: +</p> +<ul> + <li> + Temperature <i>T</i> and density <i>ρ</i>. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Tummescheit, H (2002). Design and Implementation of Object-Oriented Model Libraries using Modelica. PhD Thesis. URL: https://lucris.lub.lu.se/ws/files/4779081/8571901.pdf. + </li> + <li> + Gräber, M. and Kirches, C. and Bock, H.G. and Schlöder, J.P. and Tegethoff, W. and Köhler, J. (2011). Determining the optimum cyclic operation of adsorption chillers by a direct method for periodic optimal control. International Journal of Refrigeration, 34(4):902-913. DOI: https://doi.org/10.1016/j.ijrefrig.2010.12.021. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 14, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 13, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PhaseSeparatorVolume; diff --git a/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/Tester/Test_PhaseSeparator.mo b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/Tester/Test_PhaseSeparator.mo new file mode 100644 index 0000000000000000000000000000000000000000..7c361c5a204e5f59452d200b17d57dfb9f27c971 --- /dev/null +++ b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/Tester/Test_PhaseSeparator.mo @@ -0,0 +1,153 @@ +within SorpLib.Basics.Volumes.PhaseSeparatorVolumes.Tester; +model Test_PhaseSeparator "Tester for phase separator volume" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the VLE liquid" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of VLE models + // + SorpLib.Basics.Volumes.PhaseSeparatorVolumes.PhaseSeparatorVolume phaseSeparator( + T_initial=293.15, + rho_initial=500, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + calculateAdditionalProperties=true, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1) "Model of a phase seperator volume" annotation ( + Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=90, + origin={0,0}))); + + // + // Definition of fluid boundaries + // +protected + Modelica.Blocks.Sources.Trapezoid input_liquidPort( + amplitude=-0.0001, + rising=250, + width=400, + falling=250, + period=950, + startTime=50) + "Input for liquid port boundary" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-30,-70}))); + Modelica.Blocks.Sources.Ramp input_vaporPort( + height=0.0001, + duration=250, + startTime=500) + "Input for vapor Port" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-30,70}))); + + SorpLib.Basics.Sources.Fluids.VLESource liquidInlet( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_mFlowInput=true, + m_flow_fixed=-0.001, + h_fixed=0.5e6, + redeclare package Medium = Medium) + "Liquid inlet for phase seprator volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-40}))); + SorpLib.Basics.Sources.Fluids.VLESource VaporInlet( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_mFlowInput=true, + m_flow_fixed=1e-3, + h_fixed=1e-6, + redeclare package Medium = Medium) + "Vapor inlet for phase separator" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={0,40}))); + + // + // Definition of thermal boundaries + // + Modelica.Blocks.Sources.Ramp input_heatFlow( + height=-350, + duration=250, + startTime=250) + "Input for heat flow" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=0, + origin={70,0}))); + + SorpLib.Basics.Sources.Thermal.HeatSource heatSource( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + use_QFlowInput=true, + Q_flow_fixed=-25) + "Heat source for phase seprator volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={40,0}))); + +equation + // + // Connections + // + connect(liquidInlet.port, phaseSeparator.cfp_xMinus[1]) annotation (Line( + points={{0,-40},{0,-8.4},{-3.6,-8.4}}, + color={0,140,72}, + thickness=1)); + connect(VaporInlet.port, phaseSeparator.cfp_xPlus[1]) annotation (Line( + points={{0,40},{0,15.6},{-3.6,15.6}}, + color={0,140,72}, + thickness=1)); + connect(heatSource.port, phaseSeparator.hp_yMinus) annotation (Line( + points={{40,0},{12,0}}, + color={238,46,47}, + thickness=1)); + + connect(input_liquidPort.y, liquidInlet.m_flow_input) + annotation (Line(points={{-19,-70},{-2,-70},{-2,-41.2}}, color={0,0,127})); + connect(input_vaporPort.y, VaporInlet.m_flow_input) + annotation (Line(points={{-19,70},{-2,70},{-2,41.2}}, color={0,0,127})); + connect(input_heatFlow.y, heatSource.Q_flow_input) + annotation (Line(points={{59,0},{50,0},{50,5},{41,5}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=1000), Documentation(info="<html> +<p> +This model checks the model of the phase separator volume. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 1000 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 14, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 13, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_PhaseSeparator; diff --git a/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/Tester/package.mo b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b0ff8b3470f86bb7c3c410970d4c76dfe1385d02 --- /dev/null +++ b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/Tester/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Basics.Volumes.PhaseSeparatorVolumes; +package Tester "Models to test and varify models of phase separators" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented phase separators. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/Tester/package.order b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..a00cf22d8758b14cb027fc677b3f95329d03b4aa --- /dev/null +++ b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/Tester/package.order @@ -0,0 +1 @@ +Test_PhaseSeparator diff --git a/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/package.mo b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..112c24c5d34b5507d9c9b68558a8dd85ff2b5beb --- /dev/null +++ b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Basics.Volumes; +package PhaseSeparatorVolumes "Package containing finte volume models of phase separators" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains finite volume models of phase separators. This package +calculates fluid properties based on the open-source Modelica Standard Library +(MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PhaseSeparatorVolumes; diff --git a/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/package.order b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/package.order new file mode 100644 index 0000000000000000000000000000000000000000..d86df7300ba35ede5ce46d3b387087aff0ac351e --- /dev/null +++ b/SorpLib/Basics/Volumes/PhaseSeparatorVolumes/package.order @@ -0,0 +1,2 @@ +PhaseSeparatorVolume +Tester diff --git a/SorpLib/Basics/Volumes/Records/AdsorbateVolumeProperties.mo b/SorpLib/Basics/Volumes/Records/AdsorbateVolumeProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..89b8e1290806a8dd7f40af566dafb0de7a55012a --- /dev/null +++ b/SorpLib/Basics/Volumes/Records/AdsorbateVolumeProperties.mo @@ -0,0 +1,86 @@ +within SorpLib.Basics.Volumes.Records; +record AdsorbateVolumeProperties + "This record summarizes important thermodynamic properties of an adsorbate volume" + extends Modelica.Icons.Record; + + // + // Definition of parameters + // + parameter Integer no_adsorptivs = 1 + "Number of adsorptivs (i.e., components that can be adsorbed/desorbed)" + annotation (Dialog(tab="General", group="Media")); + + // + // Definition of state properties + // + Modelica.Units.SI.Pressure p + "Pressure"; + Modelica.Units.SI.Temperature T + "Temperature"; + SorpLib.Units.Uptake x + "Loading"; + SorpLib.Units.Uptake[no_adsorptivs] x_i + "Loading of each component"; + + // + // Definition of additional properties + // + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity of the adsorpt"; + Modelica.Units.SI.SpecificEnthalpy dh_ads + "Specific enthalpy of adsorption"; + + // + // Definition of flow-specific variables + // + Modelica.Units.SI.MassFlowRate m_flow_sorption + "Total mass flow rate at port 'sorption'"; + + Modelica.Units.SI.MassFlowRate ma_flow_xMinus + "Adsorbate mass flow rate at port '-dx/2'"; + Modelica.Units.SI.MassFlowRate ma_flow_xPlus + "Adsorbate mass flow rate at port '+dx/2'"; + + Modelica.Units.SI.MassFlowRate ma_flow_yMinus + "Adsorbate mass flow rate at port '-dy/2'"; + Modelica.Units.SI.MassFlowRate ma_flow_yPlus + "Adsorbate mass flow rate at port '+dy/2'"; + + Modelica.Units.SI.MassFlowRate ma_flow_zMinus + "Adsorbate mass flow rate at port '-dz/2'"; + Modelica.Units.SI.MassFlowRate ma_flow_zPlus + "Adsorbate mass flow rate at port '+dz/2'"; + + Modelica.Units.SI.MassFlowRate[no_adsorptivs] md_flow_xMinus + "Diffusive mass flow rates at port '-dx/2'"; + Modelica.Units.SI.MassFlowRate[no_adsorptivs] md_flow_xPlus + "Diffusive mass flow rates at port '+dx/2'"; + + Modelica.Units.SI.MassFlowRate[no_adsorptivs] md_flow_yMinus + "Diffusive mass flow rates at port '-dy/2'"; + Modelica.Units.SI.MassFlowRate[no_adsorptivs] md_flow_yPlus + "Diffusive mass flow rates at port '+dy/2'"; + + Modelica.Units.SI.MassFlowRate[no_adsorptivs] md_flow_zMinus + "Diffusive mass flow rates at port '-dz/2'"; + Modelica.Units.SI.MassFlowRate[no_adsorptivs] md_flow_zPlus + "Diffusive mass flow rates at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains important thermodynamic properties of an adsorbate volume. +These properties may be required to calculate heat transfer or mass transfer +phenomena. +</p> +</html>", revisions="<html> +<ul> + <li> + December 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorbateVolumeProperties; diff --git a/SorpLib/Basics/Volumes/Records/FluidVolumeProperties.mo b/SorpLib/Basics/Volumes/Records/FluidVolumeProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..5fe92d33a3a62739c508720a6c6c5eaf510c5bfc --- /dev/null +++ b/SorpLib/Basics/Volumes/Records/FluidVolumeProperties.mo @@ -0,0 +1,99 @@ +within SorpLib.Basics.Volumes.Records; +record FluidVolumeProperties + "This record summarizes important thermodynamic properties of a fluid volume" + extends Modelica.Icons.Record; + + // + // Definition of parameters + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Media")); + + // + // Definition of state properties + // + Modelica.Units.SI.Pressure p + "Pressure"; + Modelica.Units.SI.Temperature T + "Temperature"; + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + + // + // Definition of additional properties + // + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity at constant pressure"; + Modelica.Units.SI.ThermalConductivity lambda + "Thermal conductivity"; + Modelica.Units.SI.DynamicViscosity eta + "Dynamic viscosity"; + + Modelica.Media.Common.IsobaricVolumeExpansionCoefficient beta + "Isobaric expnasion coefficient"; + Modelica.Media.Common.IsothermalCompressibility kappa + "Isothermal compressibility"; + Modelica.Media.Common.JouleThomsonCoefficient my + "Joule-Thomson coefficient"; + + Modelica.Units.SI.PrandtlNumber Pr + "Prandtl number"; + + // + // Definition of flow-specific variables + // + Modelica.Units.SI.MassFlowRate m_flow_sorption + "Total mass flow rate at port 'sorption'"; + + Modelica.Units.SI.MassFlowRate mc_flow_xMinus + "Total convective mass flow rate at port '-dx/2'"; + Modelica.Units.SI.MassFlowRate mc_flow_xPlus + "Total convective mass flow rate at port '+dx/2'"; + + Modelica.Units.SI.MassFlowRate mc_flow_yMinus + "Total convective mass flow rate at port '-dy/2'"; + Modelica.Units.SI.MassFlowRate mc_flow_yPlus + "Total convective mass flow rate at port '+dy/2'"; + + Modelica.Units.SI.MassFlowRate mc_flow_zMinus + "Total convective mass flow rate at port '-dz/2'"; + Modelica.Units.SI.MassFlowRate mc_flow_zPlus + "Total convective mass flow rate at port '+dz/2'"; + + Modelica.Units.SI.MassFlowRate[no_components] md_flow_xMinus + "Diffusive mass flow rates at port '-dx/2'"; + Modelica.Units.SI.MassFlowRate[no_components] md_flow_xPlus + "Diffusive mass flow rates at port '+dx/2'"; + + Modelica.Units.SI.MassFlowRate[no_components] md_flow_yMinus + "Diffusive mass flow rates at port '-dy/2'"; + Modelica.Units.SI.MassFlowRate[no_components] md_flow_yPlus + "Diffusive mass flow rates at port '+dy/2'"; + + Modelica.Units.SI.MassFlowRate[no_components] md_flow_zMinus + "Diffusive mass flow rates at port '-dz/2'"; + Modelica.Units.SI.MassFlowRate[no_components] md_flow_zPlus + "Diffusive mass flow rates at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains important thermodynamic properties of a fluid volume. These +properties may be required to calculate heat transfer or mass transfer phenomena. +</p> +</html>", revisions="<html> +<ul> + <li> + December 7, 2023, by Mirko Engelpracht:<br/> + Update due to major restructering of finite volume cells. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end FluidVolumeProperties; diff --git a/SorpLib/Basics/Volumes/Records/PhaseSeparatorGeometry.mo b/SorpLib/Basics/Volumes/Records/PhaseSeparatorGeometry.mo new file mode 100644 index 0000000000000000000000000000000000000000..30ac63e3bcbbaa4e943b8abdb445cd443d95e0ab --- /dev/null +++ b/SorpLib/Basics/Volumes/Records/PhaseSeparatorGeometry.mo @@ -0,0 +1,28 @@ +within SorpLib.Basics.Volumes.Records; +record PhaseSeparatorGeometry + "This record defines the geometry of a phase separator volume" + extends SorpLib.Basics.Volumes.Records.VolumeGeometry; + + // + // Definition of parameters + // + parameter Modelica.Units.SI.Area A_base = A_yz + "Base area used to calculate relative filling level" + annotation (Dialog(tab="General", group="Geometry - Area")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains parameters defining the geometry of a phase separator volume. +</p> +</html>", revisions="<html> +<ul> + <li> + December 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PhaseSeparatorGeometry; diff --git a/SorpLib/Basics/Volumes/Records/PhaseSeparatorProperties.mo b/SorpLib/Basics/Volumes/Records/PhaseSeparatorProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..7d02dcca442eb3453438d7c0e18dc6ec73e461d1 --- /dev/null +++ b/SorpLib/Basics/Volumes/Records/PhaseSeparatorProperties.mo @@ -0,0 +1,103 @@ +within SorpLib.Basics.Volumes.Records; +record PhaseSeparatorProperties + "This record summarizes important thermodynamic properties of a phase separator volume" + extends Modelica.Icons.Record; + + // + // Definition of parameters + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Media")); + + // + // Definition of state properties + // + Modelica.Units.SI.Pressure p + "Pressure"; + Modelica.Units.SI.Temperature T + "Temperature"; + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + + // + // Definition of additional properties + // + Modelica.Units.SI.Length l_liq + "Height of liquid phase"; + Real l_liq_rel(unit="1") + "Relative height of liquid phase"; + + // + // Definition of additional properties + // + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity at constant pressure"; + Modelica.Units.SI.SpecificHeatCapacity cv + "Specific heat capacity at constant volume"; + Modelica.Units.SI.ThermalConductivity lambda + "Thermal conductivity"; + Modelica.Units.SI.DynamicViscosity eta + "Dynamic viscosity"; + + Modelica.Media.Common.IsobaricVolumeExpansionCoefficient beta + "Isobaric expnasion coefficient"; + Modelica.Media.Common.IsothermalCompressibility kappa + "Isothermal compressibility"; + Modelica.Media.Common.JouleThomsonCoefficient my + "Joule-Thomson coefficient"; + + Modelica.Units.SI.PrandtlNumber Pr + "Prandtl number"; + + // + // Definition of flow-specific variables + // + Modelica.Units.SI.MassFlowRate mc_flow_xMinus + "Total convective mass flow rate at port '-dx/2'"; + Modelica.Units.SI.MassFlowRate mc_flow_xPlus + "Total convective mass flow rate at port '+dx/2'"; + + Modelica.Units.SI.MassFlowRate mc_flow_yMinus + "Total convective mass flow rate at port '-dy/2'"; + Modelica.Units.SI.MassFlowRate mc_flow_yPlus + "Total convective mass flow rate at port '+dy/2'"; + + Modelica.Units.SI.MassFlowRate mc_flow_zMinus + "Total convective mass flow rate at port '-dz/2'"; + Modelica.Units.SI.MassFlowRate mc_flow_zPlus + "Total convective mass flow rate at port '+dz/2'"; + + Modelica.Units.SI.MassFlowRate[no_components] md_flow_xMinus + "Diffusive mass flow rates at port '-dx/2'"; + Modelica.Units.SI.MassFlowRate[no_components] md_flow_xPlus + "Diffusive mass flow rates at port '+dx/2'"; + + Modelica.Units.SI.MassFlowRate[no_components] md_flow_yMinus + "Diffusive mass flow rates at port '-dy/2'"; + Modelica.Units.SI.MassFlowRate[no_components] md_flow_yPlus + "Diffusive mass flow rates at port '+dy/2'"; + + Modelica.Units.SI.MassFlowRate[no_components] md_flow_zMinus + "Diffusive mass flow rates at port '-dz/2'"; + Modelica.Units.SI.MassFlowRate[no_components] md_flow_zPlus + "Diffusive mass flow rates at port '+dz/2'"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains important thermodynamic properties of a phase seprator +volume. These properties may be required to calculate heat transfer or mass +transfer phenomena. +</p> +</html>", revisions="<html> +<ul> + <li> + December 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PhaseSeparatorProperties; diff --git a/SorpLib/Basics/Volumes/Records/SolidVolumeProperties.mo b/SorpLib/Basics/Volumes/Records/SolidVolumeProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..14895ef86886a28442e1a4d75b1d48118ecfd62a --- /dev/null +++ b/SorpLib/Basics/Volumes/Records/SolidVolumeProperties.mo @@ -0,0 +1,44 @@ +within SorpLib.Basics.Volumes.Records; +record SolidVolumeProperties + "This record summarizes important thermodynamic properties of a solide volume" + extends Modelica.Icons.Record; + + // + // Definition of state properties + // + Modelica.Units.SI.Pressure p + "Pressure"; + Modelica.Units.SI.Temperature T + "Temperature"; + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + + // + // Definition of additional properties + // + Modelica.Units.SI.SpecificHeatCapacity c + "Specific heat capacity"; + Modelica.Units.SI.ThermalConductivity lambda + "Thermal conductivity"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains important thermodynamic properties of a solid volume. These +properties may be required to calculate heat transfer phenomena. +</p> +</html>", revisions="<html> +<ul> + <li> + December 6, 2023, by Mirko Engelpracht:<br/> + Update due to major restructering of finite volume cells. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SolidVolumeProperties; diff --git a/SorpLib/Basics/Volumes/Records/VolumeGeometry.mo b/SorpLib/Basics/Volumes/Records/VolumeGeometry.mo new file mode 100644 index 0000000000000000000000000000000000000000..11ec4d8a0731e4f90a8b830616973464b77350da --- /dev/null +++ b/SorpLib/Basics/Volumes/Records/VolumeGeometry.mo @@ -0,0 +1,52 @@ +within SorpLib.Basics.Volumes.Records; +record VolumeGeometry + "This record defines the geometry of a finite volume" + extends Modelica.Icons.Record; + + // + // Definition of parameters + // + parameter Modelica.Units.SI.Length dx = 0.1 + "Length in x direction" + annotation (Dialog(tab="General", group="Geometry - Length")); + parameter Modelica.Units.SI.Length dy = 0.1 + "Length in y direction" + annotation (Dialog(tab="General", group="Geometry - Length")); + parameter Modelica.Units.SI.Length dz = 0.1 + "Length in z direction" + annotation (Dialog(tab="General", group="Geometry - Length")); + + parameter Modelica.Units.SI.Area A_xy = dx * dy + "Cross-sectional area of x-y direction" + annotation (Dialog(tab="General", group="Geometry - Area")); + parameter Modelica.Units.SI.Area A_xz = dx * dz + "Cross-sectional area of x-z direction" + annotation (Dialog(tab="General", group="Geometry - Area")); + parameter Modelica.Units.SI.Area A_yz = dy * dz + "Cross-sectional area of y-z direction" + annotation (Dialog(tab="General", group="Geometry - Area")); + + parameter Modelica.Units.SI.Volume V = dx * dy * dz + "Volume" + annotation (Dialog(tab="General", group="Geometry - Volume")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains parameters defining the geometry of a finite volume. +</p> +</html>", revisions="<html> +<ul> + <li> + December 6, 2023, by Mirko Engelpracht:<br/> + Update due to major restructering of finite volume cells. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end VolumeGeometry; diff --git a/SorpLib/Basics/Volumes/Records/package.mo b/SorpLib/Basics/Volumes/Records/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..ae3a581aff0000cb4b869a9556b03905d8b46acf --- /dev/null +++ b/SorpLib/Basics/Volumes/Records/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Basics.Volumes; +package Records "Records describing geometry and summarizing properties of finite volumes" + extends Modelica.Icons.RecordsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains definitions of records. These records are used to cluster +parameters and variables to tidy up the model implementation. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Records; diff --git a/SorpLib/Basics/Volumes/Records/package.order b/SorpLib/Basics/Volumes/Records/package.order new file mode 100644 index 0000000000000000000000000000000000000000..b59102378f757fabb8762c99a9b38ede80b9cd3a --- /dev/null +++ b/SorpLib/Basics/Volumes/Records/package.order @@ -0,0 +1,6 @@ +AdsorbateVolumeProperties +FluidVolumeProperties +PhaseSeparatorGeometry +PhaseSeparatorProperties +SolidVolumeProperties +VolumeGeometry diff --git a/SorpLib/Basics/Volumes/SolidVolumes/SolidVolume.mo b/SorpLib/Basics/Volumes/SolidVolumes/SolidVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..d1651aa31be790eea71f88f37383c7b12ef19f4c --- /dev/null +++ b/SorpLib/Basics/Volumes/SolidVolumes/SolidVolume.mo @@ -0,0 +1,291 @@ +within SorpLib.Basics.Volumes.SolidVolumes; +model SolidVolume "Homogenous solid volume" + + // + // Definition of models + // + replaceable Media.Solids.MetalsAndMetalAlloys.Aluminium solidMedium + constrainedby Media.Solids.BaseClasses.PartialSolid( + final calcCaloricProperties=true, + final approach_v=SorpLib.Choices.SpecificVolumeSolid.Constant, + final p=p, + final T=T) + "Medium model calculating solid properties" + annotation (Dialog(tab="General", group="Media"), + choicesAllMatching=true, + Placement(transformation(extent={{-8,-8},{12,12}}))); + + // + // Definition of parameters regarding calculation setup + // + parameter SorpLib.Choices.IndependentVariablesVolume independentStateVariables= + SorpLib.Choices.IndependentVariablesVolume.pTX + "Independent state variables" + annotation (Dialog(tab="General", group="Calculation Setup"), + Evaluate=true, + HideResult = true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.Temperature T_initial = 298.15 + "Initial value of temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=(independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX))); + parameter Modelica.Units.SI.SpecificEnthalpy h_initial = 0 + "Initial value of specific enthalpy" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=(independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX))); + + extends SorpLib.Basics.Volumes.BaseClasses.PartialVolume( + final useHeatPorts=true, + useHeatPortsX = true); + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Definition of variables + // + Modelica.Units.SI.Temperature T( + start=T_initial, + stateSelect= if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then StateSelect.prefer + else StateSelect.avoid) + "Temperature"; + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + Modelica.Units.SI.Density rho + "Density"; + + Modelica.Units.SI.SpecificEnthalpy h( + start=h_initial, + stateSelect= if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX then StateSelect.prefer + else StateSelect.avoid) + "Specific enthalpy"; + Modelica.Units.SI.SpecificInternalEnergy u + "Specific internal energy"; + + Modelica.Units.SI.Mass m + "Mass"; + + Modelica.Units.SI.InternalEnergy U + "Internal energy"; + Real dU_dtau(final unit="W") + "Derivative of internal energy w.r.t. time"; + Modelica.Units.SI.HeatFlowRate Qb_flow + "Sum of all heat flow rates across boundaries"; + + SorpLib.Basics.Volumes.Records.SolidVolumeProperties solidProperties + "Properties of solid volume often required for calculation of heat transfer"; + +initial equation + if type_energyBalance == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + T = T_initial + "Fixed initial value"; + + else + h = h_initial + "Fixed initial value"; + + end if; + + elseif type_energyBalance == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + der(T) = 0 + "Steady-state initial value"; + + else + der(h) = 0 + "Steady-state initial value"; + + end if; + end if; + +equation + // + // Assertations + // + assert(useHeatPortsX or useHeatPortsY or useHeatPortsZ, + "Must use heat ports at least in one direction (e.g., x, y, or z)!", + level = AssertionLevel.error); + + // + // Property calculation + // + v = solidMedium.state_variables.v + "Specific volume"; + rho = 1 / v + "Density"; + + h = solidMedium.state_variables.h + "Specific enthalpy"; + u = solidMedium.state_variables.u + "Specific internal energy"; + + // + // Mass balance + // + m = geometry.V / v + "Mass"; + + // + // Energy balance + // + U = m * u + "Internal energy"; + + dU_dtau = Qb_flow + "Energy balance"; + + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dU_dtau = m * solidMedium.additional_variables.c * der(T) + "Transient energy balance with p and T as independent states"; + + else + dU_dtau = m *der(h) + "Transient energy balance with p and h as independent states"; + + end if; + end if; + + Qb_flow = Q_flow_xMinus + Q_flow_xPlus + Q_flow_yMinus + Q_flow_yPlus + + Q_flow_zMinus + Q_flow_zPlus + "Sum of all heat flow rates across boundaries"; + + T_heatPorts = T + "Required for conditional component"; + + // + // Summary record + // + solidProperties.p = p + "Pressure"; + solidProperties.T = T + "Temperature"; + solidProperties.v = v + "Specific volume"; + + solidProperties.c = solidMedium.additional_variables.c + "Specific heat capacity"; + solidProperties.lambda = solidMedium.additional_variables.lambda + "Thermal conductivity"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a solid volume, applying a lumped modeling approach. Depending on +the volume setup, this model may have up to six heat ports (i.e., two for each spatial +direction of a cartesian coordinate system). These heat ports allow for the combination +of several solid volumes via appropriate heat transfer models to create a spatially +distributed model. +</p> + +<h4>Main equations</h4> +<p> +The most important equation is the energy balance. When using the temperature <i>T</i> as +an independent state, the energy balance is defined as +</p> +<pre> + m * c * (dT/dτ) = ∑ Q<sub>b,flow</sub>; +</pre> +<p> +When using the specific enthalpy <i>h</i> as an independent state, the energy balance is +defined as +</p> +<pre> + m * (dh/dτ) = ∑ Q<sub>b,flow</sub>; +</pre> + +<p> +Herein, <i>m</i> is the volume mass, <i>T</i> is the temperature, <i>h</i> is the +specific enthalpy, <i>c</i> is the specific heat capacity, and <i>Q<sub>b,flow</sub></i> +is the sum of the heat flow rates over the volume boundaries. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Incompressible medium (i.e., constant specific volume <i>v</i>) + </li> + <li> + Homogenoues properties within the volume + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used as wall model to represent the thermal capacity of a +metal. Thus, e.g., walls of pipes, fins of heat exchangers, or casings of components +are modeled. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useHeatPorts</i>: + Defines if heat ports in the spatial direction <i>i</i> are required. + </li> + <li> + <i>independentStateVariables</i>: + Defines independent state variables of the model. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +This model has one dynamic state that can be selected (see options): +</p> +<ul> + <li> + Temperature <i>T</i> (recommended to avoid non-linear equations), or + </li> + <li> + specific enthalpy <i>h</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 6, 2023, by Mirko Engelpracht:<br/> + Major revisions due to restructering finite volumes. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + Revisions (e.g., object-oriented approach) after restructering of the library. + </li> + <li> + November 23, 2017, by Andrej Gibelhaus:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end SolidVolume; diff --git a/SorpLib/Basics/Volumes/SolidVolumes/Tester/Test_SolidVolume.mo b/SorpLib/Basics/Volumes/SolidVolumes/Tester/Test_SolidVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..c43fe3fa272fb689a74396e75d5b54aadffb9175 --- /dev/null +++ b/SorpLib/Basics/Volumes/SolidVolumes/Tester/Test_SolidVolume.mo @@ -0,0 +1,221 @@ +within SorpLib.Basics.Volumes.SolidVolumes.Tester; +model Test_SolidVolume "Tester for solid" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable model Solid = + SorpLib.Media.Solids.MetalsAndMetalAlloys.Aluminium + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Solid medium" + annotation (Dialog(tab="General", group="Media")); + + parameter Modelica.Units.SI.Pressure p_initial = 0 + "Initial pressure" + annotation (Dialog(tab="General", group="Start Values")); + parameter Modelica.Units.SI.Temperature T_initial = 273.15 + "Initial temperature" + annotation (Dialog(tab="General", group="Start Values")); + + // + // Definition of solid models + // + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume solid_transientFreeInitial_x( + redeclare final Solid solidMedium, + final p=p, + final T_initial=T_initial, + final type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial) + "Solid with transient energy balance but free start values and heat ports in + x direction" + annotation (Placement(transformation(extent={{-40,60},{-20,80}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume solid_transientFreeInitial_xy( + redeclare final Solid solidMedium, + final p=p, + final T_initial=T_initial, + final useHeatPortsY=true, + final type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial) + "Solid with transient energy balance but free start values and heat ports in + x and y directions" + annotation (Placement(transformation(extent={{-10,60},{10,80}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume + solid_transientFreeInitial_xyz( + redeclare final Solid solidMedium, + final p=p, + final T_initial=T_initial, + final useHeatPortsY=true, + final useHeatPortsZ=true, + final type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial) + "Solid with transient energy balance but free start values and heat ports in + x, y, and z directions" + annotation (Placement(transformation(extent={{20,60},{40,80}}))); + + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume solid_transientFixed_x( + redeclare final Solid solidMedium, + final p=p, + final T_initial=T_initial, + final type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial) + "Solid with transient energy balance but fixed start values and heat ports in + x direction" + annotation (Placement(transformation(extent={{-40,20},{-20,40}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume solid_transientFixed_xy( + redeclare final Solid solidMedium, + final p=p, + final T_initial=T_initial, + final useHeatPortsY=true, + final type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial) + "Solid with transient energy balance but fixed start values and heat ports in + x and y directions" + annotation (Placement(transformation(extent={{-10,20},{10,40}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume solid_transientFixed_xyz( + redeclare final Solid solidMedium, + final p=p, + final T_initial=T_initial, + final useHeatPortsY=true, + final useHeatPortsZ=true, + final type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial) + "Solid with transient energy balance but fixed start values and heat ports in + x, y, and z directions" + annotation (Placement(transformation(extent={{20,20},{40,40}}))); + + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume + solid_transientFreeInitial_boundaries_x( + redeclare final Solid solidMedium, + final p=p, + final T_initial=T_initial, + final type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial) + "Solid with transient energy balance but free start values and heat ports in + x direction connected to thermal boundaries" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume + solid_transientFixedInitial_boundaries_x( + redeclare final Solid solidMedium, + final p=p, + final T_initial=T_initial, + final type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial) + "Solid with transient energy balance but fixed start values and heat ports in + x direction connected to thermal boundaries" + annotation (Placement(transformation(extent={{-10,-60},{10,-40}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume + solid_steadyStateFreeInitial_boundaries_x( + redeclare final Solid solidMedium, + final p=p, + final T_initial=T_initial, + final type_energyBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) + "Solid with steady-state energy balance but free start values and heat ports + in x direction connected to thermal boundaries" + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}))); + + // + // Definition of boundaries + // +protected + Sources.Thermal.HeatSource heatSource_transientFixedInitial_xMinus( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, use_QFlowInput= + true) "Heat source for heat ports '-dx/2'" + annotation (Placement(transformation(extent={{-60,-60},{-40,-40}}))); + Sources.Thermal.HeatSource heatSource_transientFreeInitial_xMinus( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + use_QFlowInput=true) + "Heat source for heat ports '-dx/2'" + annotation (Placement(transformation(extent={{-60,-30},{-40,-10}}))); + Sources.Thermal.HeatSource heatSource_steadyStateFreeInitial_xMinus( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + use_QFlowInput= true) + "Heat source for heat ports '-dx/2'" + annotation (Placement(transformation(extent={{-60,-90},{-40,-70}}))); + Sources.Thermal.HeatSource heatSource_steadyStateFreeInitial_xPlus( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=true) + "Heat source for heat ports '+dx/2'" + annotation (Placement(transformation(extent={{50,-90},{30,-70}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Ramp input_QFlowVar( + height=10000, + duration=25, + offset=-5000, + startTime=0) "Ramp to simulate input signal of heat flow rate" annotation ( + Placement(transformation(extent={{-90,-60},{-70,-40}})), HideResult=true); + + Modelica.Blocks.Sources.Ramp input_TVar( + height=200, + duration=25, + offset=173.15, + startTime=0) "Ramp to simulate input signal of temperature" annotation ( + Placement(transformation(extent={{90,-60},{70,-40}})), HideResult=true); + // + // Definition of variables + // + Modelica.Units.SI.Pressure p(start=p_initial, fixed=true) + "Pressure"; + +equation + // + // Change of state variables + // + der(p) = (10e5 - p_initial) / 25 + "Pressure"; + + // + // Connections + // + connect(heatSource_transientFreeInitial_xMinus.port, + solid_transientFreeInitial_boundaries_x.hp_xMinus) annotation (Line( + points={{-50,-20},{-6,-20}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_transientFixedInitial_xMinus.port, + solid_transientFixedInitial_boundaries_x.hp_xMinus) annotation (Line( + points={{-50,-50},{-6,-50}}, + color={238,46,47}, + thickness=1)); + connect(heatSource_steadyStateFreeInitial_xMinus.port, + solid_steadyStateFreeInitial_boundaries_x.hp_xMinus) annotation (Line( + points={{-50,-80},{-6,-80}}, + color={238,46,47}, + thickness=1)); + connect(solid_steadyStateFreeInitial_boundaries_x.hp_xPlus, + heatSource_steadyStateFreeInitial_xPlus.port) annotation (Line( + points={{6,-80},{40,-80}}, + color={238,46,47}, + thickness=1)); + + connect(input_TVar.y, heatSource_steadyStateFreeInitial_xPlus.T_input) + annotation (Line(points={{69,-50},{60,-50},{60,-74.8},{41,-74.8}}, color={0, + 0,127})); + connect(input_QFlowVar.y, heatSource_transientFreeInitial_xMinus.Q_flow_input) + annotation (Line(points={{-69,-50},{-60,-50},{-60,-25},{-51,-25}}, color={0, + 0,127})); + connect(input_QFlowVar.y, heatSource_transientFixedInitial_xMinus.Q_flow_input) + annotation (Line(points={{-69,-50},{-60,-50},{-60,-55},{-51,-55}}, color={0, + 0,127})); + connect(input_QFlowVar.y, heatSource_steadyStateFreeInitial_xMinus.Q_flow_input) + annotation (Line(points={{-69,-50},{-60,-50},{-60,-85},{-51,-85}}, color={0, + 0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=25), Documentation(info="<html> +<p> +This model checks the solid volume model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 25 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 6, 2023, by Mirko Engelpracht:<br/> + Added documentation. + </li> + <li> + January 12, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_SolidVolume; diff --git a/SorpLib/Basics/Volumes/SolidVolumes/Tester/package.mo b/SorpLib/Basics/Volumes/SolidVolumes/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2b5778e1f23bfc1daf768d22649cddb8e118388d --- /dev/null +++ b/SorpLib/Basics/Volumes/SolidVolumes/Tester/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Basics.Volumes.SolidVolumes; +package Tester "Models to test and varify models of solid volumes" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented solid volumes. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Basics/Volumes/SolidVolumes/Tester/package.order b/SorpLib/Basics/Volumes/SolidVolumes/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..d9d7d13a6064e6348698a4755db75f957c3cbaa6 --- /dev/null +++ b/SorpLib/Basics/Volumes/SolidVolumes/Tester/package.order @@ -0,0 +1 @@ +Test_SolidVolume diff --git a/SorpLib/Basics/Volumes/SolidVolumes/package.mo b/SorpLib/Basics/Volumes/SolidVolumes/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a7710a6944e180c611cadb5112c85c6c6e8083a8 --- /dev/null +++ b/SorpLib/Basics/Volumes/SolidVolumes/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Basics.Volumes; +package SolidVolumes "Package containing finte volume models of solids" +extends Modelica.Icons.VariantsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains finite volume models of solids. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end SolidVolumes; diff --git a/SorpLib/Basics/Volumes/SolidVolumes/package.order b/SorpLib/Basics/Volumes/SolidVolumes/package.order new file mode 100644 index 0000000000000000000000000000000000000000..8641ba6ca06483e685b340c458b6e403f3d57a1c --- /dev/null +++ b/SorpLib/Basics/Volumes/SolidVolumes/package.order @@ -0,0 +1,2 @@ +SolidVolume +Tester diff --git a/SorpLib/Basics/Volumes/Utilities/mapSorptionFluidPorts.mo b/SorpLib/Basics/Volumes/Utilities/mapSorptionFluidPorts.mo new file mode 100644 index 0000000000000000000000000000000000000000..1bb61a2d383565880b6ff8b6dbee171dd774772f --- /dev/null +++ b/SorpLib/Basics/Volumes/Utilities/mapSorptionFluidPorts.mo @@ -0,0 +1,75 @@ +within SorpLib.Basics.Volumes.Utilities; +function mapSorptionFluidPorts + "Maps sorption fluid ports to the component array of a mixture fluid" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Integer no_components + "Number of components" + annotation (Dialog(tab="General", group="Inputs")); + input Integer[:] ind_adsorptivs + "Indeces of adsorptivs in the ideal gas mixture" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Integer[no_components] mappedFluidPorts + "Mapped fluid ports" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Integer fp_ind = 1 + "Actual index of fluid port"; + +algorithm + // + // Loop through components and check if they are adsorptives + // + mappedFluidPorts := zeros(no_components) + "Mapped fluid ports"; + + for ind_comp in 1:no_components loop + for ind_ads in ind_adsorptivs loop + if ind_comp == ind_ads then + mappedFluidPorts[ind_comp] :=fp_ind + "Map sorption fluid port index"; + fp_ind :=fp_ind + 1 + "Actual index of fluid port"; + break; + + end if; + end for; + end for; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function maps the indices of sorption fluid ports to a component array of a +mixture fluid in the following way: +</p> +<ul> + <li> + 0 if current component of the component array cannot be adsorbed/desorbed. + </li> + <li> + Index of sorption fluid port if current component of the component array can be + adsorbed/desorbed. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 11, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end mapSorptionFluidPorts; diff --git a/SorpLib/Basics/Volumes/Utilities/package.mo b/SorpLib/Basics/Volumes/Utilities/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..29af5622ed312d25c93a00b4f082cb53ef64d124 --- /dev/null +++ b/SorpLib/Basics/Volumes/Utilities/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Basics.Volumes; +package Utilities "Package containing utility functions and models for modelling finite volumes" + extends Modelica.Icons.UtilitiesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains utility functions and models required to model finite volumes. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Utilities; diff --git a/SorpLib/Basics/Volumes/Utilities/package.order b/SorpLib/Basics/Volumes/Utilities/package.order new file mode 100644 index 0000000000000000000000000000000000000000..4cf6a39f1ab52e384d0bfc39e6f09bd9da2f32f0 --- /dev/null +++ b/SorpLib/Basics/Volumes/Utilities/package.order @@ -0,0 +1 @@ +mapSorptionFluidPorts diff --git a/SorpLib/Basics/Volumes/package.mo b/SorpLib/Basics/Volumes/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e0ce69eef23bf370f3fcd450954144510f849738 --- /dev/null +++ b/SorpLib/Basics/Volumes/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Basics; +package Volumes "Finite volumes used to aggregate complex models" +extends SorpLib.Icons.VolumesPackage; + +annotation (Documentation(info="<html> +<p> +This package provides finite volume models of solids, fluids, phase separators, +and adsorbates. These models calculate thermodynamic properties as homogenous +properties within the volume. Thus, these models serve as the basis for aggregating +complex models discretized in several spatial directions via an upwind finite +volume approach. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Volumes; diff --git a/SorpLib/Basics/Volumes/package.order b/SorpLib/Basics/Volumes/package.order new file mode 100644 index 0000000000000000000000000000000000000000..86020b4220d1e09b6f1ffee3a37893f667c5f167 --- /dev/null +++ b/SorpLib/Basics/Volumes/package.order @@ -0,0 +1,7 @@ +BaseClasses +Records +AdsorbateVolumes +FluidVolumes +PhaseSeparatorVolumes +SolidVolumes +Utilities diff --git a/SorpLib/Basics/package.mo b/SorpLib/Basics/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a8a5f9cd594445da8076b5339eb33eb8899ad449 --- /dev/null +++ b/SorpLib/Basics/package.mo @@ -0,0 +1,34 @@ +within SorpLib; +package Basics "Library containing basic modeles used to aggregate advanced models" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains basic models required to aggregate advanced models: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Basics.Interfaces\">Interfaces</a>: + Thermal and fluid connectors that serve as interfaces between models. + </li> + <li> + <a href=\"Modelica://SorpLib.Basics.Sources\">Sources</a>: + Thermal and fluid sources that define potential, flow, and stream variables + at connectors. + </li> + <li> + <a href=\"Modelica://SorpLib.Basics.Volumes\">Volumes</a>: + Finite volume models with (transient) mass and energy balances. These finite + volume models cover adsorbates, fluids, solids, and phase separators and can + be used to create spatial distributed models. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Basics; diff --git a/SorpLib/Basics/package.order b/SorpLib/Basics/package.order new file mode 100644 index 0000000000000000000000000000000000000000..68a915b002fdf3c297889b48c6d0d53a108589f8 --- /dev/null +++ b/SorpLib/Basics/package.order @@ -0,0 +1,3 @@ +Interfaces +Sources +Volumes diff --git a/SorpLib/Choices/BalanceEquations.mo b/SorpLib/Choices/BalanceEquations.mo new file mode 100644 index 0000000000000000000000000000000000000000..25eff0c61adc8e9c24ae1f03e7b77259e7d9db77 --- /dev/null +++ b/SorpLib/Choices/BalanceEquations.mo @@ -0,0 +1,11 @@ +within SorpLib.Choices; +type BalanceEquations = enumeration( + TransientFreeInitial + "Transient balance equation - free initial state values", + TransientFixedInitial + "Transient balance equation - fixed initial state values", + TransientSteadyStateInitial + "Transient balance equation - steady-state initial state values", + SteadyStateFreeInitial + "Steady-state balance equation - free initial state values") + "Enumeration defining balance equations"; diff --git a/SorpLib/Choices/BoundaryFluidPotentialFlow.mo b/SorpLib/Choices/BoundaryFluidPotentialFlow.mo new file mode 100644 index 0000000000000000000000000000000000000000..bd5129ca3e490e9d10c97539ecfce386ce9e80fd --- /dev/null +++ b/SorpLib/Choices/BoundaryFluidPotentialFlow.mo @@ -0,0 +1,6 @@ +within SorpLib.Choices; +type BoundaryFluidPotentialFlow = enumeration( + Pressure "Prescribed pressure at fluid boundary", + MassFlowRate "Prescribed mass flow rate at fluid boundary", + VolumeFlowRate "Prescribed volume flow rate at fluid boundary") + "Enumeration defining prescribed potential or flow variable of a fluid boundary"; diff --git a/SorpLib/Choices/BoundaryFluidStreamEnthalpy.mo b/SorpLib/Choices/BoundaryFluidStreamEnthalpy.mo new file mode 100644 index 0000000000000000000000000000000000000000..8b024568a4d08fdc605368695b83c9f8b9603de5 --- /dev/null +++ b/SorpLib/Choices/BoundaryFluidStreamEnthalpy.mo @@ -0,0 +1,5 @@ +within SorpLib.Choices; +type BoundaryFluidStreamEnthalpy = enumeration( + SpecificEnthalpy "Prescribed specific enthalpy at fluid boundary", + Temperature "Prescribed temperature at fluid boundary") + "Enumeration defining prescribed stream variable (specific enthalpy) of a fluid boundary"; diff --git a/SorpLib/Choices/BoundaryFluidStreamMassFractions.mo b/SorpLib/Choices/BoundaryFluidStreamMassFractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..ea4091aa0c0a062656976e6637954618b9add3bf --- /dev/null +++ b/SorpLib/Choices/BoundaryFluidStreamMassFractions.mo @@ -0,0 +1,5 @@ +within SorpLib.Choices; +type BoundaryFluidStreamMassFractions = enumeration( + MassFractions "Prescribed mass fractions", + DryMassFractionsPhi "Prescribed mass fractions of dry air components and relative humidity") + "Enumeration defining prescribed stream variable (mass fractions) of a fluid boundary"; diff --git a/SorpLib/Choices/BoundaryThermal.mo b/SorpLib/Choices/BoundaryThermal.mo new file mode 100644 index 0000000000000000000000000000000000000000..4a2cf6ec4514d5286dbe6ee4dee69ccfe2c4a806 --- /dev/null +++ b/SorpLib/Choices/BoundaryThermal.mo @@ -0,0 +1,5 @@ +within SorpLib.Choices; +type BoundaryThermal = enumeration( + Temperature "Prescribed temperature at thermal boundary", + HeatFlowRate "Prescribed heat flow rate at thermal boundary") + "Enumeration defining prescribed variable of a thermal boundary"; diff --git a/SorpLib/Choices/ChangingConstantVariableOfDiagram.mo b/SorpLib/Choices/ChangingConstantVariableOfDiagram.mo new file mode 100644 index 0000000000000000000000000000000000000000..d95be46caf77325524cff22e7bd859a4085b1cda --- /dev/null +++ b/SorpLib/Choices/ChangingConstantVariableOfDiagram.mo @@ -0,0 +1,6 @@ +within SorpLib.Choices; +type ChangingConstantVariableOfDiagram = enumeration( + Manual "Manual input", + Linespace "Linearly distributed values", + Logspace "Logarithmicaly distributed values") + "Enumeration defining the changing type (i.e., manuel, linespace, logspace) of the constant variable of a fluid property diagram"; diff --git a/SorpLib/Choices/DiagramTypePureComponentWorkingPair.mo b/SorpLib/Choices/DiagramTypePureComponentWorkingPair.mo new file mode 100644 index 0000000000000000000000000000000000000000..11b513c549779d397b3b3a98df5016e307de27ee --- /dev/null +++ b/SorpLib/Choices/DiagramTypePureComponentWorkingPair.mo @@ -0,0 +1,6 @@ +within SorpLib.Choices; +type DiagramTypePureComponentWorkingPair = enumeration( + Isotherms "Isotherms: T = const, p = variable", + Isosters "Isosters: x = const, T = variable", + Isobars "Isobars: p = const, T = variable") + "Enumeration defining the diagram type (i.e., isotherms, isosters, or isobars) of a pure component working pair"; diff --git a/SorpLib/Choices/GeneralizedFunctionApproach.mo b/SorpLib/Choices/GeneralizedFunctionApproach.mo new file mode 100644 index 0000000000000000000000000000000000000000..fc66d172dfb47b70b911e44c576005dd83c2f11a --- /dev/null +++ b/SorpLib/Choices/GeneralizedFunctionApproach.mo @@ -0,0 +1,7 @@ +within SorpLib.Choices; +type GeneralizedFunctionApproach = enumeration( + PolynomialFunctionTemperature "Polynomial function using temperature", + PolynomialFunctionReducedTemperature "Polynomial function using reduced temperature", + ExponentialFunctionTemperature "Exponential function using temperature", + ExponentialFunctionReducedTemperature "Exponential function using reduced temperature") + "Enumeration defining the approach used within the generalized function for calculating fluid property data"; diff --git a/SorpLib/Choices/IASTAlgorithm.mo b/SorpLib/Choices/IASTAlgorithm.mo new file mode 100644 index 0000000000000000000000000000000000000000..7cfd19173a6ff586e03c57dd7e66da270a2d746a --- /dev/null +++ b/SorpLib/Choices/IASTAlgorithm.mo @@ -0,0 +1,6 @@ +within SorpLib.Choices; +type IASTAlgorithm = enumeration( + NewtonRaphson "Standard 'Newton-Raphson' algorithm", + NestedLoop "'Nested loop' algorithm", + FastIAST "'Fast IAST' algorithm") + "Enumeration defining the algorithm solving the IAST (i.e., x_i = f(p,y,T))"; diff --git a/SorpLib/Choices/IndependentVariablesMultiComponentWorkingPair.mo b/SorpLib/Choices/IndependentVariablesMultiComponentWorkingPair.mo new file mode 100644 index 0000000000000000000000000000000000000000..fcff07257deab4f62670b92c85c89cfd442ec880 --- /dev/null +++ b/SorpLib/Choices/IndependentVariablesMultiComponentWorkingPair.mo @@ -0,0 +1,5 @@ +within SorpLib.Choices; +type IndependentVariablesMultiComponentWorkingPair = enumeration( + pyT "Pressure, independent mole fractions of gas/vapor phase, and temperature", + xT "Uptakes and temperature") + "Enumeration defining the independent variables of a multi-component working pair"; diff --git a/SorpLib/Choices/IndependentVariablesPureComponentWorkingPair.mo b/SorpLib/Choices/IndependentVariablesPureComponentWorkingPair.mo new file mode 100644 index 0000000000000000000000000000000000000000..482f2f3f171e6c3bef33de329229cdb11223a5e5 --- /dev/null +++ b/SorpLib/Choices/IndependentVariablesPureComponentWorkingPair.mo @@ -0,0 +1,5 @@ +within SorpLib.Choices; +type IndependentVariablesPureComponentWorkingPair = enumeration( + pT "Pressure and temperature", + xT "Uptake and temperature") + "Enumeration defining the independent variables of a pure component working pair"; diff --git a/SorpLib/Choices/IndependentVariablesVolume.mo b/SorpLib/Choices/IndependentVariablesVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..7a50814b966e1df32f8be07e9df03530de9ad7ec --- /dev/null +++ b/SorpLib/Choices/IndependentVariablesVolume.mo @@ -0,0 +1,5 @@ +within SorpLib.Choices; +type IndependentVariablesVolume = enumeration( + pTX "Pressure, temperature, and independent mass fractions", + phX "Pressure, specific enthalpy, and independent mass fractions") + "Enumeration defining the independent variables of a finite volume"; diff --git a/SorpLib/Choices/InterpolationApproach.mo b/SorpLib/Choices/InterpolationApproach.mo new file mode 100644 index 0000000000000000000000000000000000000000..5e0d83d230775d3dd4d83a5bd0289c295ba90ed6 --- /dev/null +++ b/SorpLib/Choices/InterpolationApproach.mo @@ -0,0 +1,5 @@ +within SorpLib.Choices; +type InterpolationApproach = enumeration( + Linear "Linear interpolation without extrapolation", + CubicSplines "Cubic spline interpolation without extrapolation") + "Enumeration defining the interpolation approach for calculations"; diff --git a/SorpLib/Choices/IsobaricExpansionCoefficientAdsorpt.mo b/SorpLib/Choices/IsobaricExpansionCoefficientAdsorpt.mo new file mode 100644 index 0000000000000000000000000000000000000000..e40ee394e48f8bcb41b3dfaca97ece97b23ec55e --- /dev/null +++ b/SorpLib/Choices/IsobaricExpansionCoefficientAdsorpt.mo @@ -0,0 +1,7 @@ +within SorpLib.Choices; +type IsobaricExpansionCoefficientAdsorpt = enumeration( + Constant "Constant value", + BoilingCurve "Boiling point curve as function of temperature", + GeneralizedFunction "Generalized function often used for fluid property data calculation", + Interpolation "Table-based interpolation as function of temperature") + "Enumeration defining the calculation approach for the isobaric expansion coefficient of the adsorpt phase"; diff --git a/SorpLib/Choices/MassFlowRateHeatTranferCorrelation.mo b/SorpLib/Choices/MassFlowRateHeatTranferCorrelation.mo new file mode 100644 index 0000000000000000000000000000000000000000..054bdbdc801ec649ee108d064534aec4743332a6 --- /dev/null +++ b/SorpLib/Choices/MassFlowRateHeatTranferCorrelation.mo @@ -0,0 +1,10 @@ +within SorpLib.Choices; +type MassFlowRateHeatTranferCorrelation = enumeration( + PortXMinus + "Mass flow rate at design inlet", + PortXPlus + "Mass flow rate at design outlet", + Average + "Average absolute mass flow rate") + "Enumeration defining the mass flow rate used for calculating generic heat transfer + correlations"; diff --git a/SorpLib/Choices/MassTransferFluidProperties.mo b/SorpLib/Choices/MassTransferFluidProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..cb7a9a15fc7d7958ed0ecfede3bade66431ed2f3 --- /dev/null +++ b/SorpLib/Choices/MassTransferFluidProperties.mo @@ -0,0 +1,11 @@ +within SorpLib.Choices; +type MassTransferFluidProperties = enumeration( + PortAInlet + "Instreaming fluid properties ar port a", + PortBInlet + "Instreaming fluid properties ar port b", + ActualInlet + "Fluid properties at actual inlet", + AverageInstreaming + "Average fluid properties using instreaming fluid properties") + "Enumeration defining fluid property calculation for mass transfers"; diff --git a/SorpLib/Choices/PrescripedFanVariable.mo b/SorpLib/Choices/PrescripedFanVariable.mo new file mode 100644 index 0000000000000000000000000000000000000000..c30a30be74fbf08b3931e1a259bcf3b87f96264d --- /dev/null +++ b/SorpLib/Choices/PrescripedFanVariable.mo @@ -0,0 +1,7 @@ +within SorpLib.Choices; +type PrescripedFanVariable = enumeration( + m_flow + "Mass flow rate", + V_flow + "Volume flow rate") + "Enumeration defining the variable that is prescribed by a fan"; diff --git a/SorpLib/Choices/PrescripedPumpVariable.mo b/SorpLib/Choices/PrescripedPumpVariable.mo new file mode 100644 index 0000000000000000000000000000000000000000..9368d18893f259532b934e7c4296186691f7851e --- /dev/null +++ b/SorpLib/Choices/PrescripedPumpVariable.mo @@ -0,0 +1,7 @@ +within SorpLib.Choices; +type PrescripedPumpVariable = enumeration( + m_flow + "Mass flow rate", + V_flow + "Volume flow rate") + "Enumeration defining the variable that is prescribed by a pump"; diff --git a/SorpLib/Choices/ResistorFluidProperties.mo b/SorpLib/Choices/ResistorFluidProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..d1f76ac71561d5248a12ddef2c4d6ee298c9ec3e --- /dev/null +++ b/SorpLib/Choices/ResistorFluidProperties.mo @@ -0,0 +1,15 @@ +within SorpLib.Choices; +type ResistorFluidProperties = enumeration( + Constant + "Constant fluid properties", + PortAInlet + "Instreaming fluid properties ar port a", + PortBInlet + "Instreaming fluid properties ar port b", + ActualInlet + "Fluid properties at actual inlet", + AverageInstreaming + "Average fluid properties using instreaming fluid properties", + Detailed + "Correct fluid properties, also depending on the flow direction") + "Enumeration defining fluid property calculation for hydraulic resistors"; diff --git a/SorpLib/Choices/SorptionEnthalpy.mo b/SorpLib/Choices/SorptionEnthalpy.mo new file mode 100644 index 0000000000000000000000000000000000000000..d94cbf65946f88df7939e5c958f4ad0e8ecf645b --- /dev/null +++ b/SorpLib/Choices/SorptionEnthalpy.mo @@ -0,0 +1,7 @@ +within SorpLib.Choices; +type SorptionEnthalpy = enumeration( + Constant "Constant sorption enthalpy", + Formal "Definition according to thermodynamic derivation", + ClausiusClapeyron "Definition according to Clausius Clapeyron assumptions", + Dubinin "Definition according to the model of Dubinin") + "Enumeration defining the calculation approach for the sorption enthalpy"; diff --git a/SorpLib/Choices/SpecificHeatCapacityAdsorpt.mo b/SorpLib/Choices/SpecificHeatCapacityAdsorpt.mo new file mode 100644 index 0000000000000000000000000000000000000000..56dd3acfee937f673abe6ee0f5888c9cab703a41 --- /dev/null +++ b/SorpLib/Choices/SpecificHeatCapacityAdsorpt.mo @@ -0,0 +1,10 @@ +within SorpLib.Choices; +type SpecificHeatCapacityAdsorpt = enumeration( + Constant "Constant value", + BoilingCurve "Boiling point curve as function of temperature", + GeneralizedFunction "Generalized function often used for fluid property data calculation", + Interpolation "Table-based interpolation as function of temperature", + WaltonLeVan "Derivation according to Walton and LeVan (2005)", + ChakrabortyElAl "Derivation according to Chakraborty et al. (2009)", + SchwambergerSchmidt "Derivation according to Schwamberger and Schmidt (2013)") + "Enumeration defining the calculation approach for the specific heat capacity of the adsorpt phase"; diff --git a/SorpLib/Choices/SpecificHeatCapacitySolid.mo b/SorpLib/Choices/SpecificHeatCapacitySolid.mo new file mode 100644 index 0000000000000000000000000000000000000000..d6ac37c8debf5cfaeb1df230ac85dbf46c4cea6a --- /dev/null +++ b/SorpLib/Choices/SpecificHeatCapacitySolid.mo @@ -0,0 +1,6 @@ +within SorpLib.Choices; +type SpecificHeatCapacitySolid = enumeration( + Constant "Constant value", + GeneralizedFunction "Generalized function often used for fluid property data calculation", + Interpolation "Table-based interpolation as function of temperature") + "Enumeration defining the calculation approach for the specific heat capacity of a solid"; diff --git a/SorpLib/Choices/SpecificVolumeAdsorpt.mo b/SorpLib/Choices/SpecificVolumeAdsorpt.mo new file mode 100644 index 0000000000000000000000000000000000000000..43e40613254086869c8a1e4c38e6c3496746e082 --- /dev/null +++ b/SorpLib/Choices/SpecificVolumeAdsorpt.mo @@ -0,0 +1,7 @@ +within SorpLib.Choices; +type SpecificVolumeAdsorpt = enumeration( + Constant "Constant value", + BoilingCurve "Boiling point curve as function of temperature", + GeneralizedFunction "Generalized function often used for fluid property data calculation", + Interpolation "Table-based interpolation as function of temperature") + "Enumeration defining the calculation approach for the specific volume of the adsorpt phase"; diff --git a/SorpLib/Choices/SpecificVolumeSolid.mo b/SorpLib/Choices/SpecificVolumeSolid.mo new file mode 100644 index 0000000000000000000000000000000000000000..9981a8e112dcfed0fe4c48838a677cd511ff06e0 --- /dev/null +++ b/SorpLib/Choices/SpecificVolumeSolid.mo @@ -0,0 +1,6 @@ +within SorpLib.Choices; +type SpecificVolumeSolid = enumeration( + Constant "Constant value", + GeneralizedFunction "Generalized function often used for fluid property data calculation", + Interpolation "Table-based interpolation as function of temperature") + "Enumeration defining the calculation approach for the specific volume of a solid"; diff --git a/SorpLib/Choices/TemperatureHeatTranferCorrelation.mo b/SorpLib/Choices/TemperatureHeatTranferCorrelation.mo new file mode 100644 index 0000000000000000000000000000000000000000..5bea75febffd4f25ae76862c4190ba0861c763da --- /dev/null +++ b/SorpLib/Choices/TemperatureHeatTranferCorrelation.mo @@ -0,0 +1,12 @@ +within SorpLib.Choices; +type TemperatureHeatTranferCorrelation = enumeration( + PortA + "Average temperature at port a", + PortB + "Average temperature at port b", + Average + "Average temperature of ports a and b", + Difference + "Average temperature difference between ports a and b") + "Enumeration defining the temperature used for calculating generic heat transfer + correlations"; diff --git a/SorpLib/Choices/ThermalConductivitySolid.mo b/SorpLib/Choices/ThermalConductivitySolid.mo new file mode 100644 index 0000000000000000000000000000000000000000..a89591b8d6f8642bf9da864bb6207bf1d6bc3b1a --- /dev/null +++ b/SorpLib/Choices/ThermalConductivitySolid.mo @@ -0,0 +1,6 @@ +within SorpLib.Choices; +type ThermalConductivitySolid = enumeration( + Constant "Constant value", + GeneralizedFunction "Generalized function often used for fluid property data calculation", + Interpolation "Table-based interpolation as function of temperature") + "Enumeration defining the calculation approach for the thermal conductivity of a solid"; diff --git a/SorpLib/Choices/package.mo b/SorpLib/Choices/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..0a8808fcb14b7ff79ab307238851b8494be727aa --- /dev/null +++ b/SorpLib/Choices/package.mo @@ -0,0 +1,17 @@ +within SorpLib; +package Choices "Library containing type definitions representing choices" +extends Modelica.Icons.TypesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains definitions of types representing enumeration used within the Modelica library SorpLib. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Choices; diff --git a/SorpLib/Choices/package.order b/SorpLib/Choices/package.order new file mode 100644 index 0000000000000000000000000000000000000000..f3e17b5e793e154c1ad4211886d73b28e73e808d --- /dev/null +++ b/SorpLib/Choices/package.order @@ -0,0 +1,26 @@ +IASTAlgorithm +GeneralizedFunctionApproach +InterpolationApproach +SpecificVolumeSolid +SpecificHeatCapacitySolid +ThermalConductivitySolid +SorptionEnthalpy +SpecificHeatCapacityAdsorpt +SpecificVolumeAdsorpt +IsobaricExpansionCoefficientAdsorpt +IndependentVariablesVolume +IndependentVariablesPureComponentWorkingPair +IndependentVariablesMultiComponentWorkingPair +ChangingConstantVariableOfDiagram +DiagramTypePureComponentWorkingPair +BoundaryThermal +BoundaryFluidPotentialFlow +BoundaryFluidStreamEnthalpy +BoundaryFluidStreamMassFractions +BalanceEquations +ResistorFluidProperties +PrescripedPumpVariable +PrescripedFanVariable +TemperatureHeatTranferCorrelation +MassFlowRateHeatTranferCorrelation +MassTransferFluidProperties diff --git a/SorpLib/Components/AdsorberColumns/package.mo b/SorpLib/Components/AdsorberColumns/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..fa000ea609e54d3ee723f9a20a124cf8ce75ed8d --- /dev/null +++ b/SorpLib/Components/AdsorberColumns/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Components; +package AdsorberColumns "Adsorbers columns used in open sorption systems" + extends SorpLib.Icons.AdsorberColumnsPackage; + + annotation (Documentation(info="<html> +<p> +TO BE ADDED! +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end AdsorberColumns; diff --git a/SorpLib/Components/AdsorberColumns/package.order b/SorpLib/Components/AdsorberColumns/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Components/Cells/Adsorbent/Adsorbent.mo b/SorpLib/Components/Cells/Adsorbent/Adsorbent.mo deleted file mode 100644 index 9dbfadf1f158633f69185761d3ab2c1a4244b34c..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Adsorbent/Adsorbent.mo +++ /dev/null @@ -1,213 +0,0 @@ -within SorpLib.Components.Cells.Adsorbent; -model Adsorbent - - /*********************** SIM ***********************************/ - parameter TILMedia.VLEFluidTypes.BaseVLEFluid vleFluidType=sim.vleFluidType1 - "VLE fluid type" annotation (Dialog(tab="SIM", group="SIM"), choices( - choice=sim.vleFluidType1 "VLE fluid 1 as defined in SIM", - choice=sim.vleFluidType2 "VLE fluid 2 as defined in SIM", - choice=sim.vleFluidType3 "VLE fluid 3 as defined in SIM")); -protected - outer TIL.SystemInformationManager sim "System information manager"; - - TIL.Internals.SimPort simPort; - - /********************* Connectors *************************************/ -public - TIL.Connectors.VLEFluidPort vlePortA(final vleFluidType=vleFluidType, final - h_limit=-1e6) annotation (Placement(transformation(extent={{-82,-10},{-62, - 10}}, rotation=0), iconTransformation(extent={{-82,-10},{-62,10}}))); - TIL.Connectors.VLEFluidPort vlePortB(final vleFluidType=vleFluidType, final - h_limit=-1e6) annotation (Placement(transformation(extent={{62,-10},{82, - 10}}, - rotation=0), iconTransformation(extent={{62,-10},{82,10}}))); - TIL.Connectors.HeatPort heatPortA annotation (Placement(transformation(extent={{-10,-70}, - {10,-50}}, rotation=0), iconTransformation(extent={{-10,-70}, - {10,-50}}))); - TIL.Connectors.HeatPort heatPortB annotation (Placement(transformation(extent= - {{-10,50},{10,70}}), iconTransformation(extent={{-10,50},{10,70}}))); - - /********************* AdsorbentAdsorbate ****************************************/ - - replaceable model AdsorbentAdsorbateModel = - SorpLib.Media.AdsorbentAdsorbate.Zeolite13XWaterNunez - constrainedby - SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater - "Adsorbent / Adsorbate model" annotation (choicesAllMatching=true, Dialog( - group="Adsorbent / Adsorbate")); - - AdsorbentAdsorbateModel adsorbentAdsorbate(final x=x, final T=T) "Sorbent" - annotation (Placement(transformation(extent={{-10,20},{10,40}}))); - - Real x(unit="kg/kg") "Loading of adsorbent"; - Modelica.SIunits.Temperature T "Temperature of adsorbent/adsorbate"; - Modelica.SIunits.Pressure p "Equilibrium pressure of adsorbate"; - - /********************* VLE Fluid ************************************/ - - Modelica.SIunits.Mass massVLEFluid; - - TILMedia.VLEFluid_dT adsorbate( - final vleFluidType=vleFluidType, - d=adsorbate.VLE.d_v, - T=adsorbentAdsorbate.T) - annotation (Placement(transformation(extent={{-10,-34},{10,-14}}))); - - /********************* Parameters ************************************/ - parameter Modelica.SIunits.Mass massAdsorbent "Mass of dry adsorbent" - annotation (Dialog(group="Parameters")); - - /********************* Initialization ********************************/ - parameter Modelica.SIunits.Temperature TInitial(start=298.15) - annotation (Dialog(group="Initial Values", tab="Start and Initialization")); - parameter Real xInitial(unit="kg/kg",start=0.2) annotation (Dialog( - enable=initial_x, - group="Initial Values", - tab="Start and Initialization")); - parameter Modelica.SIunits.Pressure pInitial=100 annotation (Dialog( - enable=not initial_x, - group="Initial Values", - tab="Start and Initialization")); - parameter Boolean initial_x=true "if true then xInital else pInitial" - annotation (Dialog(group="Initial Values", tab="Start and Initialization"), - choices(choice=true "Use loading (x) as initilization parameter", choice=false - "Use pressure (p) as initilization parameter")); - - /*******************Summary**********************/ -public - inner parameter Boolean includeDefaultSummary=true - "include default entries in summary" - annotation (Dialog(tab="Advanced", group="Summary")); - - parameter Boolean generateEventsAtFlowReversal=false "If true, tranport propertie are calculated in the gas object" annotation(Evaluate=true, Dialog(tab="Advanced", group="Event-Handling")); - - -protected - record Summary - extends TIL.Internals.ClassTypes.Record; - - Modelica.SIunits.MassFlowRate m_flow_A if include; - Modelica.SIunits.MassFlowRate m_flow_B if include; - Modelica.SIunits.Pressure p_A if include; - Modelica.SIunits.Pressure p_B if include; - Modelica.SIunits.SpecificEnthalpy h_A_outflow if include; - Modelica.SIunits.SpecificEnthalpy h_B_outflow if include; - Modelica.SIunits.Pressure p if include; - Real x if include; - Modelica.SIunits.Temperature T if include; - - protected - outer parameter Boolean includeDefaultSummary; - parameter Boolean include=includeDefaultSummary; - - end Summary; - - replaceable record SummaryClass = Summary; - -public - SummaryClass summary( - m_flow_A=vlePortA.m_flow, - m_flow_B=vlePortB.m_flow, - p_A=vlePortA.p, - p_B=vlePortB.p, - h_A_outflow=vlePortA.h_outflow, - h_B_outflow=vlePortB.h_outflow, - p=adsorbentAdsorbate.p, - x=x, - T=T) annotation (Placement(transformation(extent={{66,-88},{86,-68}}, - rotation=0))); - -initial equation - T = TInitial; - - if initial_x then - x = xInitial; - else - p = pInitial; - end if; - -equation - assert(vleFluidType.concatVLEFluidName == adsorbentAdsorbate.vleFluidType.concatVLEFluidName, - "VLE Fluid in SIM doesn't match adsorbate."); - - // simport setup - connect(sim.fluidPort[vleFluidType.ID], simPort.vleFluidPort); - simPort.vleFluidMass = massVLEFluid; - simPort.vleFluidVolume =massVLEFluid/adsorbate.VLE.d_l; - - adsorbentAdsorbate.p = p; - - // Momentum balance - - vlePortA.p = p; - vlePortB.p = p; - - // Mass balance - massAdsorbent*der(x) = vlePortA.m_flow + vlePortB.m_flow; - massVLEFluid = x*massAdsorbent; - - // Energy balance - if (generateEventsAtFlowReversal) then - massAdsorbent*adsorbentAdsorbate.dudT_x*der(T) = - vlePortA.m_flow*actualStream(vlePortA.h_outflow) - - vlePortA.m_flow*adsorbentAdsorbate.u_ads + - vlePortB.m_flow*actualStream(vlePortB.h_outflow) - - vlePortB.m_flow*adsorbentAdsorbate.u_ads + - heatPortA.Q_flow + heatPortB.Q_flow; - else - massAdsorbent*adsorbentAdsorbate.dudT_x*der(T) = - vlePortA.m_flow*noEvent(actualStream(vlePortA.h_outflow)) - - vlePortA.m_flow*adsorbentAdsorbate.u_ads + - vlePortB.m_flow*noEvent(actualStream(vlePortB.h_outflow)) - - vlePortB.m_flow*adsorbentAdsorbate.u_ads + - heatPortA.Q_flow + heatPortB.Q_flow; - end if; - - // Fluid ports - vlePortA.h_outflow =adsorbate.h; - vlePortB.h_outflow =adsorbate.h; - - heatPortA.T = T; - heatPortB.T = T; - - annotation ( - Icon(graphics={Bitmap( - extent={{-100,100},{100,-100}}, - imageSource="iVBORw0KGgoAAAANSUhEUgAAATMAAAEaCAYAAAB9+7CgAAAAAXNSR0ICQMB9xQAAAAlwSFlzAAAXEgAAFxIBZ5/SUgAAABl0RVh0U29mdHdhcmUATWljcm9zb2Z0IE9mZmljZX/tNXEAAAs8SURBVHja7d0vbyNJAobxhoGBgYEDDQcOzEcIHHI87IJWDvKBk+YbnGHgwJCTgk6BhgMNTqfA7OpGCjrNVY87Eyfbcfynquyu+ll6ULJZ9av3feJy7J7m6uqqQT/hMQqMA7evmATOZAQc0F6F0CuxD4G7wI93mJMaQGaHKrLLwOMaIltmGjiWH7C/E5AwnwM9CtxsKLFlZoQG7O8EJNTnYMc7iOyJa1kC+zkBCfb5ae5jBJm1nMsUyH8CEvAi4FkkkbXcB07kCuQ9AQm3aT5FFNkTF4oL5D0BCbhpviSQ2VR5gbwnIAEv/gT8A8DguCCzlzL7phTAIJmS2UuZzZUCGCQzMnPMBIqAzF7KbJog5K9e8AXSn4DI7GXI5wlCvlRgIPkJaE5mL0M+DjxEDnmkwEDeE5CgF0F/jhjwRKZA/hOQoJ/D/leEcNu3eRzJE8h/AhL01a+PWfyxY7DtxzQ+yhN4c2e/pTwBCXghsocIz8iIDEi7s5UnIAH3B/zPZv0PxE4cLYFsInvzBCTgP4c17r5+2ixuV9J376Xb7msjZQW22tm/Y5+ABNwjsp7vf/ONegC2fsJwGfMEJOB3REZmQLqdvToB3fd9/7onIAG/IzIyA/LsbNetCThxwACRrbczMjvwgAEiW29nZHbgAQNEttHPIbNDDRggMjIrImCAyMisiIABIiOzIgIGiIzMiggYIDIyKyJggMjIrIiAASIjsyICBoiMzIoIGCAyMisiYIDIyKyIgAEiI7MiAgaIjMyKCBggMjIrImCAyMisiIABIiOzIgIGiIzMiggYILLKZVZKwACRVSyzkgIGiKxSmZUWMEBkFcqsxIABIqtMZqUGDBBZRTIrOWCAyCqRWekBA0RWgcxqCBggssJlVkvAAJEVLLOaAgaIrFCZ1RYwQGQFyqzGgAEiK0xmtQYMEFlBMqs5YIDICpFZ7QEDRFaAzAQMENngZSZggMgGLzMBA0Q2eJkJGCCywctMwACRDV5mAgaIbPAyEzBAZIOXmYABIjt4mXUBjgO3r5gEzgQMRBdW397+Efhe+s6SyCw8PgTuesJ7zf8EDOzcr3X3VvTOosssPC4DjxsGK2Bgu25ts7dZ4NjW3pBZeBwFbraUWMu9gIG1O7Xr3ooUWiyZjXcI9olrMgPW6pS9pZBZ98LjY4RwW84FDKzsk70llNksUrAA8tK+vHNCZj//2+aTQgCD5oLMFjL7ogzAoJmS2UJmt8oADJoZmS1k9i1FwF6UBHq7ZG8JZTYXLpkhW5fsbWDHzDmZAb1dsreEMpsmCPcrmQG9XbK3hDI7TxDuJZkBvV2yt4QyO276b+OzCyMyA3q7ZG+pZNb9gM8Rg50UWEAyQ8w+2VsqmXU/5CZCsO2fnY/IDHi3U/aWUGYnOz79bT84+7HQ4pEZYnfK3lLJrPtB29zx8uk3RJEiIzMk7JW9pZLZ0g/c5O6XkxKPlmSGjP2yt1Qy637oabO4gVzf2f62+9qokrKRGVJ37PQNeT3UtLckMjNm1w89IzMBA3pGZkoGMiMzMlMy6BmZCdn1Q8/ITMCAnpGZkgF6RmZKBj2TAZkpGfSMzAQM6BmZKRmgZ2SmZNAzGZCZkkHPyIzMyAx6RmZKBugZmSkZ9EwGZKZk0DMyE7Lrh56RmYABPSMzJYMhy4DMlAx6RmZCdv3QMzITMKBnZKZkIDMyIzMlg56RmZBdP/SMzAQM6BmZKRmgZ2SmZNAzGZCZkkHPyIzMyAx6RmZKBugZmSkZ9EwGZKZk0DMyE7KSQc/ITMkAPSMzJYOeyYDMlAx6RmZCdv3QMzITMKBnZKZkIDMyIzMlg56RmZBdP/SMzAQM6BmZKRmgZ2SmZNAzGZCZkkHPyEzAxgc9IzMlA/SMzJQMeiYDMlMy6BmZkRmZQc/ITMkAPSMzJYOeyYDMlAx6RmZCdv3QMzITMKBnZKZkIDMyIzMlg56RmZBdP/SMzAQM6BmZKRmgZ2SmZNAzGZCZ64eekZmAAT0jMyUD9IzMlAx6JgMyUzLoGZmRGZlBz8hMyQA9IzMlg57JgMyUDHpGZkJ2/dAzMhMwoGdkpmTQMxmQmZJBz8hMyK4fekZmAgb0jMyUDGRGZmSmZNAzMhOy64eekZmAAT0jMyUD9IzMlAx6JgMyUzLoGZmRGZlBz8hMyQA9IzMlg57JgMyUDHpGZmSmZNAzMlMyQM/ITMmgZzIgMyWDnpGZkF0/9IzMBAzoGZkpGciMzMhMyaBnZCZk1w89IzMBA3pGZkoG6BmZKRn0TAZkpmTQMzITMKBnZKZkgJ6RmZJBz2RAZkoGPSMzMiMz6BmZDTfYUWD8+voDk8CZAYLM0mYQuO14d3NC7r/eD4G7nmBfMyc1kNlhbE7If77Wy8DjGqEuMw0cGyTIbH+bE/LzNR4FbjYMdJkZoYHM9rc5IT9f43iHUJ+4NkqQ2X42J+SrXy/0P0YItuXcMEFm+Tcn5MX1zSKF2nIfODFOkFnezVUfcnh8ihjqExfGCTLLuzkya5ovCYKdGifILO/myGzxhrwfAAbNjMya5psiAAVAZj/fUawIAJk5ZgLYO3MyW3wsInawX72gDX8AyLs5Mmua8wTBXhonyOzN6/xris2RWdMcBx4iBzsyTpBZ7zWOAr8nkNlIyIvr+0vEUCeGCTJ7U2QPCUT2c3Oeme3+yf1l2rd5HBkmyCybyH5truqQI4us/dDsR6MEma0tsr/vKLgXm6s25BUi+77lbwciA5mtL7Jx9/V17zD77uaqDHmFyGbdHwQ2ufPlxNESZLa5yF59786bqy7k90S29H2nzeLmce333i9930P3Rtuxv1qCzHYXWazNVRXyuiIDyCyvyKL8f2sJmchAZuWKrBqZERnIrGyRVSEzIgOZlS+y4mVGZCCzOkRWtMyIDGRWj8iKlRmRgczqElmRMiMykFl9IitOZkQGMqtTZEXJjMhAZvWKrBiZERnIrG6RFSEzIgOZEdngZUZkIDMiG7zMiAxkRmSDl1l3z7E7IgOZEdlgZdaJbEZkIDMiG6zMiAxkRmSDl9kKkd24bTXIrG6RDUZmRAYyI7LBy4zIQGZENniZERnIjMgGLzMiA5kR2eBlRmQgsyw7K0ZkBykzIgOZZdlZUSI7OJkRGcgsy86KE9lByYzIQGZZdlakyA5GZkQGZNlZsSI7CJkRGZBlZ0WLbO8yIzIgy86KF9leZUZkQJadVSGyvcmMyIAsO6tGZHuRGZEBWXZWlciyy4zIgCw7q05kWWVGZECWnVUpsmwyC49TIgOS76xakWWRWSeyOZEBSXdWtciSy4zIgPQyI7LEMlshsmsiA6LtjMhSymyFyKZKC0TbGZGllBmRAellRmSJZUZkQHqZEdkWMutCG/eENgmcERmQTmaB245feyOyDWUWHh8Cdz2BvaaV1xmRATtJbN29/SfwncjWlFl4XAYe1wh2mf8SGbCVyLbZG5Gtkln7donu/V8/IkBkwGqJxdjb32TZL7MxkQHZZBZjb9eyfCWz7kXFx0gyOxcssFJk9pZQZrNIwbbcB06EC7wpM3tLk2vzKWKwT1wIF+gdnL0llNmXBOF63QzoH5y9JZTZbYJwAeRjRmYLmX1TBmDYkNlCZnNlAMjMMRPAvpmT2UJm0wThfhUu0Ds4e0sos/ME4V4KF+gdnL0llNlx039LkV0YCRfoHZy9pcq2C/hzxGAnggVWCs3eUsmsCzjGHTPat3n4x0qA94VmbwlldrLj09/2g7MfhQqsJTN7SyWzLuB173jZ9xtCsMBmQrO3VDJbCnmTu19OPNUFdpKavaWSWRfwabO4gVx7tr9fCvOhe6Pt2F9RgGhCs7cd+T+rXxLlogyZDAAAAABJRU5ErkJggg==", - fileName="modelica://SorpLib/Resources/Images/Adsorbent.png")}), - Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{100, - 100}})), - Documentation(info="<html> -<p>This model is a cell model combining adsorbent and adsorbate. This cell model consists of an energy and a mass balance, combined with equilibrium data for the adsorbent/adsorbate working pair (<a href=\"modelica://SorpLib.Media.Functions.CharCurve1Arctan\">SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater</a>). </p> -<p>For a cell, a lumped model approach is used with equal temperature of adsorbent/adsorbate. By combining more cells with a finite volume approach, a distributed adsorbent model can be built, with a spatial loading and temperature distribution. To create a full adsorber, this adsorbent cell model can be connected to some kind of heat exchanger model. </p> -<p><b>Main equations</b> </p> -<p>The main equations are an energy and a mass balance.</p> -<p>Mass balance: </p> -<p align=\"center\"><i>dx/dt</i> = 1 / <i>m</i><sub>sor</sub> * (<i><code>ṁ</code></i><sub>ad,in</sub> - <i><code>ṁ</code></i><sub>ad,out</sub>) </p> -<p>where <i>x</i> is the loading of the adsorbent defined as <i>x = m</i><sub>ad</sub> / <i>m</i><sub>sor</sub>. <i>m</i><sub>sor</sub> is the mass of dry adsorbent and <i>m</i><sub>ad</sub> is the mass of adsorbate. </p> -<p>Energy balance: </p> -<p align=\"center\">(<i>c</i><sub>sor</sub> + <i>x</i> <i>c</i><sub>ad</sub>) <i>dT/dt</i> + <i>u</i><sub>ad</sub> <i>dx/dt</i> = 1 / <i>m</i><sub>sor</sub> * (<i><code>ṁ</code></i><sub>ad,in</sub> * <i>h</i><sub>in</sub> - <i><code>ṁ</code></i><sub>ad,out</sub> * <i>h</i><sub>out</sub> + <code>∑</code> <i>Q</i> ) </p> -<p>where <i>c</i> is the specific heat capacity, <i>u</i><sub>ad</sub> is the specific internal energy of the adsorbate at the current loading and temperature, <i>h</i> is the specific enthalpy of the incoming and outflowing adsorbate stream, and <i>Q</i> is the heat flow.</p> -<p>The specific enthalpy of the incoming adsorbate stream is determined by the component, where the adsorbate is coming from (normally the evaporator). The specific enthalpy of the outflowing stream is set the saturation enthalpy of adsorbate in vapour state. </p> -<p><b>Assumptions and limitations</b> </p> -<p>The model uses the following main assumptions: </p> -<ul> -<li>All adsorbate is in adsorbed state. </li> -<li>Adsorbent and adsorbate have the same temperature. </li> -<li>Enthalpy of outflowing stream is set the saturation enthalpy of adsorbate in vapour state</li> -<li>Note: the pressure at the VLE ports is set to the equilibrium pressure of the equilibrium model. --> A mass transfer model has to be connected to the adsorbent model. </li> -</ul> -<p><b>Typical use and important parameters</b> </p> -<p>The adsorbent cell model is at the heart of all adsorption models: closed adsorber (adsorption heat pumps and chiller) and open adsorber (desiccant). </p> -<p><b>Dynamics</b> </p> -<p>The adsorbent model has two differential states: the loading <i>x</i> and the temperature <i>T</i>. </p> -<p><b>References</b> </p> -<ul> -<li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257. </li> -</ul> -<p><b>Author Information</b> </p> -<ul> -<li>November 18, 2017, by Uwe Bau:<br>Tidy up implementation and enhance documentation for publication of library.<br></li> -</ul> -</html>")); -end Adsorbent; diff --git a/SorpLib/Components/Cells/Adsorbent/Testers/TestAdsorbent.mo b/SorpLib/Components/Cells/Adsorbent/Testers/TestAdsorbent.mo deleted file mode 100644 index 54c4b2a22d5244c675a6bebd563ab4aab79f883e..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Adsorbent/Testers/TestAdsorbent.mo +++ /dev/null @@ -1,125 +0,0 @@ -within SorpLib.Components.Cells.Adsorbent.Testers; -model TestAdsorbent - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1(use_massFlowRateInput= - true) annotation (Placement(transformation(extent={{-34,-10},{-26,10}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - hFixed=2538000, - pFixed(displayUnit="kPa") = 0, - m_flowFixed=0, - boundaryType="m_flow") annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=180, - origin={32,0}))); - Adsorbent adsorbent( - vleFluidType=sim.vleFluidType1, - redeclare model AdsorbentAdsorbateModel = - Media.AdsorbentAdsorbate.AQSOAZ02WaterGoldsworthy, - massAdsorbent=5, - xInitial=0.25, - initial_x=true, - pInitial(displayUnit="kPa") = 100, - TInitial=298.15) - annotation (Placement(transformation(extent={{-11,-12},{11,12}}))); - - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary_Losses1( - Q_flowFixed=0, - boundaryType="T", - TFixed=453.15) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={0,42}))); - - Modelica.Blocks.Sources.Step stepVLEBoundary1( - height=-0.003, - offset=0.003, - startTime=200) - annotation (Placement(transformation(extent={{-55,-3},{-45,7}}))); - HeatTransfer.HeatTransfer heatTransfer(redeclare model HeatTransfer = - HeatTransfer.HeatTransferPhenomena.ConstantAlphaA (constantAlphaA=100), - n=1) annotation (Placement(transformation( - extent={{-8,-4},{8,4}}, - rotation=90, - origin={0,26}))); -equation - connect(adsorbent.vlePortB, vleBoundary2.port) annotation (Line( - points={{7.92,0},{7.92,0},{32,0}}, - color={153,204,0}, - thickness=0.5)); - connect(vleBoundary1.port, adsorbent.vlePortA) annotation (Line( - points={{-30,0},{-30,0},{-7.92,0}}, - color={153,204,0}, - thickness=0.5)); - connect(vleBoundary1.m_flow_in, stepVLEBoundary1.y) - annotation (Line(points={{-34,2},{-44.5,2}}, color={0,0,127})); - connect(heatBoundary_Losses1.heatPort, heatTransfer.heatPortB[1]) annotation ( - Line( - points={{0,42},{0,38},{0,34}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransfer.heatPortA, adsorbent.heatPortB) annotation (Line( - points={{0,18},{0,7.2}}, - color={204,0,0}, - thickness=0.5)); - annotation ( - Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ - 100,100}})), - experiment(StopTime=1000), - __Dymola_experimentSetupOutput, - Documentation(info="<html> - <p> - This model is a cell model combining adsorbent and adsorbate. This cell model consists of an energy and a mass balance, combined with equilibrium data for the adsorbent/adsorbate working pair - (<a href=\"modelica://SorpLib.Media.Functions.CharCurve1Arctan\">SorpLib.Media.SorbentWater.Partial.PartialSorbentWater</a>). <br> - For a cell, a lumped model approach is used with equal temperature of adsorbent/adsorbate. - By combining more cells with a finite volume approach, a distributed adsorbent model can be built, with a spatial loading and temperature distribution. - To create a full adsorber, this adsorbent cell model can be connected to some kind of heat exchanger model. - </p> - <h4>Main equations</h4> - <p> - The main equations are an energy and a mass balance.<br> - Mass balance: - <p align=\"center\"> - <i><code>ẋ</code></i> = 1 / <i>m</i><sub>sor</sub> * (<i><code>ṁ</code></i><sub>ad,in</sub> - <i><code>ṁ</code></i><sub>ad,out</sub>) - </p> - where <i>x</i> is the loading of the adsorbent defined as <i>x = m</i><sub>ad</sub> / <i>m</i><sub>sor</sub>. <i>m</i><sub>sor</sub> is the mass of dry adsorbent and <i>m</i><sub>ad</sub> is the mass of adsorbate. <br> - Energy balance: - <p align=\"center\"> - (<i>c</i><sub>sor</sub> + <i>x</i> <i>c</i><sub>ad</sub>) <i><code>Ṫ</code></i> + <i>u</i><sub>ad</sub> <i><code>ẋ</code></i> = - 1 / <i>m</i><sub>sor</sub> * (<i><code>ṁ</code></i><sub>ad,in</sub> * <i>h</i><sub>in</sub> - <i><code>ṁ</code></i><sub>ad,out</sub> * <i>h</i><sub>out</sub> + <code>∑</code> <i>Q</i> ) - </p> - where <i>c</i> is the specific heat capacity, <i>u</i><sub>ad</sub> is the specific internal energy of the adsorbate at the current loading and temperature, - <i>h</i> is the specific enthalpy of the incoming and outflowing adsorbate strem, and <i>Q</i> is the heat flow. <br> - The specific enthalpy of the incoming adsorbate stream is determined by the component, where the adsorbate is coming from (normally the evaporator). - The specific enthalpy of the outflowing enthalpy is set the saturation enthalpy of adsorbate in vapour state. - </p> - <h4>Assumptions and limitations</h4> - <p> - The model uses the following main assumptions: - <ul> - <li>All adsorbate is in adsorbed state.</li> - <li>Adsorbent and adsorbate have the same temperature.</li> - <li>Note: the pressure at the VLE ports is set to the equilibrium pressure of the equilibrium model. --> A mass transfer model has to be connected to the adsorbent model. - </ul> - </p> - <h4>Typical use and important parameters</h4> - <p> - The adsorbent cell model is at the heart of all adsorption models: closed adsorber (adsorption heat pumps and chiller) and open adsorber (desiccant). - </p> - <h4>Dynamics</h4> - <p> - The adsorbent model has two differential states: the loading <i>x</i> and the temperature <T>. - </p> - <h4>Author Information</h4> - <p> - <ul> - <li> - November 18, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end TestAdsorbent; diff --git a/SorpLib/Components/Cells/Adsorbent/Testers/package.mo b/SorpLib/Components/Cells/Adsorbent/Testers/package.mo deleted file mode 100644 index 33178e9e414fea10716c57a13e8b9a5fe2c33fe2..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Adsorbent/Testers/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.Cells.Adsorbent; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - -end Testers; diff --git a/SorpLib/Components/Cells/Adsorbent/Testers/package.order b/SorpLib/Components/Cells/Adsorbent/Testers/package.order deleted file mode 100644 index 7b237832271b071e18a631b5bce72da2b4111e5c..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Adsorbent/Testers/package.order +++ /dev/null @@ -1 +0,0 @@ -TestAdsorbent diff --git a/SorpLib/Components/Cells/Adsorbent/package.mo b/SorpLib/Components/Cells/Adsorbent/package.mo deleted file mode 100644 index 6223a3687a181ce24190a7486600a00b48ee170e..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Adsorbent/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.Cells; -package Adsorbent -extends SorpLib.Internals.ClassTypes.ComponentPackage; - - -end Adsorbent; diff --git a/SorpLib/Components/Cells/Adsorbent/package.order b/SorpLib/Components/Cells/Adsorbent/package.order deleted file mode 100644 index 4a6fffe7ff7bdfab5ab342bb4431653281a16f4d..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Adsorbent/package.order +++ /dev/null @@ -1,2 +0,0 @@ -Adsorbent -Testers diff --git a/SorpLib/Components/Cells/Gas/Gas.mo b/SorpLib/Components/Cells/Gas/Gas.mo deleted file mode 100644 index a114a31f8e37bd93af8e0d815fc6b2d2614012bf..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/Gas.mo +++ /dev/null @@ -1,343 +0,0 @@ -within SorpLib.Components.Cells.Gas; -model Gas - - /*********************** SIM ***********************************/ - - inner parameter TILMedia.GasTypes.BaseGas gasType=sim.gasType1 "Gas type" - annotation (Dialog(tab="SIM", group="SIM"), choices(choice=sim.gasType1 - "Gas 1 as defined in SIM", choice=sim.gasType2 - "Gas 2 as defined in SIM", choice=sim.gasType3 - "Gas 3 as defined in SIM")); - parameter TILMedia.VLEFluidTypes.BaseVLEFluid vleFluidType=sim.vleFluidType1 - "VLE fluid type" annotation (Dialog(tab="SIM", group="SIM"), choices( - choice=sim.vleFluidType1 "VLE Fluid 1 as defined in SIM", - choice=sim.vleFluidType2 "VLE Fluid 2 as defined in SIM", - choice=sim.vleFluidType3 "VLE Fluid 3 as defined in SIM")); - -protected - outer TIL.SystemInformationManager sim "System information manager"; - - TIL.Internals.SimPort simPort; - - /********************* Connectors *****************************/ - -public - TIL.Connectors.GasPort gasPortA(m_flow(final start=m_flowStart), final - gasType=gasType) annotation (Placement(transformation(extent={{-110, - -10},{-90,10}}, rotation=0), iconTransformation(extent={{-110, - -10},{-90,10}}))); - TIL.Connectors.GasPort gasPortB(m_flow(final start=-m_flowStart), final - gasType=gasType) annotation (Placement(transformation(extent={{90,-10}, - {110,10}}, rotation=0), iconTransformation(extent={{88,-10},{108, - 10}}))); - - TIL.Connectors.VLEFluidPort vlePort(final vleFluidType=vleFluidType, - final h_limit=-1e6) annotation (Placement(transformation( - extent={{-70,-110},{-50,-90}}), - iconTransformation(extent={{-70,-110},{-50, - -90}}))); - - TIL.Connectors.HeatPort heatPortA annotation ( - Placement(transformation(extent={{-10,-110},{10,-90}}),iconTransformation( - extent={{-10,-110},{10,-90}}))); - TIL.Connectors.HeatPort heatPortB annotation (Placement( - transformation(extent={{-10,90},{10,110}}), iconTransformation(extent={{-10,90}, - {10,110}}))); - - /************************ Gas *************************/ - - TILMedia.Gas_ph gas( - final gasType=gasType, - final p=p, - final h=h, - final xi=xi, - final computeTransportProperties = pressureDropModel.computeTransportProperties or computeTransportProperties) "Gas properties" - annotation (Placement(transformation(extent={{30,-12},{50,8}},rotation=0))); - - TILMedia.VLEFluid_pT vaporVLE_outflow( - final vleFluidType=vleFluidType, - final p=gas.p_i[1], - final T=gas.T) "Conversion of enthalpy from gas to vle fluid" - annotation (Placement(transformation(extent={{-50,-80},{-30,-60}}))); - - TILMedia.VLEFluid_ph vaporVLE_instream( - final vleFluidType=vleFluidType, - final p=vlePort.p, - final h=inStream(vlePort.h_outflow)) "Calculation of temperature of instream vapor" - annotation (Placement(transformation(extent={{-90,-80},{-70,-60}}))); - - TILMedia.Gas_pT vaporGas_instream( - final gasType=gasType, - final p=p, - final T=vaporVLE_instream.T) "Conversion of enthalpy from vle fluid to gas" - annotation (Placement(transformation(extent={{-70,-52},{-50,-32}}))); - - Modelica.SIunits.Pressure p(final start=pInitial, fixed=fixedInitialPressure) - "Pressure in gas cell"; - - Modelica.SIunits.SpecificEnthalpy h(final start=hInitial) "Specific enthalpy of gas"; - - Modelica.SIunits.MassFraction xi[gasType.nc - 1](final start=xiInitial) - "Composition of gas"; - - Modelica.SIunits.SpecificEnthalpy h_vaporGas "Specific enthalpy vle fluid"; - - Modelica.SIunits.Mass massGas; - - Real drhodt(unit="kg/(m3.s)") "Derivative of density by time"; - - inner TILMedia.Internals.PropertyRecord properties( - final d=gas.d, - final h=gas.h, - final p=gas.p, - final s=gas.s, - final T=gas.T, - final cp=gas.cp, - final transp=gas.transp); - - /************************ Pressure drop *************************/ - - replaceable model PressureDropModel = - PressureDropCorrelations.Partial.PartialPressureDrop - constrainedby PressureDropCorrelations.Partial.PartialPressureDrop "Pressure drop model" - annotation (choices(choice(redeclare model - PressureDropModel = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.ZeroPressureDrop), - choice(redeclare model PressureDropModel = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.ConstantResistanceCoefficient)), Dialog(group="Pressure drop model")); - - PressureDropModel pressureDropModel "Pressure drop" - annotation (Placement(transformation(extent={{-30,-10},{-10,10}}))); - - inner Modelica.SIunits.MassFlowRate mdotHydraulic - "Hydraulic mass flow rate"; - - /****************** Geometry *******************/ - - inner parameter Geometry.CellGeometry cellGeometry "cell geometry" annotation (Dialog(group="Geometry")); - - /********************* Initialization ********************************/ - - parameter Modelica.SIunits.Temperature TInitial - "Initial temperature of gas" annotation (Dialog(group="Initial Values", tab="Start and Initialization")); - parameter Modelica.SIunits.MassFraction[gasType.nc - 1] xiInitial=gasType.defaultMixingRatio[1:end - 1]/sum(gasType.defaultMixingRatio) - "Initial composition of gas" annotation (Dialog(group="Initial Values", tab="Start and Initialization")); - parameter Modelica.SIunits.Pressure pInitial - "Initial pressure in gas cell" annotation (Dialog(group="Initial Values", tab="Start and Initialization")); - final parameter Modelica.SIunits.SpecificEnthalpy hInitial= - TILMedia.GasFunctions.specificEnthalpy_pTxi( - gasType, - pInitial, - TInitial, - xiInitial); - parameter Boolean fixedInitialPressure=true - "If true, initial pressure is fixed" annotation (Dialog(group="Initial Values", tab="Start and Initialization")); - parameter Modelica.SIunits.MassFlowRate m_flowStart=0.2 - "Start mass flow rate for iteration" annotation (Dialog(group="Start Values", tab="Start and Initialization")); - - /*******************Summary**********************/ - - inner parameter Boolean includeDefaultSummary=true - "include default entries in summary" - annotation (Dialog(tab="Advanced", group="Summary")); - - parameter Boolean generateEventsAtFlowReversal=false "If true, events are generated at flow reversal" annotation(Evaluate=true, Dialog(tab="Advanced", group="Event-Handling")); - - parameter Boolean computeTransportProperties=false "If true, tranport properties are calculated in the gas object" annotation(Dialog(tab="Advanced", group="Transport properties")); - - parameter String HydraulicMassFlowPosition="gas port B" "Position of hydraulic mass flow of gas cell" annotation(Evaluate=true, Dialog(tab="Advanced", group="Hydraulic mass flow position"), - choices( - choice="gas port A" "hydraulic mass flow at gas port A", - choice="gas port B" "hydraulic mass flow at gas port B")); - -protected - record Summary - extends TIL.Internals.ClassTypes.Record; - - Modelica.SIunits.MassFlowRate m_flow_A if include; - Modelica.SIunits.MassFlowRate m_flow_B if include; - Modelica.SIunits.MassFlowRate m_flow_vle if include; - Modelica.SIunits.SpecificEnthalpy h_A if include; - Modelica.SIunits.SpecificEnthalpy h_B if include; - Modelica.SIunits.SpecificEnthalpy h_vle if include; - Modelica.SIunits.Pressure p_A if include; - Modelica.SIunits.Pressure p_B if include; - Modelica.SIunits.Pressure p_vle if include; - Modelica.SIunits.Temperature T if include; - Modelica.SIunits.Pressure p if include; - Modelica.SIunits.MassFraction xi[gasType.nc-1] if include; - - protected - outer parameter Boolean includeDefaultSummary; - parameter Boolean include=includeDefaultSummary; - outer parameter TILMedia.GasTypes.BaseGas gasType; - - end Summary; - - replaceable record SummaryClass = Summary; - -public - SummaryClass summary( - m_flow_A=gasPortA.m_flow, - m_flow_B=gasPortB.m_flow, - m_flow_vle=vlePort.m_flow, - h_A=noEvent(actualStream(gasPortA.h_outflow)), - h_B=noEvent(actualStream(gasPortB.h_outflow)), - h_vle=noEvent(actualStream(vlePort.h_outflow)), - p_A=gasPortA.p, - p_B=gasPortB.p, - p_vle=vlePort.p, - T=gas.T, - p=p, - xi=xi) - annotation (Placement(transformation(extent={{66,-88},{86,-68}}, - rotation=0))); - -initial equation - - h=hInitial; - - xi=xiInitial; - -equation - - // simport setup - connect(sim.fluidPort[vleFluidType.ID], simPort.vleFluidPort); - simPort.vleFluidMass = massGas*xi[1]; - simPort.vleFluidVolume = cellGeometry.volume; - - massGas=cellGeometry.volume*gas.d; - - // Fluid ports - gasPortA.h_outflow=h; - gasPortB.h_outflow=h; - - gasPortA.xi_outflow=xi; - gasPortB.xi_outflow=xi; - - vlePort.h_outflow=vaporVLE_outflow.h; - - heatPortA.T=gas.T; - heatPortB.T=gas.T; - - vlePort.p=gas.p_i[1]; - - p=(gasPortA.p+gasPortB.p)/2; - - if HydraulicMassFlowPosition=="gas port A" then - mdotHydraulic=-gasPortA.m_flow; - else - mdotHydraulic=gasPortB.m_flow; - end if; - - // Momentum balance - gasPortB.p-gasPortA.p=pressureDropModel.pressureDrop; - - // Mass balance - cellGeometry.volume*drhodt=gasPortA.m_flow+gasPortB.m_flow+vlePort.m_flow - "Moist gas mass balance"; - - drhodt=gas.drhodh_pxi*der(h)+gas.drhodp_hxi*der(p)+gas.drhodxi_ph*der(xi); - - if (generateEventsAtFlowReversal) then - massGas*der(xi) = - gasPortA.m_flow*actualStream(gasPortA.xi_outflow) - gasPortA.m_flow*xi + - gasPortB.m_flow*actualStream(gasPortB.xi_outflow) - gasPortB.m_flow*xi + - vlePort.m_flow*cat(1,{1},zeros(gasType.nc-2)) - vlePort.m_flow*cat(1,{xi[1]},zeros(gasType.nc-2)) - "Vapor mass balance"; - - // Energy balance - massGas*der(h) = - gasPortA.m_flow*actualStream(gasPortA.h_outflow) - gasPortA.m_flow*h + - gasPortB.m_flow*actualStream(gasPortB.h_outflow) - gasPortB.m_flow*h + - vlePort.m_flow*h_vaporGas - vlePort.m_flow*h + - cellGeometry.volume*der(p) + heatPortA.Q_flow + heatPortB.Q_flow; - - h_vaporGas=Modelica.Fluid.Utilities.regStep(vlePort.m_flow, vaporGas_instream.h, gas.h_i[1], 1e-6); - else - massGas*der(xi) = - gasPortA.m_flow*noEvent(actualStream(gasPortA.xi_outflow)) - gasPortA.m_flow*xi + - gasPortB.m_flow*noEvent(actualStream(gasPortB.xi_outflow)) - gasPortB.m_flow*xi + - vlePort.m_flow*cat(1,{1},zeros(gasType.nc-2)) - vlePort.m_flow*cat(1,{xi[1]},zeros(gasType.nc-2)) - "Vapor mass balance"; - - // Energy balance - massGas*der(h) = - gasPortA.m_flow*noEvent(actualStream(gasPortA.h_outflow)) - gasPortA.m_flow*h + - gasPortB.m_flow*noEvent(actualStream(gasPortB.h_outflow)) - gasPortB.m_flow*h + - vlePort.m_flow*h_vaporGas - vlePort.m_flow*h + - cellGeometry.volume*der(p) + heatPortA.Q_flow + heatPortB.Q_flow; - - h_vaporGas=noEvent(Modelica.Fluid.Utilities.regStep(vlePort.m_flow, vaporGas_instream.h, gas.h_i[1], 1e-6)); - end if; - -annotation (Icon(coordinateSystem(extent={{-100,-100},{100,100}}, - preserveAspectRatio=false), - graphics={Bitmap( - extent={{-100,100},{100,-100}}, - imageSource= - "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAACXBIWXMAAAsTAAALEwEAmpwYAAABhElEQVR42u3UsQ3AMAhFQZPJ2JzRSEvhynKkFHcd7dcTawEAcFvMo6oswpnMjIh9WN1tIM6/1AjrMQdfEBbCQlgIC4SFsBAWCAthISwQFsJCWCAshIWwQFgIC2GBsBAWwgJhISyEBcJCWAgLhIWwEBYIC2EhLBAWwkJYICyEhbBAWAgLYYGwEBbCAmEhLIQFwkJYCAuEhbAQFggLYSEsEBbCQlggLISFsEBYCAthgbAQFsICYSEshAXCQlgIC4SFsBAWCAthISwQFsJCWCAshIWwEBYIC2EhLBAWwkJYICyEhbBAWAgLYYGwEBbCAmEhLIQFwkJYCAuEhbAQFggLYSEsEBbCQlggLISFsEBYCAthgbAQFsICYSEshAXCQlgIC4SFsBAWCAthISwQFsJCWCAshIWwQFgIC2GBsBAWwgJhISyEBcJCWAgLhIWwEBYIC2EhLBAWwkJYICyEhbBAWAgLYSEsEyAshIWwQFgIC2GBsBAWwgJhISyEBcJCWAgLAAD4qReb+Qd/FUGUbAAAAABJRU5ErkJggg==", - fileName="modelica://TIL/Images/CellUni.png"), - Text( - extent={{-80,40},{80,-40}}, - lineColor={0,0,0}, - fillColor={255,255,255}, - fillPattern=FillPattern.Solid, - textString="Gas")}), - Diagram(coordinateSystem(extent={{-100,-100},{100,100}}, - preserveAspectRatio=false)), - Documentation(info="<html> - <p> - This model represents an ideal gas cell, which may contain a pure gas or a gas mixture with a condensing component such as moist air. For a cell, a lumped model approach is used with an uniform enthalpy, pressure and composition within the cell. By combining more cells with a finite volume approach, a distributed gas channel can be built, with a spatial enthalpy, pressure and composition distribution. The model has five ports: two gas ports to exchange gas, a VLE port to add/remove the condensing component, and two heat ports to exchange heat with connected components. <br> - - </p> - <h4>Main equations</h4> - <p> - <p>Mass balance: </p> - <p align=\"center\"><i>V</i> <i>d<code>ρ</code>/dt</i> = <i><code>ṁ</code></i><sub>gas,in</sub> + <i><code>ṁ</code></i><sub>gas,out</sub> + <i><code>ṁ</code></i><sub>VLE</sub> </p> - <p>where <i>V</i> is the volume, <i>ρ</i> is the density of the gas, and <i><code>ṁ</code></i><sub>gas,in</sub>, <i><code>ṁ</code></i><sub>gas,out</sub> and <i><code>ṁ</code></i><sub>VLE</sub> are the mass flow rates at the gas ports and at the vle port.</p> - <p>The derivative <i>d<code>ρ</code>/dt</i> can be expressed by the total differential: </p> - <p align=\"center\"><i>d<code>ρ</code>/dt</i> = <i>d<code>ρ</code>/dh</i> <i>dh/dt</i> + <i>d<code>ρ</code>/dp</i> <i>dp/dt</i> + <i>d<code>ρ</code>/dxi</i> <i>dxi/dt</i> </p> - <p>where <i>h</i> is the specific enthalpy, <i>p</i> is the pressure, and <i>xi</i> is the mass fraction of the condensing component in the gas cell. </p> - <p align=\"center\"> <i>V <code>ρ</code></i> <i>dxi/dt</i> = <i><code>ṁ</code></i><sub>gas,in</sub> (<i>xi</i><sub>gas,in</sub> - <i>xi</i>) - <i><code>ṁ</code></i><sub>gas,out</sub> (<i>xi</i><sub>gas,out</sub> - <i>xi</i>) + <i><code>ṁ</code></i><sub>vle</sub> (1 - <i>xi</i>) </p> - <p>Energy balance: </p> - <p align=\"center\"> <i>V <code>ρ</code></i> <i>dh/dt</i> = <i><code>ṁ</code></i><sub>gas,in</sub> (<i>h</i><sub>gas,in</sub> - <i>h</i>) - <i><code>ṁ</code></i><sub>gas,out</sub> (<i>h</i><sub>gas,out</sub> - <i>h</i>) + <i><code>ṁ</code></i><sub>vle</sub> (<i>h</i><sub>vle</sub> - <i>h</i>) + <i>V</i> <i>dp/dt</i> + <code>∑</code> <i>Q</i> </p> - <p>where <i>h</i><sub>gas,in</sub>, <i>h</i><sub>gas,out</sub>, and <i>h</i><sub>vle</sub> are the specific enthalpies of incoming/outflowing streams. </p> - <p>Momentum balance: </p> - <p align=\"center\"> <i>p</i><sub>in</sub> - <i>p</i><sub>out</sub> = <i><code>Δ</code>p</i> </p> - <p align=\"center\"> <i>p</i> = (<i>p</i><sub>in</sub> + <i>p</i><sub>out</sub>) / 2 </p> - <p>where <i>p</i><sub>in</sub>, and <i>p</i><sub>out</sub> are the pressures at the gas ports. <i><code>Δ</code>p</i> is the pressure drop, which is calculated by an internal selectable pressure drop model. </p> - The pressure at the vle port is set equal to the partial pressure of the condensing component in the gas mixture. To consider different reference states fot the specific enthalpies of gas and vle models the specific enthalpies are converted into each other using temperature and pressure. - </p> - - <h4>Assumptions and limitations</h4> - - <p> - The model uses the following main assumptions: - <ul> - <li>The gas / gas mixtrue within the cell is ideally mixed with a uniform enthalpy, pressure and composition.</li> - <li>For the calculations of the gas properties, the ideal gas law is assumed.</li> - <li>For the simple pressure drop models, such as zero pressure drop and constant pressure drop, there is no correlation between mass flow rate and pressure drop. Thus, a mass flow rate has to be given by a connected model, e.g. by a mass flow boundary.</li> - </ul> - </p> - - <h4>Typical use and important parameters</h4> - <p> - <p>For open adsorption systems the gas cell represents the moist air. </p> - - <p>With the parameter hydraulicMassFlowPosition in the advanced settings, the position of the hydraulic mass flow rate can be chosen for pressure drop calculations. For numerical reasons the hydraulic mass flow rate should be chosen at the opposite port of the mass flow boundary. If two mass flow boundaries or two pressure boundaries are used, both options work. </p> - </p> - <h4>Dynamics</h4> - <p> - The model has three states: the specific enthalpy <i>h</i>, the pressure <i>p</i> and the mass fraction of the condensing component <i>xi</i>. - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>November 23, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end Gas; diff --git a/SorpLib/Components/Cells/Gas/Geometry/CellGeometry.mo b/SorpLib/Components/Cells/Gas/Geometry/CellGeometry.mo deleted file mode 100644 index 3b8da0f514582745c0c5bcb99e549b05d67dad18..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/Geometry/CellGeometry.mo +++ /dev/null @@ -1,28 +0,0 @@ -within SorpLib.Components.Cells.Gas.Geometry; -record CellGeometry - extends SorpLib.Internals.ClassTypes.Record; - - parameter Modelica.SIunits.Length length( start=1) "Length of cell"; - - parameter Modelica.SIunits.Diameter hydraulicDiameter(start = 1) "Hydraulic diameter of cell"; - - parameter Modelica.SIunits.Area flowCrossSection(start = 1) "Cross-sectional area of cell"; - - parameter Real psi(final unit="1", start=1, min=0, max=1) "Void percentage gas channel (1 = free channel)"; - - final parameter Modelica.SIunits.Volume volume = flowCrossSection*length*psi "volume of cell"; - - annotation (Documentation(info="<html> - <p> - This record containes all information necessary to describe a gas cell. <br> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 12, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end CellGeometry; diff --git a/SorpLib/Components/Cells/Gas/Geometry/package.mo b/SorpLib/Components/Cells/Gas/Geometry/package.mo deleted file mode 100644 index b810365feaa648e1cf27203fd127db515ee8a2d4..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/Geometry/package.mo +++ /dev/null @@ -1,11 +0,0 @@ -within SorpLib.Components.Cells.Gas; -package Geometry -extends SorpLib.Internals.ClassTypes.RecordPackage; - - - - - -annotation (Documentation(info="<html> -</html>")); -end Geometry; diff --git a/SorpLib/Components/Cells/Gas/Geometry/package.order b/SorpLib/Components/Cells/Gas/Geometry/package.order deleted file mode 100644 index bf1521efd9d8d0135489a3805daed2fb40b0b6e3..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/Geometry/package.order +++ /dev/null @@ -1 +0,0 @@ -CellGeometry diff --git a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/ConstantResistanceCoefficient.mo b/SorpLib/Components/Cells/Gas/PressureDropCorrelations/ConstantResistanceCoefficient.mo deleted file mode 100644 index 89d5dbfe6cc6692a3f5235e7e9f10f8dde6b111b..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/ConstantResistanceCoefficient.mo +++ /dev/null @@ -1,43 +0,0 @@ -within SorpLib.Components.Cells.Gas.PressureDropCorrelations; -model ConstantResistanceCoefficient - "Pressure drop correlation with constant resistance coefficient" - extends Partial.PartialPressureDrop( - final computeTransportProperties=true); - - outer parameter Geometry.CellGeometry cellGeometry "cell geometry"; - - outer TILMedia.Internals.PropertyRecord properties "Fluid property record"; - - outer Modelica.SIunits.MassFlowRate mdotHydraulic - "Hydraulic mass flow rate"; - - parameter Real f(final unit="1")=2 "Resistance coefficient"; - -equation - pressureDrop=(cellGeometry.length/cellGeometry.hydraulicDiameter)/(2*properties.d*cellGeometry.flowCrossSection^2)*f*TIL.Utilities.Numerics.squareFunction(mdotHydraulic); - annotation (Documentation(info="<html> -<p> - This model calculates the pressure drop with a constant resistance coefficient according to the VDI Wärmeatlas (2013). The sign of the pressure drop is automatically determined by the sign of the hydraulic mass flow rate. The hydraulic mass flow rate is defined as outer variable and thus taken from the overlying model level. The fluid properties record is also defined as outer object and taken from the overlying model level. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> <i><code>Δ</code>p</i> = sgn(<i><code>ṁ</code></i><sub>hydraulic</sub>) <i>L</i> / <i>D</i> <i>f</i> / (2 <i><code>ρ</code></i> <i>A</i><sup>2</sup>) <i><code>ṁ</code></i><sub>hydraulic</sub><sup>2</sup> </p> -<p>where <i><code>Δ</code>p</i> is the pressure drop, <i><code>ṁ</code></i><sub>hydraulic</sub> is the hydraulic mass flow rate, <i>L</i> is the hydraulic length, <i>D</i> is the hydraulic diameter, <i>f</i> is the resistance coefficient, <i><code>ρ</code></i> is the fluid density and <i>A</i> is the cross sectional area. </p> -</p> - -<h4>References</h4> -<ul> -<li>VDI e.V., VDI Wärmeatlas 11., bearbeitete und erweiterte Auflage, Chapter L1, Darmstadt: Springer Berlin Heidelberg, 2011. </li> -</ul> - -<h4>Author Information</h4> -<p> - <ul> - <li> - November 28, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end ConstantResistanceCoefficient; diff --git a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/Partial/PartialPressureDrop.mo b/SorpLib/Components/Cells/Gas/PressureDropCorrelations/Partial/PartialPressureDrop.mo deleted file mode 100644 index 6c289eb57881e2695fb190ae4c3b27550766a744..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/Partial/PartialPressureDrop.mo +++ /dev/null @@ -1,29 +0,0 @@ -within SorpLib.Components.Cells.Gas.PressureDropCorrelations.Partial; -partial model PartialPressureDrop - - Modelica.SIunits.Pressure pressureDrop; - - parameter Boolean computeTransportProperties; - - annotation (Icon(graphics={Bitmap(extent={{-100,-100},{100,100}}, - imageSource= - "iVBORw0KGgoAAAANSUhEUgAAAdwAAAHdCAYAAAC3/8hQAAAAAXNSR0ICQMB9xQAAAAlwSFlzAAAXEgAAFxIBZ5/SUgAAABl0RVh0U29mdHdhcmUATWljcm9zb2Z0IE9mZmljZX/tNXEAAD/ESURBVHja7Z1viFzl2f8XKRJEZBGRICKLiAQRWUQkiJS8KnnxvEiyWZoULAs+ilaQCPIYJC9iELLIMjsHxZAG3CqEYGuJrTwsSGsIfXxCEUyxhNQ+QiyWLrU0+YlIbGnZ335ndpIzZ86ZOTNz7jPXfd+fGz4IG3d39vz7nuu6r+t7Tb300ktTAFAPU/PJ1qn5xo5r7F0+3MNccnRqb/PM2Mw3T/f87PnGwrXfvX9phnMCUOP9z0EAGFdEF6dbAjbX2NUWtuRYl/DNNa9u/HfdNHPNtWufd09yalP4D7b+rt3Jds4zAIILMAFBbS5vCul580JarShf7Yqc5xsH2tHy0izXCQCCCzCkuC7NTs0n+zaF9cxm5BePqI7HxetinOzciIy3cU0BILhA1LoZtSYHN0R1ZUMoztUhSrc8/fb69DPvtNj6wvvrM0fOdbGtcWF99vgXlXD/q5/1/Hz9zs7vv/mJk3UJ8ZnWMe6kqDeOPdcgILgAoV7oG9HWxgP/qfaDv3mpSkH5zg+OtQTstufea4naPYsfXxO9h1a+XN/x7rp5vvvzf3WJdUegO+LsID19qbVXrLQ0e8SA4AL4HMFuRq97m6sbXKkqMpUI3f3yRy1RevDEmhdiWrUoP/D6563jcOehs1VHymeupaOJggHBBTB4ET95fEvrIX29nWbsaPWuwx+20ru+RKgW0AuIjlknMr7xsRPj7wm30v1qZUq2cq0DggswiQtXKWKlI9sR7EgP9Jsef+taGliR2yOnvkE4K+bRn37bOrbKCnT2j8dIQ59vvVSRggYEF8DhhdoqclL1cHJslD3YG77/2rWUsARA6VEEcbLRsPa69cIzYiR8ZXMPmOgXEFyA8UV2abZd2Tp8BbGiV0VU977yCWlhD3j4zcutdPQdL37QOncjR7/0BAOCCzBEqlgPziGjWD2kVcSjgh6lMREx/1PROpfaSx+6KKt97SwjvoDgAmQvwv1LM5sVxReHSRErHakIdvvJrxCpwNH+uiLg259fbRW2Ib6A4AKUThcnWzf7Ys+PEsUiQuwBqxBL7VqILyC4AD0iuzjdEtkhWneIYqFM+vm+5qetPfvS0a/Et13xjP0kILgQktDKhKLl8HS1rMgqfcheLIyCLC2HEl8V5ana+cnjW7hfAcEFX1PGB8sWP6llR5EsvbBQFWr9UuSrfV/t+ZdqNVLbGVEvILjgidDuK2tGgchCneKrrImyJ0S9gOCCvxeRWnnahhRrZQqfEFmY9J6vxLdkwRVRLyC4YCGabewoE80qnac9tdjM/sE+MtyQ2UZJt6szU3ONXdz7gOBCnUK7UKadpxPNUvwEPqD93luffbdshfNTpJsBwQU3F0prIk/jwKAiKFWGEs2Cz6gFTT2+WxbeKJFubo0TxMsZEFyoIppNtrYeKgNmysp+T/tiDAWAkJDJysBCK7W7qe2NfV5AcGGkC6Nltzi4d1YpOJyfIIaoV5mbEu1Fq6pt4BkCCC6Ui2gltAP2sfTwUcEJD2OICVXXa6BCCVONM1hIAoILfVLHzeV+Ea0eMnrY0NIDsaOtE83zHbjPO988jfACggulhVYPFT1c2J8F6EW1CwNHCO5JTmmbhmcOggtRCu3i9KBiKAmtHiY8VAEGIw/ngcKr7RqEF8EFhBahBahBeNvZpGXaiRBcCPlkt+fPFtovym0HoQWoU3g3Xn4x0EBwIaCTvDvZ3s8ZSkLLHi2Auz3evsVVLecqLCMRXPA8fZxsbRVrILQA9oWXViIEFzw8qbJhVKqqoPJY7T2yrkNoAepH/uL9hyUkx1RrwbMMwQXz+7SNXf32aWVYQR8twGTRQA/1tPdxrroi73KeaQgumEwfL822UlIFQqvZnwwUALCF3NoGTCi6ODWf7OQZh+CClfTxXHK03z6txo7xcAOwi/zINc6yb/8uaWYEFyYZ1SY7W2/ABUPfZ46cY58WwCNUxNjHp1lp5gWefQgu1Cq0i9P9BgxonBj7tAD+7u/eeejsgIlEmGYguFCD2DYWioqilJJiVB5AGDy08mWr9qJ4Bm9ykGciggtu0sdbW2+2BW+9qngkfQwQHmrhK6xmnm+eY/A9ggtVnqSNN9minlqqjwHCR1tEfauZVTiJRSSCC2NGtXqDLSiK0psvDyOAeJBbVR/TjItEuwgujBTVNnYVTfTRm+72k1/xAAKIEBVVycCmcG8XwwwEF0qekFZfbX4FstoFmOYDAEIFkn28malkRnCh78nQVJ+CvlpFtXqz5UEDAB1UKHnHix/06dvFpQrBhdKFUdqrVTM8DxcA6BftFhtmJMcoqEJw4aX+7T7qq1UvHg8UABjEgErmi4z+Q3BjF9udRYVRShPRVwsAw1LYt0tBFYIb7YHXvNqCwqj7X/2MBwcAjIwyY4XDEPYkpxiEgOBGEtUuTheN0Zt+5h08kAGgEgYUVNGzi+AGfrBVhTzXvJR3A2BiAQAu6FNQdUX9/jybEdzwDvRc8lReFbJcY2aPf8GDAQCcIaOcm584WWgLyTMawQ3jAMvIQmX5BT7IpJABoK4Uc6FDlba52NdFcL0+uPuXZjai2vNUIQOAFe595ZOiKuZLtA4huJ4WRzV25LX86EK/r/kpNz4ATAxNGMsdgtBuHVrgGY7g+rVfmxPVyvcUIwsAsIC2s4oH3LOvi+D6IbZH8y7g2557Dy9kADDHnYfOFk0eWsESEsG1WxylhvKcC3fmyDlubAAwi7a5cvd1KaZCcO3t1y5O5w2KZ78WAHxB+7oF/boXVQDKsx7BtVGJnDNSTxcu/bUA4BPq182dsTvXXKOCGcGd7MFrz6+9klcc9fCbl7mBAcA7VGuSW0ylCmacqRDcyRRHNXblOUfJzQUzCwDwGXkEqNCzoIL5KTQAwa1xz7axkHchahYlZhYAEAqFFcx7lw+jBQhuDZFtfo+tnKO4QQEgNO5Z/LjIDnIZTUBw3R2sghm2TPoBgJDRjO4CO8gVtAHBrU1stzUucEMCQPAUtg0hugiua7GlxxYAYkPWtAW9uqu4UiG4FezZNlfyxFZDnbkBAQDRRXQRXMQWAMAJ8hnINciQ6GIFieBWIbZ6q0NsAQD6ulKdR3QR3LHFltF6AACILoKL2AIATER05bCXO2mIPV0Et7gaOTmWvWhufOwEYgsA0Af5LxeILoVUCG651h8iWwAARBfBRWwBAEyhwS0Fe7qYYyC4rUEEBxBbAIBq6FNIFb3oxi62C/TZAgDUJLp7k2MILmKL2AIAVEixI1W8o/0iFdtkJ2ILADAh0Z1LDiK4UYjt0uzUXPNq9gJgEAEAgBvRzR3tN5/sQ3BD/mP3L81siO0aI/YAAOpD2cMe0VXgM9/YgeAGGdkuTrfsxjJie8/ix9wQAACO0RD7nB7dKwqEENyQ/sgnj29pNV9nTvYdL37AjQAAUBMKcHLahS7F4rsch+DmWDbe+uy73AAAADVz56GzOfu5zXMxuFGFL7ZzycHsyZX92Hd//i8ufgCACXDbc+/lie5pBNfv9p992ZOqZmzZj3HRAwBMBgU8tzz9dt6e7jKC6+MftjvZnm3/UT/Yw29e5oIHAJgwGnaQ60Y13ziA4PoV2W7Ntv9gbAEAYAtZQOYaYwTaLhRmRbI24Om1BQAwz4Mn1vJ6dNcUOCG45iuSm8tZsb3r8Idc2AAARsnt0Q2wcjmwVHLvQILpZ97hggYAMI4Co9CLqAIS216PZG3Ia2OeixkAwD4KkEL2XA5EbFu2jZeyRVLaG+AiBgDwA7Vs9lQuK5DanWxDcO3s265SJAUA4D8FRVRB2D8GILbLh/FIBgAIh3tf+SRIJyq/P/xcY1f2pMi9BNtGAAC/2frC+8ENrvfb3EKjnTJOUmqk5mIFAPAbBU7yve8R3d3JdgS3/n3bM9kTMXv8Cy5UAIBAyHWi0n6up/25vvbbHsiK7cyRc1ygAACBkWuKMddcQXDr+MC7k23Zflvt23JhAgCEiQphQ+jP9evDyid5rnmefVsAgHjQfu5Nj7+VFd0rvvkte1aVnByl3xYAID5y+3P3Ns8guG72bXdkxfb251e5EAEAIkG1Oj7Pz/XWuhGfZACA+OjxW1ZNz/zSLIJbWSq5uUILEAAAFAytv+hDq5APBhf7aAECAIAOqt3JcaE6iuCOn0pew7oRAADSqIandz/XdmrZuJtUciw7cu/hNy9zsQEARI5qeG587ER2P/e85dSyV1XJd7/8ERcaAAC0yHehsjvgwK7BhTbBUwdRJtZcYAAAkKYntayq5f1LMwjuiAYXSiU/tPIlFxcAAHTxyKlv8qqWTRpiGEwlL81mvZLvOvwhFxYAAOSSW7U831hAcAcKbvNc+qDJP5OqZAAA6EeOIcaaNa9la4VSBzC4AACAYZEhRo/X8p7kFIKb90H2L81kU8kaycSFBAAAZbhn8eO8MX47EdzeVPLp9EFSfxVeyQAAMAwyR7Jq+2jFvnFn9q1E/VVcPAAAMAzqaOlJLRuZKGRlOEHXUPnbnnuPCwcAAEbizkNnTQ6rN1coRc8tAACMgzpbemwf9zaXoxbcvOEEejPhggEAgHG495VPzA03mPBwguZytlBKriFcLAAAMC6yBM6I7mqUgpvnKKWSbi4SAACoAvk49A43aOyKUHC724BwlAIAgKpREa6VNqEJVSU3dtEGBAAArtE2pZU2ocmM3su0Ad367LtcGAAA4AQNwLHQJmTCL5k2IAAAcIWVNqFJRLe0AQEAQK30jPBT0W7NUe7ETS5oAwIAgDrIaRNaDlJwiW4BAGCSqDi3J8rdnWwLT3CJbgEAwFqUO988HZTgKk/eqgojugUAAEtRbo2WjxOxcCS6BQCA2KLceqJbLBwBACDyKHciAwqwcAQAgNiiXKJbAACIjtzBBo6jXKJbAACIkp7BBo6jXKJbAACIEtkK1xnl1tZ3S3QLAADW0PCcLsHdk5zySnDzXKVmjpzj5AIAgCly3acceSy7Sifvo+8WAAB8oC6PZUcD5rvn3eIqBQAAVlF9UU+U++TxLeYFd2q+sSO7Cf3wm5c5qQAAYJLcebnzjQMeCG7zdPpDq+yaEwoAAJa56/CH2Sh3reoot1qx3Z1sy0a3KrvmZAIAgGVUZ6R6o27RbeyyK7gZowttRHMiAQDAB7a+8H42yj1vUnDzjC5Ubs1JBAAAH8g3wkh2GhTcbqOLmx5/ixMIAABe0WOEUaHdo7NWIGwcAQDAN1waYVRVLLU9a3Tx6E+/5eQBAIB3uGoRqiq6XUl/uNufX+Wkwfq+99fXf/IHO/z4AucEAAYjK+LMXu5FE4I7Nb84nS2W0pxBThr87LN1c+tHZzkvANAftQj1FE/tTrYbEFyKpaCX7/1yff3v39oT3JN/5NwAwGB6ZuXONVcmL7iZYqm7X/6IkwXrRz6yJ7Zaa99wbgBgMLnFU2M6T1VeLMVUIBDn/2ZTcEkrA0BZeoqn5pKnJie4mWIpfJNB/OcZu2JLWhkAytJTPDWm81SlxVI4S4GwWCxFWhkAhiW3eGp+abZ+wd0IrdMfQqE3JwhULPX1P20LLmllAChLT/HUGMPpxxlUcCb9IRR6c3Jg8WP7YktaGQDKklM8tVar4LYGFWTC7O0nv+LkwPqFy34ILmllAChLjvPUjvoEN5NOvuXptzkpYL5YirQyAIzCHS9+kEkrJ8fqE9xMOpneWxDWi6VIKwPAKMg9MZtWHqUnl3QyVIIvxVKklQFgFHrTysPPySWdDJXgS7FUdv3wV5w7ABhMT1p5BKtH0slQCb4US2WXpghx/gBgED1p5b3NK8OmlUknw9j4ViyVXn/6mvMHAOUYN608Vjp5+pl3OAmw/otL/gouaWUAKMu4aeWx0sn3vvIJJyFyVCz1j3/7LbiklQGgDOOmlcdKJzMZCBq/81tsSSsDwDCMk1YeZtD8AulkyPJ//89/wSWtDABlGSetPITgNk+nf8k9ix9z8CPH52Ip0soAMAoPvP55VnAvVSq4ylG3ctWpX/LQypcc/MjxvViKtDIADMt3f/6v9Ru+/1q36O5OtlUnuPONHekfvmXhDQ585IRQLEVaGQBG4dZn380OMzhQneDOJUfTP3zrC+9z0CMnhGIp0soAMAraUs0UEZ+pUHCb59M//L7mpxz0yAmlWIq0MgAMiwyfMvu4V8u0Bw0W2/1LM9l2oEd/+i0HPWJCKpYirQwAo6Ct1W7RbewaX3BpB4IMIRVLZdePL3B+AWAwdx46m00rL1cguN3tQDNHznGwI+Y//ju8Yqn00hAGzjMADGKU9qCh24EePLHGwY6Y134frth21r73Oc8A0J/c9qD9SzOjC26mHeg7PzjGgY6cEIulSCsDwCjc9tx7Q7UHDdUOdPvzqxzkiPnR2fDFlrQyAJRFA3y6Bbd5enTBzUwH2ta4wEGOmNU/xSG4pJUBoAwPv3m5Z3rQGBFu8yp2jiBCL5YirQwAo6Ct1rL7uH32b5dm2b+FDjEUS5FWBoBhydnHXRhBcBsH0j9EP5SDGy8xFEuRVgaAYbn75Y9Kj+srFtw9yan0D9EP5eDGSSzFUqSVAWBYZo9/kd3HvTi84M41L6V/iH4oBzdOYiqWIq0MAMOgftys/fHU/OJ0acHN+ieruVc/lIMbH3tW4yqWIq0MAMNy8xMnS/kqF0S3jV34J4NwUSzlk4Dr7+c6AIB+lPVVLuq/XU5/s34YBzVONLLOhYj5ss7/jWsAAPqjkbUZA4xzQ0S43fNv73/1Mw5qhBz4n+oF7O/frq9/75d+VT0rrc71AABFlJ2Pmz+wIGN4wfzbOPn1n6sXr5991v7ZP/mDP4Lb+B3XAgD058bHTmT7cXcMFtyM4cVNj7/FwYwQV8VSnQHv+i9pZQAIhTKDDPIGFjyF4QW42GfNttmsfUNaGQDCQLPiuwunkmODBTdTMIXhRZy4KJbKpmZP/pG0MgCEgWqdBhVO5QnuKgVTceOiWErpaQ1AcP17SCsDwCQoMzkor0J5Lf1N+iEczLhwUSwlt6q836WqZdLKABACMonqNzkoUzCVbGVCUNy4KpZSNJv3+3yyjSStDAD9uOXpt/s6TmUFd2f6f9Y3cxDjQob9VS8VRxX9vv/6X9LKABAGd7z4QUZwk4N9BLd7JJ++mYMYFy4qh9VzW/T7ZILhk9UjaWUAKOKexY+7BXdPcqpYcPcmx9L/s76ZgxgPrqLNQSLlYs+YtDIA1E3PqL655vliwc1YOj54Yo2DGBG/+Uv1AvXbvw7+vUc+8kdwy/w9ABAncmXMWjz2E1wsHSPFVbGUxHTQ71a7kC9p5bz2JqgHjUpUFkZbFHo51J66KOoZ7/y7UM+3vjfGc6e/WUWLqs/QsUsfF5nRZNfX/7z+7ypq1PeIQ7/lGixDr8Xj0myP4E7tTral/6ctC29w8CLCRbGUblzt0Zb5/YocfVmLH3O91MF/nml7b+vBX+ULmQZn/OJSceW87+LaeSnRPVV1TYbuaYkw4lvMrc++mxHcZF+v4GYqlPVNHLx4cFEs1RlUUAbtjZJWBomgxLAu20+Jr+/ioZdaZZJcbAkhvsPTMxs3Valc6KFMhXI8uCqWUoRS9jMope3LIq1cLTr3SvlO0gRFAl9m+8MSEjoVHFrYjlFqepj7PWR6KpVTnsppwT2Kh3KcuHgzVuQw7OfI20+yukgrj48mRlkzPlF0XXYbZFLRrNLFii4tLr04xf4y2uOpvLe52iu4e5JT6f9JE+x5KMQRXbh4Q9a0oWE/i4t9ZFeLtPLo/Ois7T17vSyqQMua0Oqe8sEKVZ8x5jTzQytfZgX3Ys4ebvMcLUHx4WIQvAR8FIMIn2bkklYe7eXOFytPRZDaarFw3JRN8clzvLOUObOcLXBFv9agwqEFj5z6hodEBLi4kbWvNOrncTEW0NUirVweFcVZTYP2E91J7ktK8H2aGZ23Ys0E9bYGJVuvCe7Uk8e3pP9REw94SISP0j4u1jiRgYuIm4fJ5JBg+bQ3n10SvLrTy4oKVeEfyiqaFBYyPUMMdifbrwtupgf3psff4mERAS6KpRQxj/OZtL/nyyKtHM7LU7+lPd26zrO2VXzK8iC6+dz+/GpuLy49uJHiqg2n36CCsviURiOtnH9tyawipDVMT/moqCjKp0Eewy5VMMdyD9x1+MPcXlx6cIk+Kl1VpN/UmuHLUpaA6+k62k7wba+2zBq1ELDsC4pPTmvjrFG6F3zk3lc+ye3FpQc3UlwUS1U1L1ZuQz49iGOsxMxDEUzISy+CLlLIvhdGWXlxscQDr3+e24vbqVBeSf+jGnd5gISLq2KpqtKrEjCfoiTfHIqqRlkNnwujhllVVi2rXiHEbMCgFUNW6OE3L+f24m7OwW2eSf+jZvohTOHiolhqmEEFZfClX1NrnDYo35EA+dgjOuqqai9XL2kh79cOWlZ6nF2R04u7lo5wu+bgSp0RpjBxVSxVdbrNpxm5saaVlSmJTTSU/h33uGkfM/alSuzQ75lMhLueFtxLmF6wzzbOUnqsys+pm9Gnh3lsaeWYRWOcwsCQ+mvHXbJyDfke0Yjb7tagxelOSrnrHxCmMJGIuUj/6W3Vl9S3qxVTWtmnKnIXa9RKW5+2SepYoRdQyc+iS1v3L81MtVQ39UVZUiFO4aYALT2ABqEiLJ8eHqGnyGT+EEv7Sr81StEPYpu/Qu7NnX7mnUyE29gx1VLd1BcVBiNOYeLiYenyLVUPeJ9WyGllnQs5LrGGz+ggtsVrXGc6y+S4Te2UreP29BelyohTeGjfycVyXeLvk2NRqGlll2KrFzYdNxmxKKOhIQdKWVtuMxpGJFzv2aqIS/dIGt+W+u5DvG9kIJWJcBd6bB1ve+49BCpAXBVLuZ576VNxTohpZb2ouRBb/UxlBPodL7UcWe1TLXPsXLi56QVXx21Q4ZbabhRZ+1B4GKrP8syRcz32jlMt1U19cesL7yNQgeGqWEo/07XAuIrMXa2Q0so69lW7ICkdO8xLmlUnpkHbKFWKrV5OFPmPsnWjlxbrwxCq7uG3wj2LH2dag5YPT7VUN/VFqTIiFRauiqXqKnjwae8wlLSyC7FVqniUB6vExtrqF2FWJbY6/lVkkHTMrRe7hVj/sK1xIWt+sYKPcgS4utkUfdTx+X0a8xbC23rVYqtjMo5waA/ZWmq0SHCrMGzR36prvsrrSMfQcqQbot2jHBu793Cbp3t8lKXKiFRYaUEXS0Utdf0NEnafls+2dVWLrX5WFf7DyhxYF1yZv4z7YqCXY1cD73UfWd3TDXG29IMn1rJuU2cQ3MBxVSWpNF+df4dPE1V8LgKpMv1Y5eB2a8VzeS8q49ZJ1LFFY9npqmq3ukmz/eRXCG5MuCqWmkQ1rk+j33xPK1chuvr+KiMWSyYoOr/Z4zVOnYHup7r2MC0XIdb9El+74M43zzEpKGBcDQCYRATn04xcLd+noYwjuvq+ql84LJ3/7NzncSxI9UJcd2RntYDKxbxhU4KrmQUIbri4aoKfVKO6T2PgQugtHEV09f+7+CyW9vHTI/rGybwoKna1X+tLtiC96qwLQXDBiwdUFePJRsUni7xQeguHEV0Xka3FVGhHcMfJIFW5vx1KWjmbqkdwwRtcFUdMcqSW0rQ+rVCGbJcRXZdiK5R2tbT0945a8auX1klPybFahFhXq2EdaMxtr+BqIzf1RZUyI1j+PyBdpV8n+aDwbUZuSJZ1/URX0ZrraN63Pfx+YjuJNHIWq6MvXVvF1k1GcNd6hs8rDEa0/MZVsZSr/blhsNaP2W+FZlmXJ7oSkDpSoz6NarQutsJq1b8MP4IVXIHghoerYikL9muuXiZcrVDSynmiqyxKXQKirQyfl16+rIitsGiXqRWa4xSCGziuiqXqGFRQBos2f/1WiJNQdB0o01CFg1RZ1DLi87L24mW1HiLbcoXggmlcFUulWyEmjXUj9mxkw3U5Ppbn4w5akyw0rPvFfNwVWmvQQMFVZRU3uL+Rh6tiqTqjGV/TYUUr1AHbdWJ1Lu6gZTVFarU1aJJth0S4MBSuCktUhWrp71SltE8rNAcdxKHc0nQeq0VzCC6CC0bTbjKOJ8U4+lLWgetzdFzNc3a5rBVJZVEthNWF4IJ5lPJ1sayOzfKtapW08uj4NA+5s5Rtsn5cEdxJCO7e5kUE139cFUupGtXi3+vbjFzSyqNj1aShaFnoV/dZcEOai5snuF3Wjg+tfMlN7hnaJ3JVVGK5j1R7ZL4s0sqj49PQCt2Hk7ZtLPvMsLosp+KH4dGffpsV3Ct4KQeAq2Ip6wUMvqUaSSsPj28Fcj6kkoXlQrRQ/JQZXhAorgqIrNusWTO0H7RIKw+PTwVTvqSSrQtuKC+mCG6AuCqW0vIhtWN16kneIq08PK5qE6peKi601KuO4FoV3LnmCoLLAym7fLFY883yj7TycLjyBa96WXJi8z07pM8WjeDe1/yUG90TXBZLWRhUUAbfxraRVh7u+vbBN1uf0YdCKV/um1CKplSAnBHc8z2Cu61xgZvdE1xZHPo0Vs7lS4eLRVq5PC63S6pcPo6Us7w3HorgKlucqVI+g+B6jCwXicLaE3l8WqSVyyGHMx9eoHyceWx5vnDYgrt3+XD6i/dsnAlu9rjf/n3bQ/FtRq6Gf3MND8YHwwuLtqdlsNxSF4rxxQOvf54V3NWNCDc5mP7izJFz3Owe4KpYyNqggrJpZZ9m5IZm0O4K6xXovka3wnL1dyjXr7LFmT3clamp+cZC+ot3vPgBN3vEAuPrG7tv9n+hVGK6wocJQb5VJqexvA0TyjWsbHEmwl3eiHAbu9Jf3PrC+9zwxnFVLOVjtWUHy3tSeYu0sv/bBD7vNVputwrlGla2uFtwlw8rwt2R/uL0M+9wwxvHVbGU1WHZZbA8bixvkVb2N+Xp+70irPqQh1TFf+ehs5mUcvLU1NTuZFv6i7c8/TY3vGFcFkupVcDnY+OLSUJnkVau/6WyqmV5qEcZrLbSyaY2lGtY2eIuwdX27dT+pZn0F7csvMENbxhXxVIhvFn60EaSXqSV87FeBOdjYWEaywMhfM8cpLn12Xezgrtj6qWXXppKf/GG77/GTR/hgyiEh78PhTbpRVo5H+vuYb4WFnawbOvocyFaFm3Pdgnu7mR7R3CvpP+Bmz6+CC6UkVjWU5HZRVq5lx9fsH3OfC0s7OCq6LKKpXMfynWsbHGX4Cqb3BJcmSqn/kGmy9z48YhJSPsmvs3IJa3ci+UWL59G8BVhuSDNFw/3Mtz42IlMSnlxui24881z6X94+M3L3PgRpYF8GZpdBkXqPi3Syr1Y9sYO4V6x/EITku1ppgd3vaW1myllZuIax1WjuvaEfXXLKcKnGblapJWvY3kfXvdKCLaDVluCtELxUf7uz/+VdZlauy64DDAwjW5yV8VSEvLQjpfStD4tH6fNuMKygcmv/+z/8dXLteUVynWsLHF2NF8qwu0eYICfsi1cFkuFOLnGtxm5iji4ztu4anurYoWwv2h55GFIphc9gwvmm6evC27GTxl7R1u4KpYK+UGvm9enFUqVuNVrfdzl04zofliuUA6hIK1Dno9yWnCxdzSKy2KpkErws/g2I5e0sm17zlC2XixXKIfUg9tj6zjfOHBdcHGbilI4fO8n7Ies93xapJVtbwWEUsmvFkCOsXtue+69zB5uY9c1wc26TWF+YeeN31WxVEjpmzx8m5GrFXtamaHo7rF8T2h/OZRr+eYnTmYi3KXZbsHF/MIcLoulfB9UUAZVlfq0Yk8r6yXQ4vLdO7mD9R71kNoTv/ODYz2mF9kIl15cY7jql1NBUWi9t3n4MFM1vWJPK1s1vAjlRcjy/RDStf/oT7/NFkxduaazqQi3qxf33lc+QfQmiMv9rJCKEyaVkne1Yk0rW25XCaV1znLBVAg9zh0eWvkytwc3E+F29+LedfhDhC/QdGhIeyW+pilDj6aGxarhhaLuUI6x5cEeIXVM3P/qZ7k9uN2Cm+nFvf35VYRvQqh62FVkFtKggjJY7jvMW7Gmla22cYUSeVluudIKqaakqAc3K7hdvbi3PP024jchXBZLSYBie3nxbcWYVrbq7xtKq4oEzfIKpQpc3PHiB7k9uBnBTbYyiD7sh08o5uvDYrn3MG/Flla2HH2FYqZvef82lCrwDgpWuwU32dkjuHmD6BnTVz8ui6VCKkwYBusDzbMrtrS/1egrpNGJlvdvQyviLGoJyhPcrtYgbf4igvXislgqxEEFZfBtRm5IkVUZrBpehGLnyP5tfeRMCVrr0tiM4C4zNWhyuCyWin3QueUZoHkrZJ/rLOf/ZvMcsH9bzwppm6unQnlvc7VYcOeSp9L/s/wgEcL6cFksFbuLkWXbwLwVU1rZaq90KO1z7N/Wh4LUogrlXsHdnWxP/883Pf4WQlgjikJdrZhSlHm4nLrEORsdq4YXIfXfWs7uhBYI9AwtmE/2FQvu/OJ0dojBd3/+L8SwBlxOtwl9UIGFFxoXK4a0ssuszjjrN38J4/jqpc3yCq2uREFq3tCCXMHdtHhcS3/DgyfWeFjXgG5wV0seqhzj9fVfXPJLcGNIK1s1vNCLQAjH17Lxi7YSQvJ07/FQnmtenXry+Jb+gjvfPI2ncr24LJZSaiyGQQVlsDxvtWiFnla2mnUIZf/W5Yv8uEvFciFdywpOizyU+0S4ydH0N2lyPQ9rt7jsE1VUxzFuoxcPqxNpilbIaWWrLmB6+Q3lerc8vCM01zsFp12Cuyc5NVhw55N96W+69dl3eVh7/JYf06ACn1OYRSvktLLVdpVQIi/rGR29cIV0PfdYOs4lB0sI7tJs+pvkmsGD2h0ui6VCK7mvAt9m5GqFmla22q5y8o9hHF/LNQuhpZPFzU+cLLR0LBTcPItHzffjYe0Gl3ssoRR+xJRmy1uhppWtelyH4nz092/tXtOhpZNzhs53WToOEtzV9Ddq3BAP6+pxWSylnxtaysaHlxyiAf9ffEJwPiKdXC+zx78YWDDVR3C7h9FvfeF9HtQOcFksFUofoQusDjuP6QFl1YgkFAtUy+5SIb5A9jhMzTVXygtuZjbuloU3eFB7lvLR3jDHOB/rZu55K7QUnFXDi1Amalk2eQlxJvf0M+9kZ+AulBfcJ49vaTXtpn7A9pNf8bCuEJcVmhJyjnF/rBrmxxIVWE3rh7Bfbt3GNMStrp6RfLuTbaUFl1F9fj9wQqmyjDHCiuVBZbWgJ4SCKdLJ9aKi4kzB1JVCXS0W3O59XAwwqsN1w7/mv3Kc+2PdYzZvhZKKs3zsfb93VIxmuTo5pNm3HVRU3J1Obp4eXnDnGrvSP0Q9Rjyoq8HlqLgQ3yBdoT5ln1Yo59ZqL3QIDlOW+8xD3erqmRCUY3gxWHCZHORlOi2Uodm+v/i4WiGkla2mPEMwirFcmxCqL4CKijMFUzuGFtzNyUHn0z9IvUY8qMfDZbFUaNM3XKP0oW8rhLSy1cyC7xXKlq9nPZtC6G/OomLiQROCygvu3uZy+oep14gH9Xi4LJaSTzDHeDh8m5Hre1pZL4RWl+/D0C0XS+mzhfj82Na4UMrwomSEyz5ulbgullI7AMd5OFTR7dvyOa1s2QHJ57nR1oulQh2iIlOozNbr8uiCq33cTD/uI6e+4UE9Ii73DP/0Ncc3NAEoWj6nlV26q8UsCpbb3EJ2vevpv+2zfztQcPP6cRVC86AeDZdvoCHPTfX5vLhYPqeVLftY+1z/oBduqyvEViCRM3C+7/5tScHt7se9/flVHtIj4Hr2J4MKRse3Gbk+F6B8/U+bx9RnD2Wrc4W1Qh4R2uOf3Kf/trzgMh+3En77V3cXNYMKxsPlTGJXy8f2L8tVtD4LruV+8pDrSsr6Jw8luJvtQWu0B42Oa2edUFM2deHjjFy9wPl2nC1PadJsXh+vXe07W10hBwK582/3L81UJbgrtAeNjstKWO0/0ns7PurB9Gn5mFb+xSW7x9PXfXGre+K6PkOtTBaaLTBMO9BwgrsRKtMeNHr05LIoJ9T+trqxbIlXtHxLK1tOffoYjVmObkN/LvW0A80lRysU3F6bR8b1lcN1QQODCqpB0SJpZbfH1/Ly0TTGcnQbehHnMHaOQwtuW3Sb52gPGh6XxVK+7jvFeK5cPdh8SStbL0xTupvotpoVeoviMOP4RhfcTHuQJiTwkO6P62KpUMa1WUHH07flS1rZ+qAI32wdrQ4piKGm5O6XP+oW3D3JqeoFdyNkTv+SG77/GtODBuCyWCpUM/BJ4tp608XyJa1sPXvgk+Ba7rtVJiP058QtT789dDvQ0IK7Wa18Kf2L7mt+yoO6ANfFUgwqcIPS9D4tX168rBpedJYvmQI9V6wO3PAtLT8KudOB5henHQluchTXKRtvobJyU1oJqsU3m0cfxMLyfqNvgmvVi1ovATG0J/akk/c2V4fS0KH+593JdtLKfu+xsMJb1tPKPuyN+1Dooy0Pq5X0sUwqu+nxt0ZOJw8tuKSVy+HjYHOWv0sPYcvRhQ9e1T7s4Vo1Z1GtSgzP9YffvDxWOnlEwSWtPAjLg6BZYS7Ls1yt7jn6JBpWjVm0tRWL013PsIIh08mjCS5p5YFFDT7uA7L8Xop+LN4P1g0vOstyEaJSyRafKaHbN1adTh5JcEkr+/kmygp7WU0rW25hSS/L++BWU8mWsyoW08mjCy4zcimWYvEALIHLXvQqlyJIi8+T135v83jFsm9bZTp5dMHdnWwjrUyxFMvWsphW9ukF1FqGQJW/FquSY5y/XUU6eWTBbUe5zYuklSmWYtlZ1tLKvs0ZtrQfaXXfVhOfYhsH2uOdPGI6eUzB7U4rTz/zDsVSFEuxJrwspZV9MLxILyu9uCo0szjKUNXmoU8ByuOOFz+oJJ08nuDuX5rJjuzTxjLFUizW5JaltLLV/ceiZWEIvV7cLfpOx1aR3EFbpd/5wbFMOjnZV7vgbqaVV9Mf5M5DZ6MVXN88eFlhLktpZavVtf3WJCM4y2Ibw1CCPDSGNpNOXpt68viWyQjuhtKnP8yNj52IsnjKt9QZK+xlJa3sg+FFdk0qraw0skWx1dCJGCPbDj2TgfY2l8fSzLG+eUPpW4ofefEUxVIsS8tCWtn1LGhXS9Fc3VGujpUcm6wtvTDFLLY9vbdid7JtYoK7mVZejrl4Smkg66PHWHEtC2llXwwv8ladrlNK1Vp8fkhs9SIQq9gKbZFmBPfM2Ho59g+YX5qNuXhKY71YLGtLgkfWZ/TlepiBomiLKWQtVUjHWI2cLZbSFmlVxVKVCW5bdJvnYi2eoliKZXFN2hs4hPvChehKyOTSZDUrpvOm/eSYxVbc/+pnlRZLVSy4jYUYi6colmJZXXqgTyqt7JvhRb+laK+KbMGB/2m/BFk+LspKxGZqUcStz75babFUtYLbLp66GlvxFMVSLMtrUq0cEpfQloqaFJnqbytzDGTLqO0miaz1Gg99vljbfvLYfvKryoulKhXcdvFUciz9AW9+4iTFUizWBNek0sq+GV6MsuQqJ6OMLL6l0vV5Y9+vraNYqnrBzSmekgclxVIs1mTWpNLKMrdn2V+uC8N8LZbqcZaaa+wyJ7h5xVO3PfdesCfGaoUhi5VeSm3WfW/gKW576fxM4rrwgXs2IikXxVJuBHfjTSAb5T5y6psgTwxzb1k+rLJ7jlXhq+FFDEsFW4pqKYwqjm57W4EaByrVyCp/WN7YvlBbhBBclg+rbsFlq8XmkvsYe7X9yWkFujo1n2y1LbgbbwTpD618eIgtQgguy4dVt+BSuW9rqSiK9HE5VOjrohXIreDm+CsrL47gslj1r7oF1+Ic1xiX9mktzUa2zuzxL5y1AjkV3PZebnI0/cG3LLyB4LJYE1h1Cq72BlmTXfJAbvyOfdphUYFv995t87QTbXTyQ+eTrVkjDOXHEVwWq95Vp+CGaHjhy1LXBOYVo6H21Z7odj7Z6Y3g5hlhaK4ggsti1bvqFFxVwLLqW+qz/sUlpvqMS4/RxVzzvDNddPaDAzfCQHBZPqw6Bdey4YXEKZR7VoVQShszZGB81LZ6w/dfy7YCLXgnuJtGGKdDNcJAcFkIbjeWrU51v+ozqjVGYuXT/asCKNl0qggKkXUe3VZqdFGv4O5Otmej3Ade/zyIE6X2hzwvVQBLaKJVHffDD39lW7Q0eCD7mTviqx5VFRtZWopif3yhvvNHdOvG6KJWwc2LckMfagAQI9YNL8qM2NNeqKJIvUzX1d4kYVUqXvvf+t30zIYb3dYkuL17uaFVLAPEjlKelteoLkv6PqXl9UIhUVQ0nM0ipKNjCXX23/V9afTzlBHguokruq1FcIlyAcLHsuGFBJFzBGm2vvB+7dFtjYJLlAsQKirksbyUsuU8QYf8vlv30W1tgkuUCxAu2h+1vF77PecIrtPjKjXXPF9HdFuz4BLlAoSIdcOLuv2kwbPotsIB82YEd3N03zJRLkBYWO9pxVcY+kW3tWpgrb8sx2N5W+MCFwKAx1g2vFAxF+cILES3tQtuXpR742MngpyXCxADMmawvOQ1zHkCIT//SUa3kxHcnChXDchcEAD+oYIky0v9s5wnUL1QXROBTAnu5rzcg+k/XA3I209+xYUB4BnWDS+wRgRlUJVJrWPerU3BffL4llajcaCDDQBiwZoHcXppb5lzBDNHzmVTyVen9i/NRCO47Si3sSsb4s8e/4ILBMATrBtedCYEQbzkWjjubS5PTPcm9Yvbots8T5sQgJ9YN7zImxAEcXH786sTsXC0Kbg5Zhj3vvIJFwqAB2iqjuVVZkIQhMuDJ9byLBwXJqp5k/zlrQ+wJzlFmxCAf1g3vBh1QhCEgTKmk24Dsie4tAkBeIfcm/7xb7tiy4SguJGhUm90uzQbveC2zTCWD2fbhB5+8zIXDoBRrBteMCEoXh796be9bUB7klMmtM7Eh8hpE5IrCBcPgE2sG14wIShecmbdXlUmFcHtSi03FiigAvADRZCWFxOC4kStpb1+yclBMzpn5YNs+iyvZlPL6qPiQgKwhWXDCy0mBMWHim23LLwxsVm3/gnu/qWZbAHVrc++y8UEYIh979sWWyYExcldhz80WShlVnA3U8sHsgftvuanXFAARrBueKH+YM5TXGj0niVHKW8EN8+BShVnqjzjwgKYPNYNLxq/4xzFRk7P7ZqlVLJtwZUDVSa1rMozLiyAyaOUreXFhKC4uPvlj0yM3vNWcDdH+B1luAGALawbXuizUTAVDxrr2pNKNtJz65fgqjd3b/Ni+kCqAg3bR4DJoXYbCqbACtPPvJONbq9Y6bn1SnA3C6h2ZKPcO178gAsNYEJYN7xY/RPnKBbuWfzY3HACrwV3s4BqJXtQ73/1My44gAlg3fACh6k4kPVvTlXyGfN6Zv4Dzi9Ob4jupWzVMoYYAPXz9T9tCy4OU+GjbcWcquSr8nFAcB2lljHEAKgX64YXWv/x35yn0Mk3uLCdSvZKcNu2j90ThYRy+FyAAPWwcbuZXn//lnMUOrleyfPN097omDcfVFXL881zjPEDmAy/uGRbcM//jXMUMrlj92RwMb84jeDW5LWsXD6tQgDusW54QYVy2Nz+/GpeKnmHVxrm04fd3M/tGeOnnD4XJIA7tDdqfZ38I+cpVLY1LvSKrUGv5OAEt/Wh9ySncKECqA/rhhdaP77AeQqRXDcpmSIZ9EoOU3DbrUJrtAoB1MNP/mBfcFXUxbkKC20X3vL0270tQMbG7gUtuEWtQjox7OcCVM9v/2pfcP/rfzlPoaGhNTn7tge81S1fP3hRq9Cdh85yoQJUjHXDC60fneU8hUTBvu2q15rl84dvi27zTPak6ERxwQJUg8bd+bBwmQqHB0+s9e7bynHQoxagMAU3x/pRJ+qhlS+5cAEqwLrhRWcd+i3nKgTUb6vJcKHs2wYluK0/YneyPdufqxOmE8cFDDAe6m/1YTV+x7kKgZyRe95YN0YhuEX9ufgtA4zPn772Q3AxvvCfmSPngui3DV5w2/u5ybHsydIJ5EIGGA0fDC86a+0bzpfPaOxqjk/yOR/7beMQ3By/ZebnAoyO9kV9Wuzj+onMLb7zg2O9PskejNyLVnBbf1Dbb3mNIiqA8fHB8CK95PfMefML1drc9Phb3vskRym4RaYYcqLSWxQXOEB5NIHHt6WpRpw7P5BRUUGRlLfmFtEJbusPm0sOZk+iJgtRuQxQnn/82z/B1frZZ+vr3/sl5886uROA9iSngtWlUP+woiIqVS5j/wgwGF8ML/oVUR35iPNoFU15y6lIPhNSkVRUgtsW3eZq9qTKn5MLHqA/r/3eb8HtrL9/2x7dh/WjHe595ZM8sb3ou5MUgqvK5bnmedqFAIbDF8OLYZZS5NqXlgDLKEN2kGp94nzXxwOvf94rtgFWJEcpuO0iqmRr1v5R3Nf8lBsAoAClZGNYP/wV57ou1C2S45EchG0jgpv+Q3cn2zZO7pVsuxCD6wF62bMah9gq4uV814O6RNQt0hvdNnZFo0Ox/KGbke7OrOeymq3p0QXoxjfDi1EXfbv10KfXNsj2HwT3eo9uj+eyRJceXYDrqK0mhvXrP3Ou6xBbtWSG7JGM4PatXO4dXK/pQoguQBsfDS9GWT++wLl2iVowc8V2vnk6Su2J8Y9u/eFzzZU80X3k1DfcKBA1Mozw1fBi2IX3sluxle9BTmS7GnKvLYI7hOjiRgWxo37VWBYVyjWLrVo0IxVbBFc9ujnGGIguxEwohheDFhXK7pC5UK7YBm5sgeCOKLpYQEKs/OYvcQguFcq1iu2l2MUWwU2Lbo4bFaILAFCeXH9kiW0ELlII7lDtQovTiC4AwGjILhexRXCHEN18C0hEFwBgyMhWzn6RWDYiuKMekI23MUQXAKAcuXu2iC2CW/qgyHc5R3Snn3mH6mUAAMQWwa0j0qVlCABiR9m+2557D7FFcBFdAACXYlvgIIXYIrhuqpcluthAAgBi2+mzRWwRXIeiy8ADAIiFwqk/tP4guE5Ed755Lk90macLACGjbB5ii+DWe7AKbCA1T3f2+BfcmAAQHAooFFjkeiMjtgjuJET3hu+/tr6tcYEbFACC4YHXP28FFAwiQHAnK7o5o/2E7M24UQHAdxRA5D3jNjiD2CK49R+8ueRg3gWpZnBcqQDAVwqsGtdbgUbE82wR3IkXUyX7Ni7Cq7hSAYDvKFC4/fnVArFNjvLMR3ANiG5jR6vpO3OB3vT4W7QNAYAXKEBQoJAT1V7deMYt8KxHcO0cyAL/5RsfO7H+4Ik1bmgAMMvDb15uBQj57lGNHTzjEVyDkW5+r64qmO995RNubAAwx/2vflZUiXxJgQTPdgTXdgXznuQUxVQAYJ3cofG0/SC4HlYwH827kOXWwr4uAEwS7dcWTPtZn5pvnqYSGcH1s4I5p5hK6RulcbjxAaBuCp2j2pXIB3l2I7h+F1PtbV7EJAMAJs19zU9bNSUURyG4YRdTFezratQV/boA4BLVjtx56Gzxfi2eyAhueMLbOJB3wSu9Q+sQALhAk35uefrtApvG5Bj7tQhuyCnm7RtvlGt5rUN3v/wRDwgAqIw+LT9Xp+aSp3gmI7gxFFNtzevX7VhC6o2UhwUAjJNCVhtiQQpZ/bXbeRYjuHEd/L3N5bwbQm+kGovFgwMAhkXbUwWuUUz6QXCjj3Z35qWYhYocMMoAgLJoWyq3CrmdQqblB8GFVoo5Z6h9ZwCCfE55mABAEdqGyh080OYiKWQEF7InQ/N1c0b94cUMAEUUFkZRhYzgwqBod2m2yChDPbsUVAGAUP9+YWFUy8gi2ckzFcGFQSdFAxD0ZlpQUEX7EEDcbGtcaI3+LBDbVW1T8SxFcGGoFHNjV54Xs1AjO3u7APHt1SrTVdDuQ2EUgguuCqq0tys/ZiqZAcJHdRyFe7Xq62d2LYILVQlvY6Eo2lUlM9aQAGGiTFahNSNRLYILDqPdueZKwb7N+l2HP2QQAkBAFPbVdvZqiWoRXHAuvIVmGSqk0AguHlYA/jJ7/Iv1m5842acCubHAsxDBhdpEd3G6yBqyU1RFmhnAL7af/Gr9tufeKxJa7dWepgIZwYVJnUBNHyro2xW3P79K7y6AcbQVpC2hwvSxMlr01SK4YOAkqm93Ljma51KV7t2lmhnAHqo+7tNT23aLYuAAggvGTub+pZlWyqngxtWge9nA8ZADML9PuznZZ2mWZxuCC6b3dxs7NqLd80U3skzOH1r5kocegMV9Ws2rnWvs4lmG4IJPJ3cueaqomlnopkd4AepBtRQaudmnzedKa4AJwwYQXPA12l2c7re/K2SArrduHooAExHazX1aqo8RXIhifxfhBagWVR7LerV4dN41S0Zm1SK4EGbE2zLNOD9IeGklAnAotNqnnU/28UxCcCGK/d3Grn7Cq/SX0mAIL0A51HZ3z+LH/Vt8WkKLSxSCC7FGvPtaD4E+wkuqGWBwRDtAaNc2hPYABVEILkB7GlEf4e1UNWMXCdBGL6F3vPjBgGKolu8xQgsILmQuBjlW6eHQp5Wo08eLgQbEil46+/bRdoR27/JhHKIAwYVKhFdzeLc1LvAQhijQFK7CubQILSC4UIHwLvQbjtAZCahiEWbxQoj7s/I6li1qX6Ht7NEitIDgwtgXitqJ5O3a56HTKbB64PXPeViD92ljXcsD9mfXWy+jVB0DggtuhHdpduNtfmXAQ6gVEWhCEdXN4Fs0q62SQdd3e7AA4/IAwYV6It6tLcvI1p5V/4fTrc++29r/4qEOnkez61N7klNM8AEEFyYkvC2v5qcG7fN29nrVRvHwm5d50IM/0WyreDA5JntU7nlAcMHGxbQ72d5KN/cZlJCucCblDHWLrKrqS7T0dFjFfhEQXPAj6pUxe4kHm4ZwK9rARhKqRnaLQ4lsaxZtcpBoFhBc8DHq3dZKx5XY6+2YaugBSYsRjCOyqhm4/fnVcvuyysi09mYpggIEF0K40K739J4pmc5rRSV6cBL5Qpl08VAi2xba8+1MDL2zgOBCsCnnVoXzU8OIr9LOdx3+EC9nuMZDK1+26gBKuD91983KCYqUMSC4EN0FuPHg27SRPF/2oak5o4pklHqm6Cq+VLFaePpO5snflz2q7Q3uOUBwAUYU307Fs2b3yuFKD2XEKawoVrah6uUe5prY9AFfpmcWEFyAsuJbstI5jVKMEmD2f/2LYGePf9GaLSuBLb0X25Uulsg2dnAPAYILMMpFqjaj+WTfZo/v2rACLJtJpaDVeqSICXGzgQxQtC0gMxTt0Q97XlvVxfPN0616APZkAcEFcCHA8nNODg6bek7vASuCUiSlub44X9UjrjrWnehV52CUc7dZWXyUKBYQXIDaxTfZ2mo3Uh+limNGeYineoBVkKPKV6U26QUePS2sfVdFrjqm45yT1jlt9chunOONc801DwgugJULurX3m+xr7+UNv/+b5/8s0VBk1hFi0tLtYqaOsOrY6BgNVTncL4KVUYrOIWliQHABfIuCGztavZfyxi3peFU2NS2hkUGHREd7xBKhEFLU+hv0t+hv0t+mPXD9rSOngvuNuWuliJOdGFAAggsQ2kUvu8mW61VLhM+MUog1bITcQeLVQQVDErU0rqqq07+jE5WmhVSouMzVcdgcaHGmHb02DmjQBdciILgAUUbBqoTeiIQlBm3v5zPOxCd0lBbWvqteaBS5khoGQHABBt4g7T3hnS3xUOpTQlzB3nAAXLwWsbaFdR8mEwAILoCbm6c9kGFHjyCP2K5kX1BbfyuVwgAILoDRm6ydqt5xPWWtvWMJdHNlM3V9nSr3k6/tm6aQUUTn97eENP3ZKFoCcMn/B50KyeS7TVtNAAAAAElFTkSuQmCC", - fileName= - "modelica://SorpLib/Resources/Images/DeltaP.png")}), - Documentation(info="<html> -<p> - This partial model is the basis for the pressure drop correlation models. <br> -</p> - -<h4>Author Information</h4> -<p> - <ul> - <li> - November 28, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); - -end PartialPressureDrop; diff --git a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/Partial/package.mo b/SorpLib/Components/Cells/Gas/PressureDropCorrelations/Partial/package.mo deleted file mode 100644 index 7c8a3e9e7485f94fe217593a7425d1e9b60ec8f9..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/Partial/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.Cells.Gas.PressureDropCorrelations; -package Partial - extends SorpLib.Internals.ClassTypes.PartialPackage; - -end Partial; diff --git a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/Partial/package.order b/SorpLib/Components/Cells/Gas/PressureDropCorrelations/Partial/package.order deleted file mode 100644 index 1b8a13e7267887015effecc8651b65ef88e3d839..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/Partial/package.order +++ /dev/null @@ -1 +0,0 @@ -PartialPressureDrop diff --git a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/ZeroPressureDrop.mo b/SorpLib/Components/Cells/Gas/PressureDropCorrelations/ZeroPressureDrop.mo deleted file mode 100644 index 72f33207dc0885a13c36484dfcf28c512b7dbcdd..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/ZeroPressureDrop.mo +++ /dev/null @@ -1,34 +0,0 @@ -within SorpLib.Components.Cells.Gas.PressureDropCorrelations; -model ZeroPressureDrop "Pressure drop = 0 Pa" - extends Partial.PartialPressureDrop( - final computeTransportProperties=false); - -equation - pressureDrop=0; - annotation (Documentation(info="<html> -<p> - This model sets the pressure drop to zero. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> <i><code>Δ</code>p</i> = 0 </p> -<p>where <i><code>Δ</code>p</i> is the pressure drop. </p> -</p> -<h4>Assumptions and limitations</h4> - <p> - The model uses the following main assumptions: - <ul> - <li>In this simple pressure drop model, there is no correlation between mass flow rate and pressure drop. Thus, a mass flow rate has to be given by another model, e.g. by a mass flow boundary.</li> - </ul> - </p> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 28, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end ZeroPressureDrop; diff --git a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/package.mo b/SorpLib/Components/Cells/Gas/PressureDropCorrelations/package.mo deleted file mode 100644 index a1e6d456b1b9791b015d5c1db5b42e13faead6d8..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/package.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.Cells.Gas; -package PressureDropCorrelations - extends SorpLib.Internals.ClassTypes.ModelPackage; - - - - -end PressureDropCorrelations; diff --git a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/package.order b/SorpLib/Components/Cells/Gas/PressureDropCorrelations/package.order deleted file mode 100644 index f549a873facfb54657848b7d3eee3e3203092808..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/PressureDropCorrelations/package.order +++ /dev/null @@ -1,3 +0,0 @@ -ZeroPressureDrop -ConstantResistanceCoefficient -Partial diff --git a/SorpLib/Components/Cells/Gas/Testers/TestGas.mo b/SorpLib/Components/Cells/Gas/Testers/TestGas.mo deleted file mode 100644 index 79fa0d700fd64b2e9c71dcd189a8baaa8550d57f..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/Testers/TestGas.mo +++ /dev/null @@ -1,133 +0,0 @@ -within SorpLib.Components.Cells.Gas.Testers; -model TestGas - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.GasTypes.TILMedia_MoistAir gasType1, redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - - Gas gas1( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000) - annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="m_flow", - streamVariablesInputType="T", - m_flowFixed=-0.00002, - TFixed=303.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={-76,-30}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - boundaryType="m_flow", - streamVariablesInputType="T", - m_flowFixed=-0.0002, - TFixed=303.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={-6,-30}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary3( - boundaryType="m_flow", - streamVariablesInputType="T", - m_flowFixed=-0.0002, - TFixed=303.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={64,-30}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary1(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={-70,26}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary2(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={0,28}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary3(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={70,26}))); - Gas gas2( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000) - annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); - Gas gas3( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient ( - f=0.016), - TInitial=303.15, - pInitial=1000000) - annotation (Placement(transformation(extent={{60,-10},{80,10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryB( - boundaryType="p", - TFixed=303.15, - pFixed=1500000) - annotation (Placement(transformation(extent={{96,-10},{104,10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryA(m_flowFixed=-2, TFixed= - 303.15) - annotation (Placement(transformation(extent={{-104,-10},{-96,10}}))); -equation - connect(gas1.vlePort, vleBoundary1.port) annotation (Line( - points={{-76,-10},{-76,-10},{-76,-30}}, - color={153,204,0}, - thickness=0.5)); - connect(gas1.heatPortB, heatBoundary1.heatPort) annotation (Line( - points={{-70,10},{-70,10},{-70,26}}, - color={204,0,0}, - thickness=0.5)); - connect(heatBoundary2.heatPort, gas2.heatPortB) annotation (Line( - points={{0,28},{0,10}}, - color={204,0,0}, - thickness=0.5)); - connect(vleBoundary2.port, gas2.vlePort) annotation (Line( - points={{-6,-30},{-6,-30},{-6,-10}}, - color={153,204,0}, - thickness=0.5)); - connect(gas3.gasPortA, gas2.gasPortB) annotation (Line( - points={{60,0},{34,0},{9.8,0}}, - color={255,153,0}, - thickness=0.5)); - connect(heatBoundary3.heatPort, gas3.heatPortB) annotation (Line( - points={{70,26},{70,26},{70,10}}, - color={204,0,0}, - thickness=0.5)); - connect(vleBoundary3.port, gas3.vlePort) annotation (Line( - points={{64,-30},{64,-30},{64,-10}}, - color={153,204,0}, - thickness=0.5)); - connect(gas1.gasPortB, gas2.gasPortA) annotation (Line( - points={{-60.2,0},{-36,0},{-10,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gas1.gasPortA, gasBoundaryA.port) annotation (Line( - points={{-80,0},{-90,0},{-100,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gas3.gasPortB, gasBoundaryB.port) annotation (Line( - points={{79.8,0},{90,0},{100,0}}, - color={255,153,0}, - thickness=0.5)); - annotation (Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, - -100},{100,100}})), experiment(StopTime=100)); -end TestGas; diff --git a/SorpLib/Components/Cells/Gas/Testers/TestGas2.mo b/SorpLib/Components/Cells/Gas/Testers/TestGas2.mo deleted file mode 100644 index bd6620c7365732a70a985d072381cd78d7c08809..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/Testers/TestGas2.mo +++ /dev/null @@ -1,133 +0,0 @@ -within SorpLib.Components.Cells.Gas.Testers; -model TestGas2 - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.GasTypes.TILMedia_MoistAir gasType1, redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - - Gas gas1( - fixedInitialPressure=false, - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000) - annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="m_flow", - streamVariablesInputType="T", - m_flowFixed=-0.00002, - TFixed=303.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={-76,-30}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - boundaryType="m_flow", - streamVariablesInputType="T", - m_flowFixed=-0.0002, - TFixed=303.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={-6,-30}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary3( - boundaryType="m_flow", - streamVariablesInputType="T", - m_flowFixed=-0.0002, - TFixed=303.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={64,-30}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary1(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={-70,26}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary2(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={0,28}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary3(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={70,26}))); - Gas gas2( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000) - annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); - Gas gas3( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000) - annotation (Placement(transformation(extent={{60,-10},{80,10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryB(boundaryType="p", pFixed= - 1000000) - annotation (Placement(transformation(extent={{96,-10},{104,10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryA( - boundaryType="p", - TFixed=303.15, - pFixed=1500000) - annotation (Placement(transformation(extent={{-104,-10},{-96,10}}))); -equation - connect(gas1.vlePort, vleBoundary1.port) annotation (Line( - points={{-76,-10},{-76,-10},{-76,-30}}, - color={153,204,0}, - thickness=0.5)); - connect(gas1.heatPortB, heatBoundary1.heatPort) annotation (Line( - points={{-70,10},{-70,10},{-70,26}}, - color={204,0,0}, - thickness=0.5)); - connect(heatBoundary2.heatPort, gas2.heatPortB) annotation (Line( - points={{0,28},{0,10}}, - color={204,0,0}, - thickness=0.5)); - connect(vleBoundary2.port, gas2.vlePort) annotation (Line( - points={{-6,-30},{-6,-30},{-6,-10}}, - color={153,204,0}, - thickness=0.5)); - connect(gas3.gasPortA, gas2.gasPortB) annotation (Line( - points={{60,0},{34,0},{9.8,0}}, - color={255,153,0}, - thickness=0.5)); - connect(heatBoundary3.heatPort, gas3.heatPortB) annotation (Line( - points={{70,26},{70,26},{70,10}}, - color={204,0,0}, - thickness=0.5)); - connect(vleBoundary3.port, gas3.vlePort) annotation (Line( - points={{64,-30},{64,-30},{64,-10}}, - color={153,204,0}, - thickness=0.5)); - connect(gas1.gasPortB, gas2.gasPortA) annotation (Line( - points={{-60.2,0},{-36,0},{-10,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gas3.gasPortB, gasBoundaryB.port) annotation (Line( - points={{79.8,0},{90,0},{100,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gas1.gasPortA, gasBoundaryA.port) annotation (Line( - points={{-80,0},{-100,0}}, - color={255,153,0}, - thickness=0.5)); - annotation (Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, - -100},{100,100}})), experiment(StopTime=100)); -end TestGas2; diff --git a/SorpLib/Components/Cells/Gas/Testers/TestGas3.mo b/SorpLib/Components/Cells/Gas/Testers/TestGas3.mo deleted file mode 100644 index bb49a292f35026818758e3e90be94e8aade707ff..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/Testers/TestGas3.mo +++ /dev/null @@ -1,135 +0,0 @@ -within SorpLib.Components.Cells.Gas.Testers; -model TestGas3 - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.GasTypes.TILMedia_MoistAir gasType1, redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - - Gas gas( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000, - HydraulicMassFlowPosition="gas port A") - annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="m_flow", - streamVariablesInputType="T", - m_flowFixed=-0.00002, - TFixed=303.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={-76,-30}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - boundaryType="m_flow", - streamVariablesInputType="T", - m_flowFixed=-0.0002, - TFixed=303.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={-6,-30}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary3( - boundaryType="m_flow", - streamVariablesInputType="T", - m_flowFixed=-0.0002, - TFixed=303.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={64,-30}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary1(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={-70,26}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary2(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={0,28}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary3(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={70,26}))); - Gas gas2( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000, - HydraulicMassFlowPosition="gas port A") - annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); - Gas gas3( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000, - HydraulicMassFlowPosition="gas port A") - annotation (Placement(transformation(extent={{60,-10},{80,10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryA( - boundaryType="p", - TFixed=303.15, - pFixed=1000000) - annotation (Placement(transformation(extent={{-104,-10},{-96,10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryB(m_flowFixed=-2, TFixed= - 303.15) - annotation (Placement(transformation(extent={{96,-10},{104,10}}))); -equation - connect(gas.vlePort, vleBoundary1.port) annotation (Line( - points={{-76,-10},{-76,-10},{-76,-30}}, - color={153,204,0}, - thickness=0.5)); - connect(gas.heatPortB, heatBoundary1.heatPort) annotation (Line( - points={{-70,10},{-70,10},{-70,26}}, - color={204,0,0}, - thickness=0.5)); - connect(heatBoundary2.heatPort, gas2.heatPortB) annotation (Line( - points={{0,28},{0,10}}, - color={204,0,0}, - thickness=0.5)); - connect(vleBoundary2.port, gas2.vlePort) annotation (Line( - points={{-6,-30},{-6,-30},{-6,-10}}, - color={153,204,0}, - thickness=0.5)); - connect(gas3.gasPortA, gas2.gasPortB) annotation (Line( - points={{60,0},{34,0},{9.8,0}}, - color={255,153,0}, - thickness=0.5)); - connect(heatBoundary3.heatPort, gas3.heatPortB) annotation (Line( - points={{70,26},{70,26},{70,10}}, - color={204,0,0}, - thickness=0.5)); - connect(vleBoundary3.port, gas3.vlePort) annotation (Line( - points={{64,-30},{64,-30},{64,-10}}, - color={153,204,0}, - thickness=0.5)); - connect(gas.gasPortB, gas2.gasPortA) annotation (Line( - points={{-60.2,0},{-36,0},{-10,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gas.gasPortA, gasBoundaryA.port) annotation (Line( - points={{-80,0},{-90,0},{-100,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gas3.gasPortB, gasBoundaryB.port) annotation (Line( - points={{79.8,0},{90,0},{100,0}}, - color={255,153,0}, - thickness=0.5)); - annotation (Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, - -100},{100,100}})), experiment(StopTime=100)); -end TestGas3; diff --git a/SorpLib/Components/Cells/Gas/Testers/TestGas4.mo b/SorpLib/Components/Cells/Gas/Testers/TestGas4.mo deleted file mode 100644 index 5d0e688130cc9e86f81887375ed2cfab05d8a2ca..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/Testers/TestGas4.mo +++ /dev/null @@ -1,130 +0,0 @@ -within SorpLib.Components.Cells.Gas.Testers; -model TestGas4 - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.GasTypes.TILMedia_MoistAir gasType1, redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - - Gas gas( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000) - annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="m_flow", - streamVariablesInputType="T", - TFixed=303.15, - m_flowFixed=0) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={-76,-30}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - boundaryType="m_flow", - streamVariablesInputType="T", - TFixed=303.15, - m_flowFixed=0) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={-6,-30}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary3( - boundaryType="m_flow", - streamVariablesInputType="T", - TFixed=303.15, - m_flowFixed=0) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={64,-30}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary1(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={-70,26}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary2(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={0,28}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary3(boundaryType="Q_flow", - Q_flowFixed=-30) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={70,26}))); - Gas gas2( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000) - annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); - Gas gas3( - cellGeometry( - length=0.2, - hydraulicDiameter=0.02, - flowCrossSection=0.000314, - psi=1), - redeclare model PressureDropModel = - PressureDropCorrelations.ConstantResistanceCoefficient (f=0.016), - TInitial=303.15, - pInitial=1000000) - annotation (Placement(transformation(extent={{60,-10},{80,10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryB(m_flowFixed=2, TFixed= - 303.15) - annotation (Placement(transformation(extent={{96,-10},{104,10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryA(m_flowFixed=-2, TFixed= - 303.15) - annotation (Placement(transformation(extent={{-104,-10},{-96,10}}))); -equation - connect(gas.vlePort, vleBoundary1.port) annotation (Line( - points={{-76,-10},{-76,-10},{-76,-30}}, - color={153,204,0}, - thickness=0.5)); - connect(gas.heatPortB, heatBoundary1.heatPort) annotation (Line( - points={{-70,10},{-70,10},{-70,26}}, - color={204,0,0}, - thickness=0.5)); - connect(heatBoundary2.heatPort, gas2.heatPortB) annotation (Line( - points={{0,28},{0,10}}, - color={204,0,0}, - thickness=0.5)); - connect(vleBoundary2.port, gas2.vlePort) annotation (Line( - points={{-6,-30},{-6,-30},{-6,-10}}, - color={153,204,0}, - thickness=0.5)); - connect(gas3.gasPortA, gas2.gasPortB) annotation (Line( - points={{60,0},{34,0},{9.8,0}}, - color={255,153,0}, - thickness=0.5)); - connect(heatBoundary3.heatPort, gas3.heatPortB) annotation (Line( - points={{70,26},{70,26},{70,10}}, - color={204,0,0}, - thickness=0.5)); - connect(vleBoundary3.port, gas3.vlePort) annotation (Line( - points={{64,-30},{64,-30},{64,-10}}, - color={153,204,0}, - thickness=0.5)); - connect(gas.gasPortB, gas2.gasPortA) annotation (Line( - points={{-60.2,0},{-36,0},{-10,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gas3.gasPortB, gasBoundaryB.port) annotation (Line( - points={{79.8,0},{90,0},{100,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gas.gasPortA, gasBoundaryA.port) annotation (Line( - points={{-80,0},{-90,0},{-100,0}}, - color={255,153,0}, - thickness=0.5)); - annotation (Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, - -100},{100,100}})), experiment(StopTime=100)); -end TestGas4; diff --git a/SorpLib/Components/Cells/Gas/Testers/package.mo b/SorpLib/Components/Cells/Gas/Testers/package.mo deleted file mode 100644 index c346db76a0e4e807ca131a73944a5d24fcdcd61a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/Testers/package.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.Cells.Gas; -package Testers - extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - - - -end Testers; diff --git a/SorpLib/Components/Cells/Gas/Testers/package.order b/SorpLib/Components/Cells/Gas/Testers/package.order deleted file mode 100644 index fb98d4328afccf5898f7de3fcbac1cce175ffff1..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/Testers/package.order +++ /dev/null @@ -1,4 +0,0 @@ -TestGas -TestGas2 -TestGas3 -TestGas4 diff --git a/SorpLib/Components/Cells/Gas/package.mo b/SorpLib/Components/Cells/Gas/package.mo deleted file mode 100644 index 43c6b99b7120c51d97e5a3017678eac4af00e1cc..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/package.mo +++ /dev/null @@ -1,7 +0,0 @@ -within SorpLib.Components.Cells; -package Gas - extends SorpLib.Internals.ClassTypes.ComponentPackage; - - - -end Gas; diff --git a/SorpLib/Components/Cells/Gas/package.order b/SorpLib/Components/Cells/Gas/package.order deleted file mode 100644 index a019f1ae7cf60ed8164a5f67a3da3b0b364a2c59..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Gas/package.order +++ /dev/null @@ -1,4 +0,0 @@ -Gas -PressureDropCorrelations -Geometry -Testers diff --git a/SorpLib/Components/Cells/VLEPhaseSeparator/Testers/TestVLEPhaseSeparator.mo b/SorpLib/Components/Cells/VLEPhaseSeparator/Testers/TestVLEPhaseSeparator.mo deleted file mode 100644 index 2ffb8cb3983091fda9ad5bdf70dbf45feae543d3..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/VLEPhaseSeparator/Testers/TestVLEPhaseSeparator.mo +++ /dev/null @@ -1,90 +0,0 @@ -within SorpLib.Components.Cells.VLEPhaseSeparator.Testers; -model TestVLEPhaseSeparator - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - VLEPhaseSeparator vlePhaseSeparator( - dInitial=600, - vleFluidType=sim.vleFluidType1, - volume(displayUnit="l") = 0.005, - area=0.03, - includeDefaultSummary=true, - n=2, - k=1, - TInitial=298.15) annotation (Placement(transformation( - extent={{5,8},{-5,-8}}, - rotation=180, - origin={0,0}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary1( - boundaryType="Q_flow", - use_heatFlowRateInput=false, - Q_flowFixed=-2200, - TFixed=323.15) - annotation (Placement(transformation(extent={{30,-6},{22,6}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{4,-10},{-4,10}}, - rotation=90, - origin={-14,28}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=false, - m_flowFixed=-0.001) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={0,-20}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary3( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{4,-10},{-4,10}}, - rotation=90, - origin={12,28}))); - Modelica.Blocks.Sources.Step stepVLEBounday2( - height=-0.001, - offset=0.001, - startTime=50) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=270, - origin={-16,48}))); - Modelica.Blocks.Sources.Step stepVLEBounday3(height=0.001, startTime=100) - annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=270, - origin={10,48}))); -equation - connect(heatBoundary1.heatPort, vlePhaseSeparator.heatPort) annotation (Line( - points={{26,0},{18,0},{18,-8.88178e-016},{5,-8.88178e-016}}, - color={204,0,0}, - thickness=0.5, - smooth=Smooth.None)); - - connect(vleBoundary2.m_flow_in, stepVLEBounday2.y) - annotation (Line(points={{-16,32},{-16,32},{-16,41.4}}, color={0,0,127})); - connect(stepVLEBounday3.y, vleBoundary3.m_flow_in) - annotation (Line(points={{10,41.4},{10,36.7},{10,32}}, color={0,0,127})); - connect(vlePhaseSeparator.vleVapourPort[1], vleBoundary2.port) annotation ( - Line( - points={{8.88178e-016,7.33333},{8.88178e-016,14},{-14,14},{-14,28}}, - color={153,204,0}, - thickness=0.5)); - connect(vlePhaseSeparator.vleVapourPort[2], vleBoundary3.port) annotation ( - Line( - points={{8.88178e-016,8.66667},{0,8.66667},{0,14},{12,14},{12,28}}, - color={153,204,0}, - thickness=0.5)); - connect(vlePhaseSeparator.vleLiquidPort[1], vleBoundary1.port) annotation ( - Line( - points={{-9.99201e-016,-8},{0,-8},{0,-20}}, - color={153,204,0}, - thickness=0.5)); - annotation ( - Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ - 100,100}})), - experiment(StopTime=500, Tolerance=1e-005), - __Dymola_experimentSetupOutput(events=false)); -end TestVLEPhaseSeparator; diff --git a/SorpLib/Components/Cells/VLEPhaseSeparator/Testers/package.mo b/SorpLib/Components/Cells/VLEPhaseSeparator/Testers/package.mo deleted file mode 100644 index fc620d5fb1b59f04115a5047e2e25ebca36d6cb9..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/VLEPhaseSeparator/Testers/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.Cells.VLEPhaseSeparator; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - -end Testers; diff --git a/SorpLib/Components/Cells/VLEPhaseSeparator/Testers/package.order b/SorpLib/Components/Cells/VLEPhaseSeparator/Testers/package.order deleted file mode 100644 index a0d62bb85ec5e78b6d669bf79787bd35d17c79d9..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/VLEPhaseSeparator/Testers/package.order +++ /dev/null @@ -1 +0,0 @@ -TestVLEPhaseSeparator diff --git a/SorpLib/Components/Cells/VLEPhaseSeparator/VLEPhaseSeparator.mo b/SorpLib/Components/Cells/VLEPhaseSeparator/VLEPhaseSeparator.mo deleted file mode 100644 index d9ed5a953b474ba53a21e22c6961e9d0be5859d8..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/VLEPhaseSeparator/VLEPhaseSeparator.mo +++ /dev/null @@ -1,237 +0,0 @@ -within SorpLib.Components.Cells.VLEPhaseSeparator; -model VLEPhaseSeparator - - /*********************** SIM ***********************************/ - - parameter TILMedia.VLEFluidTypes.BaseVLEFluid vleFluidType=sim.vleFluidType1 - "VLE fluid type" annotation (Dialog(tab="SIM", group="SIM"), choices( - choice=sim.vleFluidType1 "VLE fluid 1 as defined in SIM", - choice=sim.vleFluidType2 "VLE fluid 2 as defined in SIM", - choice=sim.vleFluidType3 "VLE fluid 3 as defined in SIM")); - -protected - outer TIL.SystemInformationManager sim "System information manager"; - - TIL.Internals.SimPort simPort; - - /********************** Connectors **************************/ - -public - TIL.Connectors.VLEFluidPort vleVapourPort[n](each final vleFluidType= - vleFluidType) "VLE Vapor ports" annotation (Placement(transformation( - extent={{-10,50},{10,70}}, rotation=0), iconTransformation(extent={{-10, - 50},{10,70}}))); - - TIL.Connectors.VLEFluidPort vleLiquidPort[k](each final vleFluidType= - vleFluidType) "VLE Liquid port" annotation (Placement(transformation( - extent={{-10,-70},{10,-50}}, rotation=0), iconTransformation(extent={ - {-10,-70},{10,-50}}))); - - parameter Integer n=0 - "Number of vapour ports, parameter is necessary for automatic increasing of ports" - annotation (Dialog(connectorSizing=true)); - - parameter Integer k=0 - "Number of liquid ports, parameter is necessary for automatic increasing of ports" - annotation (Dialog(connectorSizing=true)); - -public - TIL.Connectors.HeatPort heatPort annotation (Placement(transformation(extent= - {{30,-10},{50,10}}), iconTransformation(extent={{30,-10},{50,10}}))); - - /*********************** VLEFluid ***************************/ - - TILMedia.VLEFluid_dT vleFluid( - T=T, - d=d, - final vleFluidType=vleFluidType, - computeTransportProperties=false, - computeSurfaceTension=false) "VLEFluid in mixing volume" annotation ( - Placement(transformation(extent={{-10,-10},{10,10}}, rotation=0))); - - Modelica.SIunits.Density d(start=dInitial, fixed=true) "VLE fluid density"; - - Modelica.SIunits.Temperature T(start=TInitial, fixed=true) - "VLE fluid temperature"; - - Modelica.SIunits.SpecificEnergy u "VLE specific internal energy"; - - Modelica.SIunits.InternalEnergy U "VLE internal energy"; - - Real dudrho "derivative of internal energy u wrt to density rho"; - - Modelica.SIunits.Length l "height of liquid level"; - - Real l_relative "relative height of liquid level"; - - Real X "Vapour mass fraction"; - - Modelica.SIunits.Mass mass "VLE fluid mass"; - - /******************** Parameters ********************/ - - parameter Modelica.SIunits.Volume volume "fluid volume"; - parameter Modelica.SIunits.Area area "base area"; - final parameter Modelica.SIunits.Length height=volume/area - "height of VLE phase seperator"; - - /********************* Initialization ********************************/ - - parameter Modelica.SIunits.Density dInitial "Initial value for VLE density" - annotation (Dialog(group="Initial Values", tab="Start and Initialization")); - - parameter Modelica.SIunits.Temperature TInitial - "Initial value for VLE temperature" - annotation (Dialog(group="Initial Values", tab="Start and Initialization")); - - /*******************Summary**********************/ -public - inner parameter Boolean includeDefaultSummary=true - "include default entries in summary" - annotation (Dialog(tab="Advanced", group="Summary")); - - parameter Boolean generateEventsAtFlowReversal=false "If true, events are generated at flow reversal" annotation(Evaluate=true, Dialog(tab="Advanced", group="Event-Handling")); - -protected - record Summary - extends TIL.Internals.ClassTypes.Record; - - Modelica.SIunits.Pressure p_VLE if include; - Modelica.SIunits.Temperature T_VLE if include; - Modelica.SIunits.Mass mass_VLE if include; - - protected - outer parameter Boolean includeDefaultSummary; - parameter Boolean include=includeDefaultSummary; - - end Summary; - - replaceable record SummaryClass = Summary; - -public - SummaryClass summary( - p_VLE=vleFluid.p, - T_VLE=vleFluid.T, - mass_VLE=mass) annotation (Placement(transformation(extent={{66,-88},{86,-68}}, - rotation=0))); - -equation - //assert(T > 273.15, "Evaporator temperature must be above 0 °C"); Assert operator may be added for simulations with water - - // simport setup - connect(sim.fluidPort[vleFluidType.ID], simPort.vleFluidPort); - - simPort.vleFluidMass = mass; - simPort.vleFluidVolume = volume; - - mass = volume*d "Mass in cv"; - u = vleFluid.h - vleFluid.p/vleFluid.d "specific internal energy"; - U = mass*u; - - X = (vleFluid.VLE.d_l - d)/d*vleFluid.VLE.d_v/(vleFluid.VLE.d_l - vleFluid.VLE.d_v); - l = (1 - X)*mass/(vleFluid.VLE.d_l*area); - l_relative = l/height; - - // Momentum balances - for i in 1:n loop - vleFluid.p = vleVapourPort[i].p; - // vapour port: vapour enthalpy + 10 J/kg --> slightly overheated --> higher stability in valve models - vleVapourPort[i].h_outflow = vleFluid.VLE.h_v + 10; - vleVapourPort[i].h_limit = -1e6; - //no limiter used - end for; - - for i in 1:k loop - vleFluid.p = vleLiquidPort[i].p; - // liquid port: liquid enthalpy - 10 J/kg --> slightly subcooled --> higher stability in valve models - vleLiquidPort[i].h_outflow = vleFluid.VLE.h_l - 10; - vleLiquidPort[i].h_limit = -1e6; - //no limiter used - end for; - - // Calculation of du/drho using the Brdigeman table and the equation of Cl.-Clayperon - dudrho = 1/d^2*(-vleFluid.p + (vleFluid.VLE.h_v - vleFluid.VLE.h_l)/(1/ - vleFluid.VLE.d_v - 1/vleFluid.VLE.d_l)); - - if (generateEventsAtFlowReversal) then - u*volume*der(d) + mass*vleFluid.cv*der(T) + mass*dudrho*der(d) = sum( - vleVapourPort.m_flow .* actualStream(vleVapourPort.h_outflow)) + sum( - vleLiquidPort.m_flow .* actualStream(vleLiquidPort.h_outflow)) + heatPort.Q_flow - "Energy balance"; - else - u*volume*der(d) + mass*vleFluid.cv*der(T) + mass*dudrho*der(d) = sum( - vleVapourPort.m_flow .* noEvent(actualStream(vleVapourPort.h_outflow))) + sum( - vleLiquidPort.m_flow .* noEvent(actualStream(vleLiquidPort.h_outflow))) + heatPort.Q_flow - "Energy balance"; - end if; - - volume*der(d) = sum(vleVapourPort[:].m_flow) + sum(vleLiquidPort[:].m_flow) - "Mass balance"; - - heatPort.T = T; - - annotation ( - defaultComponentName="simpleEvapCond", - Icon(coordinateSystem(preserveAspectRatio=true, extent={{-40,-60},{40,60}}), - graphics={Bitmap( - extent={{-44,-62},{44,60}}, - imageSource= - "iVBORw0KGgoAAAANSUhEUgAAAPAAAAFuCAMAAAH/l1WxAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAByUExURZvI76rU9QAAADh/w5HB6qDN8myl2nux4WKe1nGq3VeW0bDY+L7j/kyOzb/k/zN7wbXd+ihzvYG15Cl0vQAAAHeu34a65lKSz7rg/S12v0iLyz2DxpbF7QAAAKXR84u96AAAAAAAAAAAAGei2Fya1EKGyPNjzFIAAAAjdFJOU///y///////////////////////x///////////NP//PP9ElpbsfAAAAAlwSFlzAAAXEQAAFxEByibzPwAAA3ZJREFUeF7t3dmKHDkURVE5PZTnsTxPFS77/3/RweWiJxFGCuoIH+311BBcNofuzrazOtPl+3akbC+P8LiJx01le3akbB+OlO33kbK9OlK2N0d43MTjpjt+fKjkv0xtPG7icdNW8qW3bSv50tu2lXzpbdtKvvS2bSX/eW/jcROPm+748fEvaw5x3InjThx3WvS4DNuPnwzbj78M24/zRXgAx5047sRxJ447nTy+zjcNRvzjfYhD1/z3uQ/HnTjuxHEnjjtx3InjTose59vxA/bj/D38gP043+kfsB/nGwAD9uP8IcKA/TjfPRiwH+fPJwbsx/kr7wEcd+K4E8edOO7EcSeOO3HcieNO/+/xCaeOz9jD+fscKcIyhGUIyxCWISxDWIawDGEZwjKEZQjLEJaZG/40QYR/TBDhBxNE+GqCCN9OEOGPE0T46wQRfjdBhPPtZynCMoRlCMsQliEsQ1iGsAxhGcIyhGUIyxCWISxDWCbCc5z6roQTbuYt5gdeGoRlCMsQliEsQ1iGsAxhGcIyhGUIyxCWISxDWIawDGEZwjKEZQjLEJYhLENYhrAMYRnCMouG89PXUhHOL0GXinB+7FsqwvnN7VIRzs+bS0U4v25eKsL5QXepCOd35EtFOD9hLxXh/GJ/qQjnR/ulIpx/GoFUhPM7BaQinH+EglSE88sMpCKc/8uzFGEZwjKEZQjLEJYhLENYhrAMYRnCMoRlCMsQliEsQ1iGsAxhGcIyhGUIyxCWISxDWIawDGEZwjKEZQjLLBqeY1b4MuvrZ2e5TPtbPEsMzs/F2GOwOwa7Y7A7BrtjsDsGu2OwOwa7Y7A7BrtjsDsGu2OwOwa7Y7A7BrtjsDsGu2OwOwa7Y7A7BrtjsDsGu2OwOwa7Y7A7BrtjsDsGu2OwOwa7Y7A7BrtjsDsGu2Owu3UHP19EHfx6EXXwvUXUwQ8XUQd/W0Qd/HMRdfDbRdTB7xdRBz9aRB38eBF18NNF1MEvFlEH/1lEHXx/EXXw50XUwfllxPYY7I7B7hjsjsHuGOyOwe4Y7I7B7hjsjsHuGOyOwe4Y7I7B7hjsjsHuGOyOwe4Y7I7B7hjsjsHuGOyOwe4Y7I7B7hjsjsHuGOyOwe4Y7I7B7hjsjsHuGOyOwe4Y7I7B7hjsjsHuGOyOwe4Y7G7dwSspN5f8qyVcfv0FM01fniGVbusAAAAASUVORK5CYII=", - fileName= - "modelica://SorpLib/Resources/Images/EvpCond.png")}), - Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-40,-60},{40, - 60}})), - Documentation(info="<html> - <p> - This model represents an ideal vapour liquid equilibrium (VLE) phase separator. The model has three ports: a VLE vapour port, a VLE liquid port, and a heat port. <br> - - </p> - <h4>Main equations</h4> - <p> - <p>Mass balance: </p> - <p align=\"center\"><i>V</i> <i>d<code>ρ</code>/dt</i> = <code>∑</code> <i><code>ṁ</code></i> </p> - <p>where <i>V</i> is the volume, <i>ρ</i> is the density of the VLE fluid, and <i><code>ṁ</code></i> are the mass flow rates at the VLE vapour ports, and the VLE liquid ports.</p> - <p>Energy balance: </p> - <p align=\"center\"><i>V u</i> <i>d<code>ρ</code>/dt</i> + <i>m</i> <i>c</i><sub>v</sub> <i>dT/dt</i> + <i>m du/d<code>ρ</code> d<code>ρ</code>/dt</i> = - <code>∑</code> <i><code>ṁ</code> h </i> + <code>∑</code> <i>Q</i> </p> - <p>where <i>c</i><sub>v</sub> is the specific heat capacity at constant volume, <i>u</i> is the specific internal energy at the current density and temperature, <i>h</i> is the specific enthalpy of the incoming and outflowing VLE streams, and <i>Q</i> is the heat flow.</p> - <p>The partial derivative <i>du/d<code>ρ</code></i> can be expressed as:</p> - <p align=\"center\"><i>du/d<code>ρ</code></i> = 1/<i><code>ρ</code></i><sup>2</sup> <i>( -p + T dpdT )</i> </p> - <p>where <i>dpdT</i> can be substituted with the equation of Clausius-Clayperon: <i>dpdT = (h<sup>v</sup> - h<sup>l</sup>) / (T (v<sup>v</sup> - v<sup>l</sup>)</i>. <br> - For more information see Gräber (2011) and Tummescheit (2002). <br></p> - The VLE phase seperator has two VLE ports, a liquid and a vapour VLE port. At the liquid VLE port, the specific enthalpy of the leaving fluid is slightly subccoled, at the vapour VLE port, the specific enthalpy of the leaving fluid is slightly superheated. - </p> - <h4>Assumptions and limitations</h4> - - <p> - The model uses the following main assumptions: - <ul> - <li>Liquid and vapour phase are in chemical equilibrium --> same pressure and temperature</li> - </ul> - </p> - <h4>Typical use and important parameters</h4> - <p> - For adsorption systems, the VLE phase separator is a core part of the the evaporator/condenser component. - </p> - <h4>Dynamics</h4> - <p> - The model has two states: the temperature <i>T</i> and the density <i><code>ρ</code></i>. - </p> - <h4>References</h4> - <p> - <ul> - <li>Tummescheit, H. Design and Implementation of Object-Oriented Model Libraries using Modelica. PhD Thesis. Lund, 2002.</li> - <li>Gräber, M.; Kirches, C.; Bock, H.G.; Schlöder, J.P.; Tegethoff, W.; Köhler, J. Determining the optimum cyclic operation of adsorption chillers by a direct method for periodic optimal control. Int. J. Refrig., 2011, 34(4), 902-913.</li> - </ul> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>November 22, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html> -")); -end VLEPhaseSeparator; diff --git a/SorpLib/Components/Cells/VLEPhaseSeparator/package.mo b/SorpLib/Components/Cells/VLEPhaseSeparator/package.mo deleted file mode 100644 index 6c6f6636fb1bb0cb22243fe5eace8e1ce9a5dee2..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/VLEPhaseSeparator/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.Cells; -package VLEPhaseSeparator -extends SorpLib.Internals.ClassTypes.ComponentPackage; - - -end VLEPhaseSeparator; diff --git a/SorpLib/Components/Cells/VLEPhaseSeparator/package.order b/SorpLib/Components/Cells/VLEPhaseSeparator/package.order deleted file mode 100644 index 47b6b56a731b325b3b0dfe156be112f895de700a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/VLEPhaseSeparator/package.order +++ /dev/null @@ -1,2 +0,0 @@ -VLEPhaseSeparator -Testers diff --git a/SorpLib/Components/Cells/Wall/Testers/TestWall.mo b/SorpLib/Components/Cells/Wall/Testers/TestWall.mo deleted file mode 100644 index 9d011ecb3945e4fe809dbc0354d69d5bf4ef7702..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Wall/Testers/TestWall.mo +++ /dev/null @@ -1,43 +0,0 @@ -within SorpLib.Components.Cells.Wall.Testers; -model TestWall - - Wall wall( - redeclare model WallMaterial = TILMedia.SolidTypes.TILMedia_Steel, - volume=0.1, - TInitial=333.15) - annotation (Placement(transformation(extent={{-8,-6},{8,6}}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary2( - Q_flowFixed=5000, - boundaryType="T", - TFixed=298.15) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={0,40}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary1(boundaryType="Q_flow", - Q_flowFixed=-8000) annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=90, - origin={0,-20}))); - HeatTransfer.HeatTransfer heatTransfer(redeclare model HeatTransfer = - HeatTransfer.HeatTransferPhenomena.ConstantAlphaA (constantAlphaA=500)) - annotation (Placement(transformation( - extent={{-8,-4},{8,4}}, - rotation=90, - origin={0,22}))); -equation - connect(heatBoundary1.heatPort, wall.heatPortA) annotation (Line( - points={{0,-20},{0,-6}}, - color={204,0,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(heatTransfer.heatPortA, wall.heatPortB) annotation (Line( - points={{0,14},{0,5.7}}, - color={204,0,0}, - thickness=0.5)); - connect(heatBoundary2.heatPort, heatTransfer.heatPortB[1]) annotation (Line( - points={{0,40},{0,35},{0,30}}, - color={204,0,0}, - thickness=0.5)); - annotation (Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, - -100},{100,100}})), experiment(StopTime=1000)); -end TestWall; diff --git a/SorpLib/Components/Cells/Wall/Testers/package.mo b/SorpLib/Components/Cells/Wall/Testers/package.mo deleted file mode 100644 index 0e04418dc2b5c0b4a4c4373cd16e97f10696271a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Wall/Testers/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.Cells.Wall; -package Testers - extends SorpLib.Internals.ClassTypes.ApplicationPackage; - -end Testers; diff --git a/SorpLib/Components/Cells/Wall/Testers/package.order b/SorpLib/Components/Cells/Wall/Testers/package.order deleted file mode 100644 index 0017d6dd9d9e85a98025a0209eb1c666c11e7aa1..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Wall/Testers/package.order +++ /dev/null @@ -1 +0,0 @@ -TestWall diff --git a/SorpLib/Components/Cells/Wall/Wall.mo b/SorpLib/Components/Cells/Wall/Wall.mo deleted file mode 100644 index 433249c4bea3aa633f39170f90c31e9bd6113491..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Wall/Wall.mo +++ /dev/null @@ -1,108 +0,0 @@ -within SorpLib.Components.Cells.Wall; -model Wall - - /********************* Connectors ****************************************/ - - TIL.Connectors.HeatPort heatPortA - annotation (Placement(transformation(extent={{-10,-50},{10,-30}}), - iconTransformation(extent={{-10,-50},{10,-30}}))); - TIL.Connectors.HeatPort heatPortB - annotation (Placement(transformation(extent={{-10,28},{10,48}}), - iconTransformation(extent={{-10,28},{10,48}}))); - TIL.Connectors.HeatPort heatPortC - annotation (Placement(transformation(extent={{68,-10},{88,10}}), - iconTransformation(extent={{68,-10},{88,10}}))); - TIL.Connectors.HeatPort heatPortD - annotation (Placement(transformation(extent={{-88,-10},{-68,10}}), - iconTransformation(extent={{-88,-10},{-68,10}}))); - - /********************* Solid ****************************************/ - - replaceable model WallMaterial = TILMedia.SolidTypes.BaseSolid constrainedby - TILMedia.SolidTypes.BaseSolid "Wall material" annotation (choicesAllMatching=true, Dialog( - group="Solid type")); - - TILMedia.Solid wallMaterial(T=T, - redeclare model SolidType=WallMaterial) "Wall material properties" annotation (Placement( - transformation(extent={{-10,-12},{10,8}}, rotation=0))); - - Modelica.SIunits.Temperature T "Temperature of wall material"; - - /********************* Parameters ****************************************/ - - parameter Modelica.SIunits.Volume volume "Volume of wall cell"; - - final parameter Modelica.SIunits.Mass mass=wallMaterial.d*volume - "Mass of wall cell"; - - /********************* Initialization ********************************/ - - parameter Modelica.SIunits.Temperature TInitial "Initial Temperature" annotation (Dialog(group="Initial Values", tab="Start and Initialization")); - -initial equation - - T=TInitial; - -equation - - // Heat ports - heatPortA.T=T; - heatPortB.T=T; - heatPortC.T=T; - heatPortD.T=T; - - // Energy balance - mass*wallMaterial.cp*der(T) =heatPortA.Q_flow + heatPortB.Q_flow + - heatPortA.Q_flow + heatPortB.Q_flow; - - annotation (Icon(coordinateSystem(preserveAspectRatio=false,extent={{-80,-40}, - {80,40}}), graphics={Bitmap(extent={{-95,40},{94,-42}}, - fileName= - "modelica://SorpLib/Resources/Images/Wall.png")}), - Diagram(coordinateSystem(preserveAspectRatio= - true, extent={{-80,-40},{80,40}}), graphics), - Documentation(info="<html> - <p> - This model represents a wall cell. For a cell, a lumped model approach is used with an uniform Temperatur. By combining more cells with a finite volume approach, a distributed model can be built, with a spatial and temperature distribution. The model has four heat ports to exchange heat with connected components. <br> - - </p> - <h4>Main equations</h4> - <p> - <p>Energy balance: </p> - <p align=\"center\"> <i>m</i> <i>c</i> <i>dT/dt</i> = <code>∑</code> <i>Q</i> </p> - <p>where <i>m</i> is the mass, <i>c</i> is the specific heat capacity, <i>T</i> is the temperature and <i>Q</i> is the heat flow. </p> - The temperature at each heat port is set equal to the wall temperature <i>T</i>. - </p> - - <h4>Assumptions and limitations</h4> - - <p> - The model uses the following main assumptions: - <ul> - <li>The wall cell has a uniform temperature --> heat conduction is not considered</li> - </ul> - </p> - - <h4>Typical use and important parameters</h4> - <p> - In heat exchangers the wall cell represents the thermal capacity of the metal mass. - </p> - <h4>Dynamics</h4> - <p> - The model has one state: the temperature <i>T</i>. - </p> - <h4>References</h4> - <p> - <ul> - </ul> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>November 23, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end Wall; diff --git a/SorpLib/Components/Cells/Wall/package.mo b/SorpLib/Components/Cells/Wall/package.mo deleted file mode 100644 index ed4dc6571676a9cf382dea851820a9dc2be23990..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/Wall/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.Cells; -package Wall - extends SorpLib.Internals.ClassTypes.ComponentPackage; - - -end Wall; diff --git a/SorpLib/Components/Cells/package.mo b/SorpLib/Components/Cells/package.mo deleted file mode 100644 index 71803c3ed672c9d2e2dcba30b868b317463a6dcc..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/package.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components; -package Cells -extends SorpLib.Internals.ClassTypes.ComponentPackage; - - - - -end Cells; diff --git a/SorpLib/Components/Cells/package.order b/SorpLib/Components/Cells/package.order deleted file mode 100644 index ada36aaa15f19fae1296027377234b5b0930a34a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Cells/package.order +++ /dev/null @@ -1,4 +0,0 @@ -Adsorbent -Gas -Wall -VLEPhaseSeparator diff --git a/SorpLib/Components/ClosedAdsorber/Adsorber.mo b/SorpLib/Components/ClosedAdsorber/Adsorber.mo deleted file mode 100644 index cbc651e37ffd9fae6340c864cb1b7497bd998b11..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/Adsorber.mo +++ /dev/null @@ -1,338 +0,0 @@ -within SorpLib.Components.ClosedAdsorber; -model Adsorber - "adsorber model including adsorbent, tube heat exchanger, and casing (optional) " - /********************************** SIM ***********************************/ - parameter TILMedia.VLEFluidTypes.BaseVLEFluid vleFluidType=sim.vleFluidType1 - "VLE fluid type" annotation (Dialog(tab="SIM", group="SIM"), choices( - choice=sim.vleFluidType1 "VLE fluid 1 as defined in SIM", - choice=sim.vleFluidType2 "VLE fluid 2 as defined in SIM", - choice=sim.vleFluidType3 "VLE fluid 3 as defined in SIM")); - - parameter TILMedia.LiquidTypes.BaseLiquid liquidType=sim.liquidType1 - "Liquid type" annotation (Dialog(tab="SIM", group="SIM"), choices( - choice=sim.liquidType1 "Liquid 1 as defined in SIM", - choice=sim.liquidType2 "Liquid 2 as defined in SIM", - choice=sim.liquidType3 "Liquid 3 as defined in SIM")); - -protected - outer TIL.SystemInformationManager sim "System information manager"; - TIL.Internals.SimPort simPort; - - /*************************** Connectors *************************************/ -public - TIL.Connectors.VLEFluidPort vlePortA(final vleFluidType=vleFluidType) - "VLE Port A" annotation (Placement(transformation(extent={{-4,17},{16,37}}, - rotation=0), iconTransformation(extent={{-4,17},{16,37}}))); - TIL.Connectors.VLEFluidPort vlePortB(final vleFluidType=vleFluidType) - "VLE Port B" annotation (Placement(transformation(extent={{-4,-55},{16,-35}}, - rotation=0), iconTransformation(extent={{-4,-55},{16,-35}}))); - - TIL.Connectors.LiquidPort liquidPortA(liquidType=liquidType) "Liquid PortA" - annotation (Placement(transformation(extent={{65,-41},{85,-21}}), - iconTransformation(extent={{65,-41},{85,-21}}))); - TIL.Connectors.LiquidPort liquidPortB(liquidType=liquidType) "Liquid Port B" - annotation (Placement(transformation(extent={{65,0},{85,20}}), - iconTransformation(extent={{65,0},{85,20}}))); - - TIL.Connectors.HeatPort heatPort if (enableHeatPort and enableCasing) - annotation (Placement(transformation(extent={{-69,-20},{-49,0}}, - rotation=0), - iconTransformation(extent={{-69,-20},{-49,0}}))); - - /******************** Components ***************************/ - - /***************************** Adsorbent ***********************************/ - -public - Cells.Adsorbent.Adsorbent adsorbent( - vleFluidType=vleFluidType, - massAdsorbent=massAdsorbent, - includeDefaultSummary=includeDefaultSummary, - xInitial=xInitial, - TInitial=TInitial, - pInitial=pInitial, - initial_x=initial_x, - redeclare final model AdsorbentAdsorbateModel = AdsorbentAdsorbateModel, - generateEventsAtFlowReversal=generateEventsAtFlowReversal) annotation ( - Placement(transformation( - extent={{-10,-10},{10,10}}, - rotation=270, - origin={6,-10}))); - - /*********************** Heat exchanger ***********************************/ - - TIL.LiquidComponents.Tubes.Tube heatexchanger( - enableHeatPorts=true, - initLiquid="linearTemperatureDistribution", - liquidType=liquidType, - steadyStateContinuity=true, - nCells=nCells, - redeclare model WallHeatConductionModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.WallHeatTransfer.GeometryBasedConduction, - redeclare parameter TubeGeometry tubeGeometry, - redeclare model TubeSideHeatTransferModel = TubeSideHeatTransferModel, - redeclare model PressureDropModel = PressureDropModel, - redeclare model WallMaterial = WallMaterial_hx, - TInitialWall(displayUnit="degC") = hx_TInitialWall, - TInitialLiquid_CellN=hx_TInitialCelln, - includeDefaultSummary=includeDefaultSummary, - TInitialLiquid_Cell1=hx_TInitialCell1) annotation (Placement(transformation( - extent={{8,2},{-8,-2}}, - rotation=270, - origin={51,-9.5}))); - - /******************************** Casing ***********************************/ - - TIL.OtherComponents.Thermal.HeatCapacitor casing( - solidMass=massCasing, - TInitial=TInitialCasing, - inputType="m, solid", - redeclare model WallMaterial = WallMaterial_casing) if enableCasing annotation (Placement( - transformation( - extent={{-6,-6},{6,6}}, - rotation=180, - origin={-38,-4}))); - - /********************* General Parameters ************************************/ - - inner parameter Boolean enableCasing=true "true, if casing is modeled" - annotation (Dialog(group="Casing")); - - inner parameter Boolean enableHeatPort=true - "true, if heat port to environment is enabled" - annotation (Dialog(enable=enableCasing, group="Casing")); - - /********************* Parameters Heat Exchanger*****************************/ - - replaceable model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Steel - constrainedby TILMedia.SolidTypes.BaseSolid - "Wall material of heat exchanger" annotation (choicesAllMatching=true, - Dialog(group="Heat Exchanger")); - - inner replaceable record TubeGeometry = - SorpLib.Components.ClosedAdsorber.Geometry.TubeGeometry constrainedby - SorpLib.Components.ClosedAdsorber.Geometry.TubeGeometry - "Geometry of tube" annotation (choicesAllMatching=true, Dialog(group="Heat Exchanger")); - - inner parameter TubeGeometry adsorberTubeGeometry "Geometry of adsorber tube"; - - parameter Integer nCells(min=1) = 1 - "Number of cells of heat exchanger (Discretization level of HX)" - annotation (Dialog(group="Heat Exchanger")); - - /********************* Parameters Adsorbent*****************************/ - - parameter Modelica.SIunits.Mass massAdsorbent=5 "Mass of dry sorbent" - annotation (Dialog(group="Adsorbent / Adsorbate")); - parameter Modelica.SIunits.Mass massCasing=2 "Mass of Container" - annotation (Dialog(group="Casing", enable=enableCasing)); - replaceable model WallMaterial_casing = TILMedia.SolidTypes.TILMedia_Steel - constrainedby TILMedia.SolidTypes.BaseSolid "Wall material of casing" - annotation (choicesAllMatching=true, Dialog(enable=enableCasing, group="Casing")); - - /*********************** Adorbent Adsorbate Model *************************/ - replaceable model AdsorbentAdsorbateModel = - SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater - constrainedby - SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater - " Water-Sorbent Model" annotation ( - Placement(transformation(extent={{-32,-70},{-12,-50}})), - choicesAllMatching=true, - Dialog(group="Adsorbent / Adsorbate")); - - /*********************** Heat transfer models ****************************/ - - HeatTransfer.HeatTransfer heatTransfer_1_n_HX(n=nCells, redeclare model - HeatTransfer = HeatTransferModel_HX) annotation (Placement(transformation( - extent={{-6.25,-3.25},{6.25,3.25}}, - rotation=0, - origin={30.25,-9.75}))); - - HeatTransfer.HeatTransfer heatTransfer_inner(redeclare model HeatTransfer = - HeatTransferModel_InternalCoupling) if enableCasing annotation ( - Placement(transformation( - extent={{-6,-3},{6,3}}, - rotation=180, - origin={-21,-10}))); - - replaceable model HeatTransferModel_HX = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA - constrainedby - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - "Adsorber heat transfer model between adsorber and heat exchanger wall" - annotation ( - extend=[10,20; -10,40], - Dialog(group="Heat Transfer"), - choices(choice(redeclare model - HeatTransferModel_HX = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlpha), - choice(redeclare model HeatTransferModel_HX = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA), - choice(redeclare model HeatTransferModel_HX = - SorpLib.Components.ClosedAdsorber.RecordsTransportCoefficients.HeatTransfer.HeatTransferSilicaGel_Lanzerath2015), - choice(redeclare model HeatTransferModel_HX = - SorpLib.Components.ClosedAdsorber.RecordsTransportCoefficients.HeatTransfer.HeatTransferZeolith13X_Lanzerath2015))); - - replaceable model HeatTransferModel_InternalCoupling = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA - constrainedby - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - "Adsorber heat transfer model for connection between adsorbent and casing" - annotation ( - extend=[10,20; -10,40], - choices(choice(redeclare model - HeatTransferModel_InternalCoupling = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlpha), - choice(redeclare model HeatTransferModel_InternalCoupling = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA)), - Dialog(group="Casing", enable=enableCasing)); - - replaceable model TubeSideHeatTransferModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.HeatTransfer.PartialHeatTransfer - constrainedby - TIL.LiquidComponents.Tubes.TransportPhenomena.HeatTransfer.PartialHeatTransfer - "Tube side heat transfer model" annotation ( - extend=[10,20; -10,40], - choicesAllMatching=true, - Dialog(group="Heat Transfer")); - - /*********************** Pressure drop ****************************/ - - replaceable model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop - constrainedby - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.PartialPressureDrop - "Pressure drop model" annotation ( - choicesAllMatching=true, - Dialog(group="Heat Exchanger"), - Placement(transformation(extent={{-10,20},{10,40}}, rotation=0))); - - /*******************Summary**********************/ -public - inner parameter Boolean includeDefaultSummary=true - "include default entries in summary" - annotation (Dialog(tab="Advanced", group="Summary")); - -protected - record Summary - extends TIL.Internals.ClassTypes.Record; - - Modelica.SIunits.Temperature T_liq_A if include; - Modelica.SIunits.Temperature T_liq_B if include; - Modelica.SIunits.Temperature T_cas if (include and enableCasing); - Modelica.SIunits.Pressure p_ad if include; - Real x_ad if include; - Modelica.SIunits.Temperature T_ad if include; - Modelica.SIunits.EnthalpyFlowRate DeltaH_flow_liq if include; - Modelica.SIunits.HeatFlowRate Q_flow_liq_ad if include; - Modelica.SIunits.HeatFlowRate Q_flow_ad_cas if (include and enableCasing); - Modelica.SIunits.HeatFlowRate Q_flow_cas_amb if (include and enableHeatPort); - - protected - outer parameter Boolean includeDefaultSummary; - parameter Boolean include=includeDefaultSummary; - outer parameter Boolean enableCasing; - outer parameter Boolean enableHeatPort; - - end Summary; - - replaceable record SummaryClass = Summary; - -public - SummaryClass summary( - T_liq_A=heatexchanger.summary.T_liq_A, - T_liq_B=heatexchanger.summary.T_liq_B, - T_cas=casing.T, - p_ad=adsorbent.adsorbentAdsorbate.p, - x_ad=adsorbent.x, - T_ad=adsorbent.T, - DeltaH_flow_liq = heatexchanger.portA.m_flow*(heatexchanger.summary.h_liq_A-heatexchanger.summary.h_liq_B), - Q_flow_liq_ad = -heatexchanger.summary.Q_flow_liq, - Q_flow_ad_cas = heatTransfer_inner.heatPortA.Q_flow, - Q_flow_cas_amb = heatPort.Q_flow) annotation (Placement(transformation(extent={{-59,-59}, - {-39,-39}},rotation=0))); - - /************************* Advanced ******************************/ - - parameter Boolean generateEventsAtFlowReversal=false - "If true, tranport propertie are calculated in the gas object" - annotation (Evaluate=true, Dialog(tab="Advanced", group="Event-Handling")); - - /********************* Initialization ********************************/ - parameter Modelica.SIunits.Temperature TInitial=343.15 - annotation (Dialog(group="Sorbent / Sorbate", tab="Initialization")); - parameter Boolean initial_x=true "if true then xInital else pInitial" - annotation (Dialog(group="Sorbent / Sorbate", tab="Initialization")); - parameter Real xInitial=0.2 annotation (Dialog( - enable=initial_x, - group="Sorbent / Sorbate", - tab="Initialization")); - parameter Modelica.SIunits.Pressure pInitial=10e2 annotation (Dialog( - enable=not initial_x, - group="Sorbent / Sorbate", - tab="Initialization")); - - parameter Modelica.SIunits.Temperature hx_TInitialCell1=288.15 - "Initial Temperature of heat exchanger fluid in cell 1" - annotation (Dialog(tab="Initialization", group="Heat Exchanger")); - parameter Modelica.SIunits.Temperature hx_TInitialCelln=298.15 - "Initial Temperature of heat exchanger fluid in cell n" - annotation (Dialog(tab="Initialization", group="Heat Exchanger")); - parameter Modelica.SIunits.Temperature hx_TInitialWall=293.15 - "Initial Temperature of heat exchanger wall" - annotation (Dialog(tab="Initialization", group="Heat Exchanger")); - - parameter Modelica.SIunits.Temperature TInitialCasing=343.15 - annotation (Dialog(group="Casing", tab="Initialization")); - -equation - - connect(heatTransfer_1_n_HX.heatPortB, heatexchanger.heatPort) annotation ( - Line( - points={{36.5,-9.75},{49,-9.75},{49,-9.5}}, - color={204,0,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(adsorbent.vlePortA, vlePortA) annotation (Line( - points={{6,-2.8},{6,27}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(adsorbent.vlePortB, vlePortB) annotation (Line( - points={{6,-17.2},{6,-45}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(liquidPortA, heatexchanger.portA) annotation (Line( - points={{75,-31},{51,-31},{51,-17.5}}, - color={0,170,238}, - thickness=0.5)); - connect(heatexchanger.portB, liquidPortB) annotation (Line( - points={{51,-1.5},{51,-1.5},{51,10},{75,10}}, - color={0,170,238}, - thickness=0.5)); - connect(adsorbent.heatPortB, heatTransfer_1_n_HX.heatPortA) annotation (Line( - points={{12,-10},{13,-10},{13,-9.75},{24,-9.75}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransfer_inner.heatPortB[1], casing.heatPort) annotation (Line( - points={{-27,-10},{-38,-10}}, - color={204,0,0}, - thickness=0.5)); - connect(casing.heatPort, heatPort) annotation (Line( - points={{-38,-10},{-38,-10},{-59,-10}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransfer_inner.heatPortA, adsorbent.heatPortA) annotation (Line( - points={{-15,-10},{-15,-10},{0,-10}}, - color={204,0,0}, - thickness=0.5)); - annotation (Diagram(coordinateSystem( - preserveAspectRatio=true, - grid={1,1}, - extent={{-60,-60},{70,40}})), Icon(coordinateSystem(preserveAspectRatio= - true, grid={1,1}, extent={{-60,-60},{70,40}}), graphics={Bitmap( - extent={{-57,-59},{77,41}}, - imageSource="iVBORw0KGgoAAAANSUhEUgAAAiIAAAGLCAYAAAD6T/mRAAAAAXNSR0ICQMB9xQAAAAlwSFlzAAAXEgAAFxIBZ5/SUgAAABl0RVh0U29mdHdhcmUATWljcm9zb2Z0IE9mZmljZX/tNXEAACOXSURBVHja7d0tcFXJuoDhJZGRyEhkJDISGYmMREbGwGEUx41EIrkOiUDsjEIikZGpW1fkuqg53NVr9tzJwM6w9/rp7q/Xc6reOlVMCP3fb/fqr7vruu7bfX755ZcOAADURavz9Q8ZA1rHgNbuwAwYy4gIoPOCiADGMiICEBEiAhjLiAig84KIAMay/UXE4AYAQP3iTUQAAAARISIAABARIgIAAIgIEQEAgIgQEQAAQESICAAARISIAAAAIkJEAAAgIkQEAAAQESICAAARISIAAICIqGwAAIgIEQEAAEQEAAAQESICAAARISIAAICIEBEAAIgIEQEAAESEiAAAQESICAAAICJEBAAAIkJEAAAAESEiAAAQESICAACICBEBAICIEBEAAEBEiAgAAESEiAAAACICAACICBEBAABEBAAAEBEiAgAAESEiAACAiBARAACICBEBAABEhIgAAEBEiAgAACAiRAQAACJCRAAAABEhIgAAEBEiAgAAiAgRAQCAiBARAABARIgIAABEhIgAAAAiAgAAiAgRAQCAiBARAABARIgIAABEhIgAAAAiQkQAACAiRAQAABARIgIAABEhIgAAgIgQEQAAiAgRAQAARISIAABARIgIAAAgIkQEAAAiQkQAAAARAQAARISIAAAAIgIAAIgIEQEAgIgQEQAAQESICAAARISIAAAAIkJEAAAgIkQEAAAQESICAAARISIAAICIEBEAAIgIEQEAAESEiAAAQESICAAAICJEBAAAIkJEAAAAEQEAAESEiDTCt0/do2+b7nnP6/9cdZv7/P5b96b/8/P+Zx7LawXp33THPRd9Wt/+Le1X3bv+zy97Tpppl43ndU11Kd9tlw0RwaRG3zfw99+uum/7kDpE/3eeyWuR9J/2afq8Z9qv+59/EbhdNp3XNdVl5HznXLREbxNEBKM6WN+Rfu0b9N2+E/MPk3SQHZLoeU3/dp+GDyPT/iXS6rL1vK6pLiPnO+eipZU2QURwcCcbGvCIhv9dJ7jpf9dTeV00/SfD6mda2u/633MWoF02ndc11WXUfOdetLTUJogIDp2Yb6dOzN91glN5XST9T8cOiDvZdM8rbpdN53VNdRk137kXLa21CSKCvW1/jo72QMc7ltdZ0380daX0gEhVsY27pryuqS6j5jv3oqXFNkFEsBdpy3Huifn+lqS8zpj+A75PH5j26yRpVdVV43ldU11GzHeJRUuLbYKIYB/jfzLrNuDurcEzeZ0l/ScLp/2ionbZdF7XVJdR85170dJqmyAi+CljT2UfeoJbXutP/7BSq2Ql3Xpe11SXEfNdYtHSapsgIvjZ1uPR0hPzvU53Kq8B0l/B/Sit53VNdRk137kXLS23CSKCn1n/ea7JOW1zymv96S9dT2vI65rqMmK+SyxaWm4TRAT/yHA1cKYOV/rzTPS85kp/DZ/RWs/rmuoyYr5LLFpabhNEBD/bftxknJxv5LX+9JeupzXkdU11GTHfJRYtLbcJIoKfDQxfs21BXpWtp+h5zZn+NbVL+ZPvGhYtLbcJIoKfdbjrFYlI6LzmTP+a2qX8yXcNi5aW2wQRQU3mfyuvIba1b9fSLkvldU11GTHfJRYtLbcJIoJ/ZKlb/B7oAF/ltf70l66nNeR1TXUZMd8lFi0ttwkign/k26a7zNXhUkeT1/rTnw7qraVdlsrrmuoyYr5LLFpabhNEBD8bGJ5k24Is/AJk9LxmS/+mO19NuyyU1zXVZcR8l1i0tNwmiAj22Ya8zmD9d+mSIHmdnP4vGdL+uJJ22XRe11SX0fJdatHSapsgItin0y1+eU8tNzxGz2t6m2IN9bSGvK6pLiPmu8SipdU2QURQfJWSDmPVtDKLntel0l/jCrr1vK6pLqPlu9SipcU2QUSw91bkMIkus/V4Jq+zpv/pIq+CVvhsfOt5XVNdRsx3iUVLi22CiKDslummu5TXRdJ/MfPK7G3F7bLpvK6pLqPlu9SipbU2QURwaMd7PpuNVyohreR1rsGqthDPNeZ1TXUZLd+lFi0ttQkigjEd72TKFcfDCqKyzzGt5jX925NWbJVv4a8pr2uqy2j5LrVoaaVNEBFMWq2kB5kOPXxV8yG5FvOaTt2ntBwyUPY/+zFtO4erp8bzuqa6jJbvUouWFtoEEcHkASKtBtL23q6JOnWung/DCfOAAtJSXvt0Hfe8GAah3YPT5/6/v44+aa0hr2uqy2j5LrVoidwmiAgAABYtRISIAABARIgIAAAgIkQEAAAiQkQAAAARISKxeN3/71//+tc3AAD+ie/n6xby1E+B50SEiAAAiAgRISIAABARIkJEAABEhIishb4i/ksHAwAQESKSnX//+9+PXr16dauDAQCICBEp8VnmUucCABARIlJCQh6/evXqTucCABARIlLibMiFjgUAICJEpOSuyOmrV6++TK3Ily9ffux/V1PPmAMA/o6bVbHo7shMh1bf9EJypEwBgIgQERxEEoheJH6dKiO90Nz0//9CmQIAESEiGCMkJy9fvtzMICSf+9/1VJkCABEhIhgjJGfb3Y2pn2vepwgdZQoARISIVMC3T92jb5vuec/r/1x1m/v8/lv3pv/z8/5nqpi404Vn6Qr4qWG+6fxJurMk/b5m6nHTHfdc9HX29m91eNW96//8sudkLYNTzW269v4WaTyovY+ULMu1jAdEpIGJq2+U779ddd/2ITXi/u88q2R35PHLly8/zPC55rr/XVXkaUI9nvZ183nPOrzuf77Z8zI1t+na+1vk8aC2PlKyLNc2HhCRwKvF3pJ/7Rvh3b4d5YdOU8mKaM3hvqkO+rr4MLIOv7S0Q1Jzm669v7U0HpTuIyXLcq3jAREJumIcGt2Ixvpdw73pf1c1Bz/XFu6bBo1hNTOtDu/633OmTS/Xpmvvb62OByX6SMmyXPN4QERiDti3UzvKdw33tJb8rSXcNw1SY1dcO9l0z7Xp+dt07f2t5fEgdx8pWZZrHw+ISLCt6zls/QF7P64pry2H+/b1eDR15fPAoBduW7bmNl17f2t5PMjdR0qWpfGAiIQifbecu6Pc/65ZY55bDPc95ADcgXV4nQZUbXqeNl17f2t5PMjdR0qWpfGAiETavn4y69bd7u28sxrz3lK4b1qlLFyHF9r09DZde39reTzI3UdKlqXxgIiEYuxJ6kNPXddcBmlHI+1sRA73Xboeh63gIKugmtt07f2t5fEgdx8pWZbGAyISZzfkU3e0dEe5Z9CntZdH1HDfbPUY4F6Imtt07f2t5fEgdx8pWZbGAyIS7bPMea7Okr6VRimXFBUTKdw3Vz1GqMOa23Tt/a3l8SB3HylZlsYDIhKK4TrfTJ2l9s8zO3ZHwoT75qrHCHVYc5uuvb+1PB7k7iMly9J4QERCMdzUl6+z3EQso/SJpfZw31z1GKEOa27Ttfe3lseD3H2kZFkaD4hINBH5mu075lXsstqG+17XGO6bsx616fHlUXt/a3k8yN1HSpal8YCIRBORayKyP7WG++asR216kohU3d9aHg9y95GSZWk8ICI+zTy8jXfbSiOoLdw341Zs9XVYc5uuvb+1PB7k7iMly9J4QERCsdTNew802q+tNIJ7QlJFuG+ueoxQhzW36dr7W8vjQe4+UrIsjQdEJBTfNt1lrs6SOkdrIvInpcN9c9VjOo2vTY9v07X3t5bHg9x9pGRZGg+ISDQReZLtO2bgV1z33B0pFu6brR433bk2Pb5N197fWh4PcveRkmVpPCAi4chxsGl4b+FTd9RKI/iJkBQJ913ihc8ddVjF436R23Tt/a3l8SB3HylZlsYDIhJtV2TxW/gi3ao6o5BkDfdNj1+pw/rbdO39reXxIHcfKVmWxgMiEnFX5MuC5nwbZSU9N7nDfZeqx0i7IRHadO39reXxIHcfKVmWxgMiEm1X5MnQqJf5jni2Rgn5bnckS7hvX9ZPF3l2PMiT31HadO39reXxIHcfKVmWxgMiElFGzhZosJdrl5DvhOTp0uG+aZCYeQv2rTY9f5uuvb+1PB7k7iMly3Lt4wERiTlwP5/NoAsMOt8+dY9SHnpep0t97tN3oDfDN9sKthS34b43S4X7zjX41BKeN6Vea27Ttfe36ONBjgl63z5SsixbGw+ISOMism20J1PeKhi2ITNvv/b/3vEhl/gMNw9uumcly3npcN9UB5O2hCvYfk1t8cB6/dj/ndNIbbr2/hZxPDhk1ydnHylZli2MB0RkRSJy36LT64qHnqTOueOQVsrp3xy70hiEpPAOyTbc9+MS4b4prO/Q8tlO5k+Ktr2U7gm3Q25F80mkNl17f4swHoxua5n7SKmyjDoeEJEVi8ifDTdtKaYtuV0dJxl2z4cSnzzSLsgcp8KHfG26p6XLeslw31RWPS+GQWV3GXxOnz1qGHCmrhp/tnqsuk1XnLYI6Zs6nuTsIyXLMtJ4QESISNWDxpwn0YcVwo4t/dxsw30va3vdN7OEzHvKv/EbfQEQESKSf1X2aIn4+O3OyHENeaztdd+Mcnm9yJ0HFex4ASAiRKQRhm+ly10QtKkprznCfWth2IZerl6vk8DqPwARISKYump+ssgFPZVfwLZ0uG8F9fps0ToNfOofABEhIitZNd9bPX+pMe8lX/fNUK9fMtTrjV0RgIgQEYxfNadT5kuvmv9aPZ/WWg5LhvuW2uXKWK8OrgJEhIhg9IR1nmvCivCyZO7XfRes19fZ6vWqe68vAUSEiGAUKd4+14RV6+eZ72kh3HfKxWUj6vWrvgQQESKCUQy3ZeabsG4ilU3kcN/h8qR89XqnLwFEhIhg7IT1NdtZgquY9boN9/0cKdx3ibtDWqtXAESEiNQhIiasPYkU7psjYoaIAESEiGCOCSvnp5nb6OW1Dfd9U3u4b46Q7PsXm+lLABEhIhiFQ42jhaTqcN8lb8qt/eZcAESEiATi26a7FOY5SUie1Rjum+5syXiPyKW+BBARIoKxE5aLryZyL9z3tpZw3+0jhreZ6vVYXwKICBHBaHIcWB3esvnUHbVcjrWF++a41CydRdGHACJCRDB1wlr8dtUIt6rOKCRVhPtud0VuFpVLuyEAESEimGlX5MuCE9ZtPyk+XluZ1hDuu+gLvF7eBYgIEcGMuyJPFjtTsOnO1lquNYT79uX/YoEdrrf6DUBEiAjmlpEzERWLCUnRcN+0ezFj9NM7dQoQESKCpWTk+fDtvxEJSeckUp7Swc1038V9+lX9m+F8TMbPRiXDfVNI75Rdr+2ZkAv9BCAiRARLy8jJlDdohsmu8OeYlIdDLmvr0/wxTdQ50lYy3DdJVzo4fKhsDq80O5gKgIgg82R+cWjUxXCjZ8GDqSlEeMptscOV95suy8N023DfdyXCfVMdpd2gJBi76jjJ5HBNfDpfQkAAEBGUnNjTp409Jqzz0pExU3dySu3oRHzdFwARISLAjxJyN/NB26w3wfYScR7ldV8ARISIAH9JyPESt8NuD2c+zZmXP8N9eyG5q/l1XwBEhIgAW5Z88n4QnE/do9x5qv11XwBEhIgAvyx8c2gFN4huw32/1va6LwAiQkSAX5a9mv7ershNiV2RP6nxdV8ARISIwG7IpnuS5Zn7AgdXH9gdKRbuCwBEBPhRRF7nEpF0N0kt+RbuC4CIEBFUwJSLy0Z8nvlaW/6F+wIgIkQEBenl4HNGEbmrsQyE+wIgIkQE5UTkOtsZkau626RwXwBEhIggv4h8ISI/CIlwXwBEhIggk4h8yPhp5jpKuQj3BUBEiAgyMLz0m09ENtHKZxvu+1a4LwAiQkSwAN823WnGe0Quo5aTcF8ARISIYAkR+dQ9+s9Vd5tJRI6jl1cvE8+F+wIgIkQE8+6KvM7wWeZDK+Ul3BcAESEimH9X5GbJ+0Na2A3ZISTHwn0BEBEignl2RZ4t+EnmouWymyvcN93yqi0CRISIYM0y8mL292V+696upfymhPumzzTuHAGICBEBGdl0FzM+cvdubeU3Idz3QvsDiAgRAf6QkdMpkTTbMyGrnlgPCfftf+6LdgcQESIC3JeRT93jdNnZIBUH7oL8eTA1/X8SkvR5Jl1m9ifbn7nsOWm9HLfhvv/9k7MhDqoCRISIAA8JSS8M50kedkXWpJ2T4Zr4dL7kLwE53fdV3+HRvf7vNiwiF72I/O9PRORUWwOICBEBZpCWsW/XDI/vNbRDkuRi30gan2YAIkJEgKkS0kvEsLsx/b6Rs+ACku4W+eCwKgAiQkSQT0KeHnqW5Cf3jjyPVgbb13pfj71tVfguQESICDBGQj51R1N3Qh7YGTmJUgZzvT/jQjOAiBAR4EB+v+reL3Qt/HW6er7mvPficPLy5cuNK94BEBEighK7IZvuZOHXei8qFZCjkZeWefQOABEB5mJshMwBuyI3te2KbMNxb6dKSHq9NwmNdgQQESICjNkN+dQdLbob8teuyLNKdkFO53jYLr3W2/+uJ9oQQESICNoSg8y3mKZLznKISLrdtbCAjA3H/f4zzHV6pbf2egVARIgIDp2oitxiOkyEGUQkXXRWolynhuPeE5Db9Cpv+n0R6hUAESEi2G+iKnyLaVqVZxKRm9xlO1c4bs/7Q+8GcTstQESICCLsghS/xbT/+1+znBG5yteOS4fjup0WICJEBBEkpIpbTOe+xKykiMwZjjv2UjK30wJEhIigfgmp6BbTjJ9mbpcs0znCcbfnSEaH47qdFiAiRAQhqOkW06XSsiNtXxfaBakmHHfNt9MCRISIIMpuSGW3mA6hoznCd6+6dzMLyFzhuF/HhOPWXq8AiAgRwU5qu8W0n+CeZLrQ7HyO8isdjhulXgEQESKCHyf9Sm8xHcJFl51E71I469TymzEc992h4bgR6xUAESEi+H73ocpbTFOYaM23qtb+Ou5abqcFQEQQnJpvMV1qV2TKbkgN4bjR6xUAESEiuD/ZV3uL6ez3X0w8ZFlDOG4L9QqAiBAR3J+wqr7FNEnDzJ8S3o7YBQn3Om6Lt9MCICJEpE0Rqf4W07lk5NBw3drCcVurVwBEhIggzC2m6fBq+h05PsfUGo7bYr0CICJEZOVEusU0haSmKI1Dzo30P/sx3Uuy778xYzju2znDcVuuVwBEhIismIi3mPZpPu55MUjG7snxc//fXx8iILWH466hXgEQESKyThEJdYvp3MwZjpt2U9QrACJCRHAgUW4xnZtI4bjqFQARISIt74pUfYvpArsgc4bjHqtXAESEiKDS1XNNq+bI4bjqFQARISKt74pUdYvpnMwdjqte66hXAEREhbcnI8VvMZ2bVsJx1SsAIkJExk8En7pH/WTwPIWUpoum7tMP6m+Gl1Ir2eYudYvp3LQWjqteARARIjJm8D855GKp7eVbpxWkO9stpgsISJPhuGuvVwBEhIgctgNyNOVmy+F67gMu41osDwvfYjo3rYfjrrVeARARInLgLsgcL58OK9d+BVtBfma/xXSBXZBVhOOurV4BEBEiMk5C7maOTmjq88DMArK6cFwAICJE5MEV5hJPrw9is+nCH5ackzWH4wIAESEiO+mF4cOCV2lfp8gb5SwcFwCICBHZtRvyLMPjYhdrLuOZw3FPtFsARISItLQb8mVpEen/jZs17ooIxwUAIkJE/nk3JM9z6ys8uDpnOG46V6K9AiAiRKRFEXmdS0TS3SQr2QWZKxz3w1rCcQGAiKyUKReXjfg887VxASkejru9X+Mivafyt6v4r7p3/Z9fphDtbJIb6GmAmtIetdwi13ekfrWGvBKRlTFc/JRPRO5aLMM5w3HT55yRg8fpvnU5RDFtuhdLDmQHPg2QbuKt4h6UkmmPWm6R6ztSv1pTXonI+kTkOtsZkav2yr10OG5aYY4NvR4OKc+4ukkr4kOvX/9hgiq0Yi6Z9qjlFrm+I/WrNeaViKxPRL4QkcOpIRx3exPu9dRdqjmu4t9eiPdlhl2zm9wX4JVMe9Ryi1zfkfrVWvNKRNYnIh9ySUhq8A0ISBXhuGnwnvU6/gkRTdtJ6XbGdnKX6xXnkmmPWm6R6ztSv1pzXonIykhbqxlFZBO5rGoJx00v0M79SW07GZyMSMujJXbVtivl46U/LZRKe9Ryi1zfkfrV2vNKRFZGWolkvEck5LsotYXjLhXpNOYq/iVFdmlxLZn2qOUWub4j9au155WIrE1E/ljh3GYSkeNIZVPj67hpxVHLVfzpMrzZX2v+MT1nCwl4sbRHLbfI9R2pX8krEVnrrsjil5qlsyhRyqOGcNyHWPpMzyFX8ec4X5Q+AyxRxyXTHrXcItd3pH4lr0RkzbsiNws2zLsouyEzh+MezVxPR5l2rp5Vk5Y/0nMashx3pD1quUWu70j9Sl6JyNp3RZ4t2Cir2Zb8h88ws4Tjpt+x1Ou4w82UGQaRdA6glrTsm54ay3FX2qOWW+T6jtSv5JWIkJFN92KBBvm2cgEJ8zrucMVyhkFkn+3xXGlZYru+ZNqjllvk+o7Ur+SViOAPGbmYTUL6Rl/5Z5hZwnHTeZIcr+MON1HmGURuaknLvumpsRx3pT1quUWu70j9Sl6JCP6SkdMpkTTbMyHVfo6J+jpuejQw12RQU1r2SU+t5fh92qOWW+T6jtSv5JWI4L6MfOoej3lHYvtC43GNeZo5HPe0wCByXZGIXAcWkeuCIhKy3Fp+k6qmfiWvRAQPCEk64JQEY1dkTdo5GcLB0vmSSgWk5nDcSrdVbyvbqr+NWI670h613CLXd6R+Ja9EBA1SczjuoSx1G+KOQeRrLWnZNz01luOutEctt8j1HalfySsRQUNECMc9eHdq013mGET2OWScKy3b9LyPWI670h613CLXd6R+Ja9EBG0ISJhw3BGDyJMsk8GmO68mLX+k53nIctyR9qjlFrm+I/UreSUiiP8ZJlQ47hiWePn0uy3Vu3QuaM+0LH7wbZueowXKsVjao5Zb5PqO1K/klYgg5i5IyHDckSuas0W3VA+4ETHHLY1L3UZZMu1Ryy1yfUfqV/JKRBBLQEKH49a2ohmzkllydTXcZbPgKrJk2qOWW+T6jtSv1p5XIoLqaSUcd8KK5ukiz7GPuIRu+zT87ULfmc8WLsdiaY9abpHrO1K/WnteiQiqZsZw3F9Lh+NOHEgu5hxAprwJtMhW76a7DLtNvWfao5Zb5PqO1K/WnFcigippMRy3loFkjrDCFOkw2wor86RUMu1Ryy1yfUfqV2vNKxFBbQIyWzhu/7vOWiuftDqdtFU+47Zx/7tOprxlMeSj0PZ8ybRHLbfI9R2pX60xr0QE1bCGcNxZBpJP3dGh7wL1P/sxfe9fapW16zmAn520r+FAX8m0Ry23yPUdqV+tKa9EBDXsgswZjlv1YDfzhHCc3vwZBojdA8fn/r+/zjFQpoEtbd/v8UbReW0TUsm0Ry23yPUdqV+tJa9EBCUFZK5w3C+RwnEBAEQEBVl7OC4AgIigEMJxAQBEBNkRjgsAICIoISDCcQEARERl50c4LgCAiBCR7GzDcf9nhnMgAIDG+X6+biFP/Tx4TkQK7oLoWAAAIkJESu2GPJ4algsAICJEBFNk5FLnAgAQESJShHSw1BkRAAARISL/z/ZNgYvff+ve/ueq2/xJeisiPcudXtac+azIf+lgAAAisnIR6QXjdHi4aL/XFa/TA0gzfZ55rYMBAIjISkUkvXg5vH55wFPd94Tky9QdEiICACAiKxWRJBHD7sYICbknI3f97zkjIgAAIkJEDpGQp4NETJCQv7Hpnk89uOoALwDgIdys2tbnmKOpOyEP7Iyc6CwAACJCRP6R36+693NKyN8OsX7q7GwAAIgIEXlgN2TTnSwhIfc+0VzoMJjURnuZTZ/6el7fDyEfwsh/6970f36eDllLH0BEiEhAxkbIHLArcmNXBCMl+fiQ3bo08fd/55n0AUSEiMRZaR4tuhvy165IiME39+Vt8vrwDkOfrl/HHp4eJvwFdyBqT1/UdlDbzpKyqT8tRKSNyeg8h4ikQbvycjg78PK2i6i7PLXnNQ3+w300c+zEbbqna0tfxHaQJvQDd5Y+pgsXlU3esqmtnohIIwxmn0FE0sBd667A2EllOwA9jVLXEfK6TePtzJFbp2tJX7R2kHZkpxyU337qeqJsli2b2uqJiDTG0EDyiMhNhRPz6dRJZTuRvKi9niPkNa0o59hpeGDn4bj19EVrB9vLE7/OUH63Uy5QVDax6omItCkiX3OISKKyifnZzGdgLiuWkBB5TZ/vFhThTevpi9QOtpPb3czpea5s5i2b2uqJiLQrItdrE5G5t9fvdbCz2uo3Sl7Ttu3sA96Maa49fZHawTYt1wvI3N2YTyPKJkY9ERGfZuZofLcV5fnLQnm8q+2uiCh5XTqEfOo5pdrTF6kdLFmWYy5QVDYx6omINCwiS92ouqPhfa1kh+BsyXzWFB0UJa/ZQsj/WKWetpa+SO1g9k8gu8vwQtlMK5va6omINC4iQyx8hgE2Ree0vENQ465IlLzmCiEfK0+1py9SO1g6Ldv07H2BorKJUU9EpH0ReZJppXcur/L6wK7cu1wT/ZjPH7WnL0o7yJaWP9LzXNmMK5va6omIrEBE1rRLkG4BzDSZfJDXg9rfJuNEf9Na+qK0g1xp2e7Avlc248qmtnoiIisRkbWcm1jTeZhIec0ZQp5oLX1R2kGutNSWnmhlU1s9EZGViMiSuyKVnZn4nKlz3cnrQWm9rlxEqk5flHaQKy21pSda2dRWT0RkRSKS4roXuSdhppPRMw3K1xEnk9bzmvnTx21r6YvSDmoTOmXThngTkfZk5GLmTzJv17DrU6mIhMlr7VvB0baqa20HOdNSW3oilU1t9UREViYic8pILeG633WwD5kmk2t5PajNXeYa9MYcjqs9fVHaQa601JaeaGVTWz0RkRWKyHbgPZt05XFFn2P+trJd8K2Q7zrXRl4Pam9VhwtGC2estR3kSktt6YlWNrXVExFZqYgMg2969rlvkIecG+l/9uNSTz3PJFinmSaT4g/gRctrju/S24PTRy2mL0I7yJaW2tITrGxqqycismIRudcoj9Oz1oNk7B48Pw9x5xULyD25erTI41Y/dq4TeT24nS1+e+mUMPLa0xehHWRLyx/pOVY248qmtnoiIkSkOZbedlzy4bLW87rkIblhYJ0YRl57+iK0gxyXZR1yyZ6yiVFPRISItPbJ6fHwxsFyhn8qr6N3HZ4sthIb8SR7tPRFaAfb1fbNgpPb3SGrbGUTo56ICBFp8XPT8yhb62vL6yK3/M54Zqf29EVoB4u+7DrioLyyiVFPRMTk3eInmjczG/5HeZ1v0pztcr0FJvna0xehHaRzZwtM/G+VzbxlU1s9ERG0KCNv5xp05njOWl7/NgCeTHnjZfiEsuTnjsrTF6EdzHmB4hz3FimbGPVERNDiZ5qLmuxeXn9M86HfqocDiJneN6o9fbW3g3SGYsq5m+1Zgwtls2zZ1FZPRAQtysjJobcJDhEUm+6ZvGZI86fuKH0OSaupXZN+GiCHPKUQ2wITfO3pq70dpDI59M6iP1fXcx14VDbx6omIoFUhebJd4W4eGGw+D9+SN91TeYU2P/+km2RtD6F7seTEpmxi1RMRAQAAJSdsIgIAAIgIEQEAgIgQEQAAQESICAAARISIAAAAIkJEAAAgIkQEAAAQESICAAARISIAAICIEBEAAIgIEQEAAESEiAAAQESICAAAICIqHAAAIkJEAAAAEQEAAESEiAAAQESICAAAICJEBAAAIkJEAAAAESEiAAAQESICAACICBEBAICIEBEAAEBEiAgAAESEiAAAACJCRAAAICJEBAAAEBEiAgAAESEiAACAiAAAACJCRAAAICJEBAAAEBEiAgAAESEiAACAiBARAACICBEBAABEhIgAAEBEiAgAACAiRAQAACJCRAAAABEhIgAAEBEiAgAAiAgRAQCAiBARAABARFQ2AABEhIgAAAAiAgAAiAgRAQCAiBARAABARIgIAABEhIgAAAAiQkQAACAiRAQAABARIgIAABEhIgAAgIgQEQAAiAgRAQAARISIAABARIgIAAAgIkQEAAAiQkQAAAARAQAARISIAAAAIgIAAIjI7PlSuQAAoLiIfG9aQOsYANaxagSMZUQE0HlBRABjGREBiAgRAYxlRATQeUFEAGPZwP8BPpR6YYI4vlEAAAAASUVORK5CYII=", - fileName="modelica://SorpLib/Resources/Images/ClosedAdsorber.png")})); -end Adsorber; diff --git a/SorpLib/Components/ClosedAdsorber/Geometry/Adsorber_Finned_Tubes_Alu.mo b/SorpLib/Components/ClosedAdsorber/Geometry/Adsorber_Finned_Tubes_Alu.mo deleted file mode 100644 index ee79202a66a4391632833ae0978fcb554f6e1f10..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/Geometry/Adsorber_Finned_Tubes_Alu.mo +++ /dev/null @@ -1,14 +0,0 @@ -within SorpLib.Components.ClosedAdsorber.Geometry; -record Adsorber_Finned_Tubes_Alu - "Finned tube Alu used for dissertation Lanzerath and mobile adsorption project" - extends TubeGeometry( - final innerDiameter=0.01285, - final wallThickness=0.004005, - length=7.355, - final nParallelTubes=1, - final crossSectionType=TIL.Internals.CrossSectionType.Circular, - final innerCrossSectionalAreaNonCircular=0, - final outerCrossSectionalAreaNonCircular=0, - final innerPerimeterNonCircular=0); - -end Adsorber_Finned_Tubes_Alu; diff --git a/SorpLib/Components/ClosedAdsorber/Geometry/TubeGeometry.mo b/SorpLib/Components/ClosedAdsorber/Geometry/TubeGeometry.mo deleted file mode 100644 index b49296c11ab267b64de23a8ed6917a7cb5ee1ff0..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/Geometry/TubeGeometry.mo +++ /dev/null @@ -1,56 +0,0 @@ -within SorpLib.Components.ClosedAdsorber.Geometry; -record TubeGeometry "Geometry record for a tube" - extends SorpLib.Internals.ClassTypes.Record; - - parameter Modelica.SIunits.Diameter innerDiameter=0.01 - "Inner diameter of circular tube" annotation (Dialog(group="Geometry", - enable=(crossSectionType == TIL.Internals.CrossSectionType.Circular))); - parameter Modelica.SIunits.Length wallThickness=0.0005 "Wall thickness" - annotation (Dialog(group="Geometry", enable=(crossSectionType == TIL.Internals.CrossSectionType.Circular))); - parameter Modelica.SIunits.Length length=1 "|Geometry|Length"; - - parameter Integer nParallelTubes(min=1) = 1 - "|Geometry|Number of parallel Tubes"; - - parameter TIL.Internals.CrossSectionType crossSectionType=TIL.Internals.CrossSectionType.Circular - "|Geometry|Tube Cross Section Type"; - - parameter Modelica.SIunits.Area innerCrossSectionalAreaNonCircular=0 - "Inner cross sectional area of one non-circular tube" annotation (Dialog( - group="Geometry", enable=not (crossSectionType == TIL.Internals.CrossSectionType.Circular))); - - parameter Modelica.SIunits.Area outerCrossSectionalAreaNonCircular=0 - "Outer cross sectional area of one non-circular tube" annotation (Dialog( - group="Geometry", enable=not (crossSectionType == TIL.Internals.CrossSectionType.Circular))); - - parameter Modelica.SIunits.Length innerPerimeterNonCircular=0 - "Perimeter of one non-circular tube" annotation (Dialog(group="Geometry", - enable=not (crossSectionType == TIL.Internals.CrossSectionType.Circular))); - - final parameter Modelica.SIunits.Diameter outerDiameter=innerDiameter + 2* - wallThickness; - final parameter Modelica.SIunits.Area innerCrossSectionalArea=if - tubeIsCircular then Modelica.Constants.pi*innerDiameter*innerDiameter/4.0 - *nParallelTubes else innerCrossSectionalAreaNonCircular*nParallelTubes - "Inner cross-sectional area"; - final parameter Modelica.SIunits.Area outerCrossSectionalArea=if - tubeIsCircular then Modelica.Constants.pi*outerDiameter*outerDiameter/4.0 - *nParallelTubes else outerCrossSectionalAreaNonCircular*nParallelTubes - "Outer cross-sectional area"; - final parameter Modelica.SIunits.Area hydraulicCrossSectionalArea=if - tubeIsCircular then Modelica.Constants.pi*innerDiameter*innerDiameter/4.0 - else innerCrossSectionalAreaNonCircular "Hydraulic cross sectional area"; - final parameter Modelica.SIunits.Diameter hydraulicDiameter=if tubeIsCircular - then innerDiameter else 4*innerCrossSectionalAreaNonCircular/ - innerPerimeterNonCircular "Hydraulic diameter"; - final parameter Modelica.SIunits.Volume innerVolume=innerCrossSectionalArea* - length "Inner volume"; - final parameter Modelica.SIunits.Volume outerVolume=outerCrossSectionalArea* - length "Outer volume"; - final parameter Modelica.SIunits.Area innerHeatTransferArea=if tubeIsCircular - then Modelica.Constants.pi*innerDiameter*length*nParallelTubes else - innerPerimeterNonCircular*length*nParallelTubes; - final parameter Boolean tubeIsCircular=(crossSectionType == TIL.Internals.CrossSectionType.Circular) - "true, if tube's cross section is circular"; - -end TubeGeometry; diff --git a/SorpLib/Components/ClosedAdsorber/Geometry/package.mo b/SorpLib/Components/ClosedAdsorber/Geometry/package.mo deleted file mode 100644 index 96a51a780e90895818e11aad91c8ad82489b0afb..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/Geometry/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.ClosedAdsorber; -package Geometry -extends SorpLib.Internals.ClassTypes.RecordPackage; - - -end Geometry; diff --git a/SorpLib/Components/ClosedAdsorber/Geometry/package.order b/SorpLib/Components/ClosedAdsorber/Geometry/package.order deleted file mode 100644 index ca85bb44bfbab8945608c43476b1f6160dea3bf4..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/Geometry/package.order +++ /dev/null @@ -1,2 +0,0 @@ -TubeGeometry -Adsorber_Finned_Tubes_Alu diff --git a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/HeatTransferSilicaGel_Lanzerath2015.mo b/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/HeatTransferSilicaGel_Lanzerath2015.mo deleted file mode 100644 index efedc1f7d37ce48347bd43701d30f77758a78d99..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/HeatTransferSilicaGel_Lanzerath2015.mo +++ /dev/null @@ -1,28 +0,0 @@ -within SorpLib.Components.ClosedAdsorber.RecordsTransportCoefficients.HeatTransfer; -model HeatTransferSilicaGel_Lanzerath2015 - "Heat transfer coefficient heat exchanger to adsorbent (Silica gel) (Lanzerath2015)" - extends SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlpha(final constantAlpha=686.7, final heatTransferArea=Modelica.Constants.pi*0.02086*adsorberTubeGeometry.length); - - outer parameter SorpLib.Components.ClosedAdsorber.Geometry.TubeGeometry adsorberTubeGeometry; - - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false)), - Documentation(info="<html> -<p> - The heat transfer coefficient in this record was determined by Lanzerath et. al. (2015) for silica gel 123 particles. -</p> -<h4>References</h4> -<ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end HeatTransferSilicaGel_Lanzerath2015; diff --git a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/HeatTransferZeolith13X_Lanzerath2015.mo b/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/HeatTransferZeolith13X_Lanzerath2015.mo deleted file mode 100644 index b6f20cf0687f8533520a37c9cf6ec82462812eab..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/HeatTransferZeolith13X_Lanzerath2015.mo +++ /dev/null @@ -1,28 +0,0 @@ -within SorpLib.Components.ClosedAdsorber.RecordsTransportCoefficients.HeatTransfer; -model HeatTransferZeolith13X_Lanzerath2015 - "Heat transfer coefficient heat exchanger to adsorbent (Zeolite13X) (Lanzerath2015)" - extends SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlpha(final constantAlpha=294.6, final heatTransferArea=Modelica.Constants.pi*0.02086*adsorberTubeGeometry.length); - - outer parameter SorpLib.Components.ClosedAdsorber.Geometry.TubeGeometry adsorberTubeGeometry; - - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false)), - Documentation(info="<html> -<p> - The heat transfer coefficient in this record was determined by Lanzerath et. al. (2015) for zeolite 13 X particles. -</p> -<h4>References</h4> -<ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end HeatTransferZeolith13X_Lanzerath2015; diff --git a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/package.mo b/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/package.mo deleted file mode 100644 index 6e41626ea85bed426722c7704d7f43ef02b96d91..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.ClosedAdsorber.RecordsTransportCoefficients; -package HeatTransfer -extends SorpLib.Internals.ClassTypes.RecordPackage; - -end HeatTransfer; diff --git a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/package.order b/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/package.order deleted file mode 100644 index 14a2e44875631bdb77dd1efa80c8fc77c07ddbc5..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/HeatTransfer/package.order +++ /dev/null @@ -1,2 +0,0 @@ -HeatTransferSilicaGel_Lanzerath2015 -HeatTransferZeolith13X_Lanzerath2015 diff --git a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/package.mo b/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/package.mo deleted file mode 100644 index 9c840d9fee6ab23916af437018bc408374cb886d..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.ClosedAdsorber; -package RecordsTransportCoefficients -extends SorpLib.Internals.ClassTypes.RecordPackage; - -end RecordsTransportCoefficients; diff --git a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/package.order b/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/package.order deleted file mode 100644 index 2dc6ac88dcb02452267722241d53e148e08190d1..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/RecordsTransportCoefficients/package.order +++ /dev/null @@ -1 +0,0 @@ -HeatTransfer diff --git a/SorpLib/Components/ClosedAdsorber/Testers/TestAdsorber1.mo b/SorpLib/Components/ClosedAdsorber/Testers/TestAdsorber1.mo deleted file mode 100644 index 2cd05499adf0e4472949588150a4d44597e90659..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/Testers/TestAdsorber1.mo +++ /dev/null @@ -1,96 +0,0 @@ -within SorpLib.Components.ClosedAdsorber.Testers; -model TestAdsorber1 - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1, redeclare - TILMedia.LiquidTypes.TILMedia_Water liquidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - Adsorber adsorber( - enableHeatPort=false, - xInitial=0.10, - initial_x=true, - redeclare model HeatTransferModel_InternalCoupling = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA, - enableCasing=false, - redeclare model AdsorbentAdsorbateModel = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Aluminum, - nCells=10, - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - includeDefaultSummary=true, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ConstantZeta - (zeta=1, massFlowLimit=0.001), - redeclare record TubeGeometry = Geometry.Adsorber_Finned_Tubes_Alu, - redeclare model HeatTransferModel_HX = - RecordsTransportCoefficients.HeatTransfer.HeatTransferSilicaGel_Lanzerath2015, - TInitial=303.15, - hx_TInitialCell1=293.15, - hx_TInitialCelln=293.15, - hx_TInitialWall=293.15) - annotation (Placement(transformation(extent={{-10,-8},{10,8}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundaryA( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=270, - origin={0,20}))); - Modelica.Blocks.Sources.Step stepVLEBounday_vapour( - height=-0.001, - offset=0.001, - startTime=50) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=270, - origin={2,38}))); - Modelica.Blocks.Sources.Step stepVLEBounday_liquid( - height=0.001, - offset=-0.001, - startTime=100) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=90, - origin={-2,-36}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundaryB( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true, - hFixed=2.5e6) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={0,-20}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryB(boundaryType="p") - annotation (Placement(transformation(extent={{36,6},{44,26}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryA(m_flowFixed=-0.1, TFixed= - 313.15) - annotation (Placement(transformation(extent={{36,-24},{44,-4}}))); -equation - connect(adsorber.vlePortA, vleBoundaryA.port) annotation (Line( - points={{0.153846,5.92},{0.153846,11.46},{0,11.46},{0,20}}, - color={153,204,0}, - thickness=0.5)); - connect(adsorber.vlePortB, vleBoundaryB.port) annotation (Line( - points={{0.153846,-5.6},{0.153846,-12.05},{0,-12.05},{0,-20}}, - color={153,204,0}, - thickness=0.5)); - connect(vleBoundaryB.m_flow_in, stepVLEBounday_liquid.y) - annotation (Line(points={{-2,-24},{-2,-29.4}}, color={0,0,127})); - connect(stepVLEBounday_vapour.y, vleBoundaryA.m_flow_in) - annotation (Line(points={{2,31.4},{2,24}}, color={0,0,127})); - connect(liquidBoundaryB.port, adsorber.liquidPortB) annotation (Line( - points={{40,16},{20,16},{20,3.2},{10.7692,3.2}}, - color={0,170,238}, - thickness=0.5)); - connect(liquidBoundaryA.port, adsorber.liquidPortA) annotation (Line( - points={{40,-14},{20,-14},{20,-3.36},{10.7692,-3.36}}, - color={0,170,238}, - thickness=0.5)); - annotation ( - Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ - 100,100}})), - experiment(StopTime=500, Interval=1), - __Dymola_experimentSetupOutput); -end TestAdsorber1; diff --git a/SorpLib/Components/ClosedAdsorber/Testers/TestAdsorber2.mo b/SorpLib/Components/ClosedAdsorber/Testers/TestAdsorber2.mo deleted file mode 100644 index 819d8dace6c44c459e6dd8eea86a9279f2f30417..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/Testers/TestAdsorber2.mo +++ /dev/null @@ -1,107 +0,0 @@ -within SorpLib.Components.ClosedAdsorber.Testers; -model TestAdsorber2 - import SorpLib; - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1, redeclare - TILMedia.LiquidTypes.TILMedia_Water liquidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - Adsorber adsorber( - xInitial=0.10, - redeclare record TubeGeometry = - SorpLib.Components.ClosedAdsorber.Geometry.Adsorber_Finned_Tubes_Alu, - initial_x=true, - redeclare model AdsorbentAdsorbateModel = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Aluminum, - nCells=10, - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - includeDefaultSummary=true, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ConstantZeta - (zeta=1, massFlowLimit=0.001), - enableCasing=true, - enableHeatPort=true, - redeclare model HeatTransferModel_InternalCoupling = - HeatTransfer.HeatTransferPhenomena.ConstantAlphaA (constantAlphaA=50), - redeclare model HeatTransferModel_HX = - SorpLib.Components.ClosedAdsorber.RecordsTransportCoefficients.HeatTransfer.HeatTransferSilicaGel_Lanzerath2015, - TInitial=576.3, - hx_TInitialCell1=566.3, - hx_TInitialCelln=566.3, - hx_TInitialWall=566.3) - annotation (Placement(transformation(extent={{-10,-8},{10,8}}))); - - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryA(m_flowFixed=-0.1, TFixed= - 313.15) - annotation (Placement(transformation(extent={{36,-24},{44,-4}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundaryA( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=270, - origin={0,20}))); - Modelica.Blocks.Sources.Step stepVLEBounday_vapour( - height=-0.001, - offset=0.001, - startTime=50) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=270, - origin={2,38}))); - Modelica.Blocks.Sources.Step stepVLEBounday_liquid( - height=0.001, - offset=-0.001, - startTime=100) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=90, - origin={-2,-36}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundaryB( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true, - hFixed=2.5e6) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={0,-20}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryB(boundaryType="p") - annotation (Placement(transformation(extent={{36,6},{44,26}}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary(boundaryType="Q_flow", - Q_flowFixed=100) - annotation (Placement(transformation(extent={{-4,-6},{4,6}}, - rotation=180, - origin={-24,0}))); -equation - connect(adsorber.vlePortA, vleBoundaryA.port) annotation (Line( - points={{0.153846,5.92},{0.153846,11.46},{0,11.46},{0,20}}, - color={153,204,0}, - thickness=0.5)); - connect(liquidBoundaryA.port, adsorber.liquidPortA) annotation (Line( - points={{40,-14},{20,-14},{20,-3.36},{10.7692,-3.36}}, - color={0,170,238}, - thickness=0.5)); - connect(adsorber.vlePortB, vleBoundaryB.port) annotation (Line( - points={{0.153846,-5.6},{0.153846,-12.05},{0,-12.05},{0,-20}}, - color={153,204,0}, - thickness=0.5)); - connect(vleBoundaryB.m_flow_in, stepVLEBounday_liquid.y) - annotation (Line(points={{-2,-24},{-2,-29.4}}, color={0,0,127})); - connect(stepVLEBounday_vapour.y, vleBoundaryA.m_flow_in) - annotation (Line(points={{2,31.4},{2,24}}, color={0,0,127})); - connect(adsorber.liquidPortB, liquidBoundaryB.port) annotation (Line( - points={{10.7692,3.2},{10.7692,3.2},{20,3.2},{20,16},{40,16}}, - color={0,170,238}, - thickness=0.5)); - connect(adsorber.heatPort, heatBoundary.heatPort) annotation (Line( - points={{-9.84615,-4.44089e-016},{-9.84615,0.46},{-24,0.46},{-24,0}}, - color={204,0,0}, - thickness=0.5)); - annotation ( - Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ - 100,100}})), - experiment(StopTime=500, Interval=1), - __Dymola_experimentSetupOutput); -end TestAdsorber2; diff --git a/SorpLib/Components/ClosedAdsorber/Testers/package.mo b/SorpLib/Components/ClosedAdsorber/Testers/package.mo deleted file mode 100644 index 12b147b0fab1ec70c7694bed7f95cbbbeb8cd0cc..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/Testers/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.ClosedAdsorber; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - -end Testers; diff --git a/SorpLib/Components/ClosedAdsorber/Testers/package.order b/SorpLib/Components/ClosedAdsorber/Testers/package.order deleted file mode 100644 index 8e2602413228556a8ed574fb93e7d3b385654332..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/Testers/package.order +++ /dev/null @@ -1,2 +0,0 @@ -TestAdsorber1 -TestAdsorber2 diff --git a/SorpLib/Components/ClosedAdsorber/package.mo b/SorpLib/Components/ClosedAdsorber/package.mo deleted file mode 100644 index 3f79a6389a1bf0c8ef5fb9a07dbf08dd650de82f..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/package.mo +++ /dev/null @@ -1,7 +0,0 @@ -within SorpLib.Components; -package ClosedAdsorber "Model of a closed adsorber: combining adsorbent and heat exchanger" -extends SorpLib.Internals.ClassTypes.ComponentPackage; - - - -end ClosedAdsorber; diff --git a/SorpLib/Components/ClosedAdsorber/package.order b/SorpLib/Components/ClosedAdsorber/package.order deleted file mode 100644 index 69b07111b09a03991b6e35cc396baa01933ba7ba..0000000000000000000000000000000000000000 --- a/SorpLib/Components/ClosedAdsorber/package.order +++ /dev/null @@ -1,4 +0,0 @@ -Adsorber -Geometry -RecordsTransportCoefficients -Testers diff --git a/SorpLib/Components/EvpCond/EvpCond.mo b/SorpLib/Components/EvpCond/EvpCond.mo deleted file mode 100644 index 792d4a5fe1ad2ece20b2d52dc45e48bd7eae1c13..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/EvpCond.mo +++ /dev/null @@ -1,321 +0,0 @@ -within SorpLib.Components.EvpCond; -model EvpCond - "evaporator/condenser model including VLE separator, tube heat exchanger, and casing (optional) " - - /*********************** SIM ***********************************/ - - parameter TILMedia.VLEFluidTypes.BaseVLEFluid vleFluidType=sim.vleFluidType1 - "VLE fluid type" annotation (Dialog(tab="SIM", group="SIM"), choices( - choice=sim.vleFluidType1 "VLE fluid 1 as defined in SIM", - choice=sim.vleFluidType2 "VLE fluid 2 as defined in SIM", - choice=sim.vleFluidType3 "VLE fluid 3 as defined in SIM")); - - parameter TILMedia.LiquidTypes.BaseLiquid liquidType=sim.liquidType1 - "Liquid type" annotation (Dialog(tab="SIM", group="SIM"), choices( - choice=sim.liquidType1 "Liquid 1 as defined in SIM", - choice=sim.liquidType2 "Liquid 2 as defined in SIM", - choice=sim.liquidType3 "Liquid 3 as defined in SIM")); - -protected - outer TIL.SystemInformationManager sim "System information manager"; - - TIL.Internals.SimPort simPort; - - /********************** Connectors **************************/ -public - TIL.Connectors.VLEFluidPort vlePort_vapour[nports](each final vleFluidType= - vleFluidType) "VLE port (vapour)" annotation (Placement(transformation( - extent={{-10,28},{10,48}}, rotation=0), iconTransformation(extent={{-10, - 28},{10,48}}))); - - TIL.Connectors.VLEFluidPort vlePort_liquid[kports](each final vleFluidType= - vleFluidType) "VLE port (liquid)" annotation (Placement(transformation( - extent={{-10,-48},{10,-28}}, rotation=0), iconTransformation(extent={{ - -10,-48},{10,-28}}))); - TIL.Connectors.LiquidPort liquidPortA(final liquidType=liquidType) - "Liquid portA" annotation (Placement(transformation(extent={{-110,-20},{-90, - 0}}, rotation=0), iconTransformation(extent={{-110,-20},{-90,0}}))); - TIL.Connectors.LiquidPort liquidPortB(final liquidType=liquidType) - "Liquid portB" annotation (Placement(transformation(extent={{90,-20},{110,0}}, - rotation=0), iconTransformation(extent={{90,-20},{110,0}}))); - - TIL.Connectors.HeatPort heatPort if (enableHeatPort and enableCasing) - "Heat Port ambient" annotation (Placement(transformation(extent={{56,26},{76, - 46}}, rotation=0), iconTransformation(extent={{56,26},{76,46}}))); - - /******************** Components ***************************/ - - /*********************** VLE volume ***********************************/ -public - Cells.VLEPhaseSeparator.VLEPhaseSeparator volume( - vleFluidType=vleFluidType, - n=nports, - volume(displayUnit="l") = freeVolume, - area=basearea, - dInitial=dInitial, - TInitial=TInitial, - k=kports) annotation (Placement(transformation( - extent={{-6.50003,-9.5},{6.50001,9.5}}, - rotation=0, - origin={0,10}))); - - /*********************** Heat exchanger ***********************************/ - - TIL.LiquidComponents.Tubes.Tube heatexchanger( - enableHeatPorts=true, - steadyStateContinuity=true, - initLiquid="linearTemperatureDistribution", - redeclare model WallHeatConductionModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.WallHeatTransfer.GeometryBasedConduction, - liquidType=liquidType, - redeclare model TubeSideHeatTransferModel = - TubeSideHeatTransferModel, - TInitialLiquid_CellN=hx_TInitialCelln, - TInitialLiquid_Cell1=hx_TInitialCell1, - TInitialWall=hx_TInitialWall, - redeclare parameter TubeGeometry tubeGeometry, - redeclare model PressureDropModel = PressureDropModel, - redeclare model WallMaterial = WallMaterial_hx, - nCells=nCells) annotation (Placement( - transformation( - extent={{-8,-2},{8,2}}, - rotation=0, - origin={34,-22}))); - - /*********************** Casing ***********************************/ - - TIL.OtherComponents.Thermal.HeatCapacitor casing( - solidMass=massCasing, - TInitial=TInitialCasing, - inputType="m, solid", - redeclare model WallMaterial = WallMaterial_casing) if enableCasing annotation (Placement( - transformation( - extent={{-6,-6},{6,6}}, - rotation=90, - origin={72,20}))); - - /*********************** Heat Transfer ***********************************/ - - HeatTransfer.HeatTransfer heatTransfer_tube_VLE(redeclare model HeatTransfer = - VLESideHeatTransferModel, n=nCells) annotation (Placement( - transformation( - extent={{6,3},{-6,-3}}, - rotation=90, - origin={34,-5}))); - - HeatTransfer.HeatTransfer heatTransfer_inner(redeclare model HeatTransfer = - HeatTransferModel_InternalCoupling, n=1) if - enableCasing annotation ( - Placement(transformation( - extent={{-6,-3},{6,3}}, - rotation=0, - origin={51,20}))); - - /********************* General Parameters ************************************/ - - inner parameter Boolean enableCasing=true "true, if casing is modeled" - annotation (Dialog(group="Casing"),choices(choice = true - "Casing is modelled", choice = false - "Casing is neglected")); - - inner parameter Boolean enableHeatPort=true - "true, if heat port to environment is enabled" - annotation (Dialog(enable=enableCasing, group="Casing")); - - /******************** Parameters Geometry ********************/ - - parameter Integer nports=0 "Number of connected adsorber units" - annotation (Dialog(connectorSizing=true)); - - parameter Integer kports=0 "Number of connected adsorber units" - annotation (Dialog(connectorSizing=true)); - - parameter Integer nCells=10 "number of hx discretization"; - - replaceable record TubeGeometry = - SorpLib.Components.EvpCond.Geometry.TubeGeometry constrainedby - SorpLib.Components.EvpCond.Geometry.TubeGeometry - "Geometry of tube" annotation (choicesAllMatching=true, Dialog(group= - "Geometry")); - - parameter Modelica.SIunits.Volume freeVolume=0.001 "free fluid volume" - annotation (Dialog(group="Geometry")); - - parameter Modelica.SIunits.Area basearea=heatexchanger.tubeGeometry.length - *heatexchanger.tubeGeometry.outerDiameter "base area of vle volume" - annotation (Dialog(group="Geometry")); - - replaceable model WallMaterial_hx = - TILMedia.SolidTypes.TILMedia_Steel - constrainedby TILMedia.SolidTypes.BaseSolid - "Wall material of heat exchanger" annotation (choicesAllMatching=true, - Dialog(group="Geometry")); - - parameter Modelica.SIunits.Mass massCasing=2 "Mass of Container" - annotation (Dialog(group="Casing", enable=enableCasing)); - replaceable model WallMaterial_casing = - TILMedia.SolidTypes.TILMedia_Steel - constrainedby TILMedia.SolidTypes.BaseSolid "Wall material of casing" - annotation (choicesAllMatching=true, Dialog(enable=enableCasing, group= - "Casing")); - - /*********************** Heat transfer models ****************************/ - - replaceable model VLESideHeatTransferModel = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA - constrainedby - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - "VLE side Heat Transfer Model" annotation (Placement(transformation(extent= - {{-32,-70},{-12,-50}})), choicesAllMatching=true); - - replaceable model HeatTransferModel_InternalCoupling = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA - constrainedby - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - "Internal heat transfer model for connection between VLE fluid and casing" - annotation ( - extend=[10,20; -10,40], - choicesAllMatching=true, - Dialog(group="Casing", enable=enableCasing)); - - replaceable model TubeSideHeatTransferModel = - SorpLib.Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate - constrainedby - TIL.LiquidComponents.Tubes.TransportPhenomena.HeatTransfer.PartialHeatTransfer - "Tube side heat transfer model" annotation (extend=[10,20; -10,40], - choicesAllMatching=true); - - /*********************** Pressure drop ****************************/ - - replaceable model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop - constrainedby - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.PartialPressureDrop - "Pressure drop model" annotation ( - choicesAllMatching=true, - Dialog(group="Pressure drop"), - Placement(transformation(extent={{-10,20},{10,40}}, rotation=0))); - - /*******************Summary**********************/ -public - inner parameter Boolean includeDefaultSummary=true - "include default entries in summary" - annotation (Dialog(tab="Advanced", group="Summary")); - -protected - record Summary - extends TIL.Internals.ClassTypes.Record; - - Modelica.SIunits.Temperature T_liq_A if include; - Modelica.SIunits.Temperature T_liq_B if include; - Modelica.SIunits.Temperature T_cas if (include and enableCasing); - Modelica.SIunits.Pressure p_VLE if include; - Modelica.SIunits.Density d_VLE if include; - Modelica.SIunits.Temperature T_VLE if include; - Modelica.SIunits.EnthalpyFlowRate DeltaH_flow_liq if include; - Modelica.SIunits.HeatFlowRate Q_flow_liq_VLE if include; - Modelica.SIunits.HeatFlowRate Q_flow_VLE_cas if (include and enableCasing); - Modelica.SIunits.HeatFlowRate Q_flow_cas_amb if (include and enableHeatPort); - - protected - outer parameter Boolean includeDefaultSummary; - parameter Boolean include=includeDefaultSummary; - outer parameter Boolean enableCasing; - outer parameter Boolean enableHeatPort; - - end Summary; - - replaceable record SummaryClass = Summary; - -public - SummaryClass summary( - T_liq_A=heatexchanger.summary.T_liq_A, - T_liq_B=heatexchanger.summary.T_liq_B, - T_cas=casing.T, - p_VLE=volume.vleFluid.p, - d_VLE=volume.d, - T_VLE=volume.T, - DeltaH_flow_liq = heatexchanger.portA.m_flow*(heatexchanger.summary.h_liq_A-heatexchanger.summary.h_liq_B), - Q_flow_liq_VLE = -heatexchanger.summary.Q_flow_liq, - Q_flow_VLE_cas = heatTransfer_inner.heatPortA.Q_flow, - Q_flow_cas_amb = heatPort.Q_flow) annotation (Placement(transformation(extent={{-98,18}, - {-78,38}}, rotation=0))); - - /************************* Advanced ******************************/ - - parameter Boolean generateEventsAtFlowReversal=false - "If true, tranport propertie are calculated in the gas object" - annotation (Evaluate=true, Dialog(tab="Advanced", group="Event-Handling")); - - /******************** Initialization ********************/ - - parameter Modelica.SIunits.Density dInitial( - min=0, - max=1000) = 100 "Initial value for VLE density in free volume" - annotation (Dialog(tab="Initialization", group="VLE volume")); - parameter Modelica.SIunits.Temperature TInitial(min=273.15) = 300 - "Initial value for VLE temperature in free volume" - annotation (Dialog(tab="Initialization", group="VLE volume")); - - parameter Modelica.SIunits.Temperature hx_TInitialCell1=288.15 - "Initial Temperature of heat exchanger fluid in cell 1" - annotation (Dialog(tab="Initialization", group="Heat Exchanger")); - parameter Modelica.SIunits.Temperature hx_TInitialCelln=298.15 - "Initial Temperature of heat exchanger fluid in cell n" - annotation (Dialog(tab="Initialization", group="Heat Exchanger")); - parameter Modelica.SIunits.Temperature hx_TInitialWall(min=273.15) = 300 - "Initial value for heat exchanger temperature" - annotation (Dialog(tab="Initialization", group="heat exchanger")); - - parameter Modelica.SIunits.Temperature TInitialCasing=343.15 - annotation (Dialog(group="Casing", tab="Initialization")); - -equation - - connect(volume.heatPort, heatTransfer_inner.heatPortA) annotation (Line( - points={{6.50001,10},{34,10},{34,20},{45,20}}, - color={204,0,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(volume.heatPort, heatTransfer_tube_VLE.heatPortA) annotation (Line( - points={{6.50001,10},{34,10},{34,1}}, - color={204,0,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(vlePort_vapour, volume.vleVapourPort) annotation (Line( - points={{0,38},{0,19.5},{-1e-005,19.5}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(volume.vleLiquidPort, vlePort_liquid) annotation (Line( - points={{-1e-005,0.5},{-1e-005,-20},{0,-20},{0,-38}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(liquidPortA, heatexchanger.portA) annotation (Line( - points={{-100,-10},{-70,-10},{-70,-22},{26,-22}}, - color={0,170,238}, - thickness=0.5)); - connect(heatexchanger.portB, liquidPortB) annotation (Line( - points={{42,-22},{70,-22},{70,-10},{100,-10}}, - color={0,170,238}, - thickness=0.5)); - connect(heatTransfer_inner.heatPortB[1], casing.heatPort) annotation (Line( - points={{57,20},{66,20}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransfer_tube_VLE.heatPortB, heatexchanger.heatPort) annotation ( - Line( - points={{34,-11},{34,-11},{34,-20}}, - color={204,0,0}, - thickness=0.5)); - connect(casing.heatPort, heatPort) annotation (Line( - points={{66,20},{66,36}}, - color={204,0,0}, - thickness=0.5)); - annotation (Diagram(coordinateSystem(preserveAspectRatio=false, grid={1,1}, extent={{-100,-40}, - {100,40}})), Icon(coordinateSystem( - preserveAspectRatio=true, extent={{-100,-40},{100,40}}), graphics={ - Bitmap(extent={{-100,-58},{100,58}}, fileName= - "modelica://SorpLib/Resources/Images/Evaporator.png")})); -end EvpCond; diff --git a/SorpLib/Components/EvpCond/Geometry/CondLanzerath2014.mo b/SorpLib/Components/EvpCond/Geometry/CondLanzerath2014.mo deleted file mode 100644 index f33e0ebb8157ba2f38318b88305910d6b4b878e0..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/Geometry/CondLanzerath2014.mo +++ /dev/null @@ -1,34 +0,0 @@ -within SorpLib.Components.EvpCond.Geometry; -record CondLanzerath2014 - "Condenser used in dissertation of Lanzerath (2014 & 2015)" - extends TubeGeometry( - final innerDiameter=0.008, - final wallThickness=0.001, - length=4.55, - final nParallelTubes=1, - final crossSectionType=TIL.Internals.CrossSectionType.Circular, - final innerCrossSectionalAreaNonCircular=0, - final outerCrossSectionalAreaNonCircular=0, - final innerPerimeterNonCircular=0); - - annotation (Documentation(info="<html> - <p> - This record containes the information on the condenser used by Lanzerath (2014 & 2015).<br> - </p> - <h4>References</h4> - <p> - <ul> - <li>Lanzerath, F. Modellgestützte Entwicklung von Adsorptionswärmepumpen (in German). Aachen: Mainz, 2014. Aachener Beiträge zur Technischen Thermodynamik. 3. ISBN 9783861304722.</li> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> - </ul> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 07, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end CondLanzerath2014; diff --git a/SorpLib/Components/EvpCond/Geometry/EvpLanzerath2014.mo b/SorpLib/Components/EvpCond/Geometry/EvpLanzerath2014.mo deleted file mode 100644 index 31eeee434720326f0e6787f38f5e19d92a7144d6..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/Geometry/EvpLanzerath2014.mo +++ /dev/null @@ -1,35 +0,0 @@ -within SorpLib.Components.EvpCond.Geometry; -record EvpLanzerath2014 - "Evaporator used in dissertation of Lanzerath (2014 & 2015)" - extends TubeGeometry( - final innerDiameter=0.01467, - final wallThickness=0.0015025, - length=2.3, - final nParallelTubes=1, - final crossSectionType=TIL.Internals.CrossSectionType.Circular, - final innerCrossSectionalAreaNonCircular=0, - final outerCrossSectionalAreaNonCircular=0, - final innerPerimeterNonCircular=0); - - annotation (Documentation(info="<html> - <p> - This record containes the information on the evaporator used by Lanzerath (2014 & 2015).<br> - </p> - <h4>References</h4> - <p> - <ul> - <li>Lanzerath, F. Modellgestützte Entwicklung von Adsorptionswärmepumpen (in German). Aachen: Mainz, 2014. Aachener Beiträge zur Technischen Thermodynamik. 3. ISBN 9783861304722.</li> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> - </ul> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 07, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html> -")); -end EvpLanzerath2014; diff --git a/SorpLib/Components/EvpCond/Geometry/TubeGeometry.mo b/SorpLib/Components/EvpCond/Geometry/TubeGeometry.mo deleted file mode 100644 index 2fff3126df0e8b31687650946931d17088979bfa..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/Geometry/TubeGeometry.mo +++ /dev/null @@ -1,70 +0,0 @@ -within SorpLib.Components.EvpCond.Geometry; -record TubeGeometry "Geometry record for a tube" - extends SorpLib.Internals.ClassTypes.Record; - - parameter Modelica.SIunits.Diameter innerDiameter=0.01 - "Inner diameter of circular tube" annotation (Dialog(group="Geometry", - enable=(crossSectionType == TIL.Internals.CrossSectionType.Circular))); - parameter Modelica.SIunits.Length wallThickness=0.0005 "Wall thickness" - annotation (Dialog(group="Geometry", enable=(crossSectionType == TIL.Internals.CrossSectionType.Circular))); - parameter Modelica.SIunits.Length length=1 "|Geometry|Length"; - - parameter Integer nParallelTubes(min=1) = 1 - "|Geometry|Number of parallel Tubes"; - - parameter TIL.Internals.CrossSectionType crossSectionType=TIL.Internals.CrossSectionType.Circular - "|Geometry|Tube Cross Section Type"; - - parameter Modelica.SIunits.Area innerCrossSectionalAreaNonCircular=0 - "Inner cross sectional area of one non-circular tube" annotation (Dialog( - group="Geometry", enable=not (crossSectionType == TIL.Internals.CrossSectionType.Circular))); - - parameter Modelica.SIunits.Area outerCrossSectionalAreaNonCircular=0 - "Outer cross sectional area of one non-circular tube" annotation (Dialog( - group="Geometry", enable=not (crossSectionType == TIL.Internals.CrossSectionType.Circular))); - - parameter Modelica.SIunits.Length innerPerimeterNonCircular=0 - "Perimeter of one non-circular tube" annotation (Dialog(group="Geometry", - enable=not (crossSectionType == TIL.Internals.CrossSectionType.Circular))); - - final parameter Modelica.SIunits.Diameter outerDiameter=innerDiameter + 2* - wallThickness; - final parameter Modelica.SIunits.Area innerCrossSectionalArea=if - tubeIsCircular then Modelica.Constants.pi*innerDiameter*innerDiameter/4.0 - *nParallelTubes else innerCrossSectionalAreaNonCircular*nParallelTubes - "Inner cross-sectional area"; - final parameter Modelica.SIunits.Area outerCrossSectionalArea=if - tubeIsCircular then Modelica.Constants.pi*outerDiameter*outerDiameter/4.0 - *nParallelTubes else outerCrossSectionalAreaNonCircular*nParallelTubes - "Outer cross-sectional area"; - final parameter Modelica.SIunits.Area hydraulicCrossSectionalArea=if - tubeIsCircular then Modelica.Constants.pi*innerDiameter*innerDiameter/4.0 - else innerCrossSectionalAreaNonCircular "Hydraulic cross sectional area"; - final parameter Modelica.SIunits.Diameter hydraulicDiameter=if tubeIsCircular - then innerDiameter else 4*innerCrossSectionalAreaNonCircular/ - innerPerimeterNonCircular "Hydraulic diameter"; - final parameter Modelica.SIunits.Volume innerVolume=innerCrossSectionalArea* - length "Inner volume"; - final parameter Modelica.SIunits.Volume outerVolume=outerCrossSectionalArea* - length "Outer volume"; - final parameter Modelica.SIunits.Area innerHeatTransferArea=if tubeIsCircular - then Modelica.Constants.pi*innerDiameter*length*nParallelTubes else - innerPerimeterNonCircular*length*nParallelTubes; - final parameter Boolean tubeIsCircular=(crossSectionType == TIL.Internals.CrossSectionType.Circular) - "true, if tube's cross section is circular"; - - annotation (Documentation(info="<html> - <p> - This record containes all information necessary to describe a liquid tube. <br> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 07, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html> -")); -end TubeGeometry; diff --git a/SorpLib/Components/EvpCond/Geometry/package.mo b/SorpLib/Components/EvpCond/Geometry/package.mo deleted file mode 100644 index 5f03358f1178b33fc6c980a05c3c892e063645af..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/Geometry/package.mo +++ /dev/null @@ -1,7 +0,0 @@ -within SorpLib.Components.EvpCond; -package Geometry -extends SorpLib.Internals.ClassTypes.RecordPackage; - - - -end Geometry; diff --git a/SorpLib/Components/EvpCond/Geometry/package.order b/SorpLib/Components/EvpCond/Geometry/package.order deleted file mode 100644 index 9dea20e8b56326cf365e93f7e7cfa84373cf477f..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/Geometry/package.order +++ /dev/null @@ -1,3 +0,0 @@ -TubeGeometry -EvpLanzerath2014 -CondLanzerath2014 diff --git a/SorpLib/Components/EvpCond/Testers/TestEvpCond1.mo b/SorpLib/Components/EvpCond/Testers/TestEvpCond1.mo deleted file mode 100644 index 89f55b55f5b05b3a56efc8e78ed8ac5cf1ddea4e..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/Testers/TestEvpCond1.mo +++ /dev/null @@ -1,92 +0,0 @@ -within SorpLib.Components.EvpCond.Testers; -model TestEvpCond1 - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1, redeclare - TILMedia.LiquidTypes.TILMedia_Water liquidType1) - annotation (Placement(transformation(extent={{50,64},{70,84}}))); - EvpCond evpCond( - freeVolume(displayUnit="l") = 0.002, - dInitial=300, - nports=1, - kports=1, - nCells=10, - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - redeclare model VLESideHeatTransferModel = - HeatTransfer.HeatTransferPhenomena.ConstantAlphaA (constantAlphaA=100), - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Copper, - enableCasing=false, - redeclare record TubeGeometry = Geometry.EvpLanzerath2014, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - enableHeatPort=false, - TInitial=298.15, - hx_TInitialWall=298.15) - annotation (Placement(transformation(extent={{-12,-4},{12,6}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary_vapour( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=270, - origin={0,20}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryA(m_flowFixed=-0.1, - TFixed=313.15) - annotation (Placement(transformation(extent={{-44,-10},{-36,10}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryB(boundaryType="p") - annotation (Placement(transformation(extent={{36,-10},{44,10}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary_liquid( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={0,-20}))); - Modelica.Blocks.Sources.Step stepVLEBounday_vapour( - height=-0.001, - offset=0.001, - startTime=50) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=270, - origin={2,38}))); - Modelica.Blocks.Sources.Step stepVLEBounday_liquid( - height=0.001, - offset=-0.001, - startTime=100) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=90, - origin={-2,-36}))); -equation - - connect(liquidBoundaryA.port, evpCond.liquidPortA) annotation (Line( - points={{-40,0},{-18,0},{-18,-0.25},{-12,-0.25}}, - color={0,170,238}, - thickness=0.5, - smooth=Smooth.None)); - connect(evpCond.liquidPortB, liquidBoundaryB.port) annotation (Line( - points={{12,-0.25},{26,-0.25},{26,0},{40,0}}, - color={0,170,238}, - thickness=0.5, - smooth=Smooth.None)); - connect(vleBoundary_vapour.port, evpCond.vlePort_vapour[1]) annotation (Line( - points={{0,20},{0,20},{0,5.75}}, - color={153,204,0}, - thickness=0.5)); - connect(vleBoundary_liquid.port, evpCond.vlePort_liquid[1]) annotation (Line( - points={{0,-20},{0,-16},{0,-3.75}}, - color={153,204,0}, - thickness=0.5)); - connect(stepVLEBounday_vapour.y, vleBoundary_vapour.m_flow_in) - annotation (Line(points={{2,31.4},{2,27.7},{2,24}}, color={0,0,127})); - connect(vleBoundary_liquid.m_flow_in, stepVLEBounday_liquid.y) - annotation (Line(points={{-2,-24},{-2,-29.4}}, color={0,0,127})); - annotation ( - Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ - 100,100}})), - experiment(StopTime=500, Tolerance=1e-005), - __Dymola_experimentSetupOutput(events=false)); -end TestEvpCond1; diff --git a/SorpLib/Components/EvpCond/Testers/TestEvpCond2.mo b/SorpLib/Components/EvpCond/Testers/TestEvpCond2.mo deleted file mode 100644 index ebb6260f165cb95876020cd4393d88116d123b81..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/Testers/TestEvpCond2.mo +++ /dev/null @@ -1,97 +0,0 @@ -within SorpLib.Components.EvpCond.Testers; -model TestEvpCond2 - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1, redeclare - TILMedia.LiquidTypes.TILMedia_Water liquidType1) - annotation (Placement(transformation(extent={{50,64},{70,84}}))); - EvpCond evpCond( - freeVolume(displayUnit="l") = 0.002, - dInitial=300, - nports=1, - kports=1, - nCells=10, - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - enableCasing=true, - redeclare model VLESideHeatTransferModel = - HeatTransfer.HeatTransferPhenomena.ConstantAlphaA (constantAlphaA=100), - redeclare model WallMaterial_casing = - TILMedia.SolidTypes.TILMedia_Steel, - redeclare model HeatTransferModel_InternalCoupling = - HeatTransfer.HeatTransferPhenomena.ConstantAlphaA (constantAlphaA=5), - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Copper, - massCasing=2, - redeclare record TubeGeometry = Geometry.EvpLanzerath2014, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - enableHeatPort=false, - TInitial=298.15, - hx_TInitialWall=298.15) - annotation (Placement(transformation(extent={{-12,-4},{12,6}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary_vapour( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=270, - origin={0,20}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryA(m_flowFixed=-0.1, - TFixed=313.15) - annotation (Placement(transformation(extent={{-44,-10},{-36,10}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryB(boundaryType="p") - annotation (Placement(transformation(extent={{36,-10},{44,10}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary_liquid( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={0,-20}))); - Modelica.Blocks.Sources.Step stepVLEBounday_vapour( - height=-0.001, - offset=0.001, - startTime=50) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=270, - origin={2,38}))); - Modelica.Blocks.Sources.Step stepVLEBounday_liquid( - height=0.001, - offset=-0.001, - startTime=100) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=90, - origin={-2,-36}))); -equation - - connect(liquidBoundaryA.port, evpCond.liquidPortA) annotation (Line( - points={{-40,0},{-18,0},{-18,-0.25},{-12,-0.25}}, - color={0,170,238}, - thickness=0.5, - smooth=Smooth.None)); - connect(evpCond.liquidPortB, liquidBoundaryB.port) annotation (Line( - points={{12,-0.25},{26,-0.25},{26,0},{40,0}}, - color={0,170,238}, - thickness=0.5, - smooth=Smooth.None)); - connect(vleBoundary_vapour.port, evpCond.vlePort_vapour[1]) annotation (Line( - points={{0,20},{0,20},{0,5.75}}, - color={153,204,0}, - thickness=0.5)); - connect(vleBoundary_liquid.port, evpCond.vlePort_liquid[1]) annotation (Line( - points={{0,-20},{0,-16},{0,-3.75}}, - color={153,204,0}, - thickness=0.5)); - connect(stepVLEBounday_vapour.y, vleBoundary_vapour.m_flow_in) - annotation (Line(points={{2,31.4},{2,27.7},{2,24}}, color={0,0,127})); - connect(vleBoundary_liquid.m_flow_in, stepVLEBounday_liquid.y) - annotation (Line(points={{-2,-24},{-2,-29.4}}, color={0,0,127})); - annotation ( - Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ - 100,100}})), - experiment(StopTime=500, Tolerance=1e-005), - __Dymola_experimentSetupOutput(events=false)); -end TestEvpCond2; diff --git a/SorpLib/Components/EvpCond/Testers/TestEvpCond3.mo b/SorpLib/Components/EvpCond/Testers/TestEvpCond3.mo deleted file mode 100644 index 4def28e4601459dd64c23959b85f1934dcf3ea5d..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/Testers/TestEvpCond3.mo +++ /dev/null @@ -1,126 +0,0 @@ -within SorpLib.Components.EvpCond.Testers; -model TestEvpCond3 - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1, redeclare - TILMedia.LiquidTypes.TILMedia_Water liquidType1) - annotation (Placement(transformation(extent={{50,64},{70,84}}))); - EvpCond evpCond( - freeVolume(displayUnit="l") = 0.002, - dInitial=300, - nports=2, - kports=1, - nCells=10, - redeclare model TubeSideHeatTransferModel = - Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube.SiederTate, - enableCasing=true, - redeclare model VLESideHeatTransferModel = - HeatTransfer.HeatTransferPhenomena.ConstantAlphaA (constantAlphaA=100), - redeclare model WallMaterial_casing = - TILMedia.SolidTypes.TILMedia_Steel, - redeclare model HeatTransferModel_InternalCoupling = - HeatTransfer.HeatTransferPhenomena.ConstantAlphaA (constantAlphaA=5), - vleFluidType=sim.vleFluidType1, - liquidType=sim.liquidType1, - redeclare model WallMaterial_hx = TILMedia.SolidTypes.TILMedia_Copper, - massCasing=2, - redeclare record TubeGeometry = Geometry.EvpLanzerath2014, - redeclare model PressureDropModel = - TIL.LiquidComponents.Tubes.TransportPhenomena.PressureDrop.ZeroPressureDrop, - enableHeatPort=true, - TInitial=298.15, - hx_TInitialWall=298.15) - annotation (Placement(transformation(extent={{-12,-4},{12,6}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary_vapour1( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=270, - origin={-16,20}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryA(m_flowFixed=-0.1, - TFixed=313.15) - annotation (Placement(transformation(extent={{-44,-10},{-36,10}}))); - TIL.LiquidComponents.Boundaries.Boundary liquidBoundaryB(boundaryType="p") - annotation (Placement(transformation(extent={{36,-10},{44,10}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary_liquid( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={0,-20}))); - Modelica.Blocks.Sources.Step stepVLEBounday_vapour2( - startTime=50, - height=-0.0005, - offset=0.0005) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=270, - origin={-14,36}))); - Modelica.Blocks.Sources.Step stepVLEBounday_liquid( - height=0.001, - offset=-0.001, - startTime=100) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=90, - origin={-2,-36}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary(boundaryType="Q_flow", - Q_flowFixed=100) - annotation (Placement(transformation(extent={{-4,-6},{4,6}}, - rotation=90, - origin={22,20}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary_vapour2( - pFixed(displayUnit="kPa") = 15000, - boundaryType="m_flow", - use_massFlowRateInput=true) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=270, - origin={4,20}))); - Modelica.Blocks.Sources.Step stepVLEBounday_vapour1( - height=-0.0005, - offset=0.0005, - startTime=150) annotation (Placement(transformation( - extent={{-6,-6},{6,6}}, - rotation=270, - origin={6,36}))); -equation - - connect(liquidBoundaryA.port, evpCond.liquidPortA) annotation (Line( - points={{-40,0},{-18,0},{-18,-0.25},{-12,-0.25}}, - color={0,170,238}, - thickness=0.5, - smooth=Smooth.None)); - connect(evpCond.liquidPortB, liquidBoundaryB.port) annotation (Line( - points={{12,-0.25},{26,-0.25},{26,0},{40,0}}, - color={0,170,238}, - thickness=0.5, - smooth=Smooth.None)); - connect(vleBoundary_vapour1.port, evpCond.vlePort_vapour[1]) annotation (Line( - points={{-16,20},{-16,20},{-16,16},{-16,10},{0,10},{0,5.125}}, - color={153,204,0}, - thickness=0.5)); - connect(vleBoundary_liquid.port, evpCond.vlePort_liquid[1]) annotation (Line( - points={{0,-20},{0,-16},{0,-3.75}}, - color={153,204,0}, - thickness=0.5)); - connect(stepVLEBounday_vapour2.y, vleBoundary_vapour1.m_flow_in) - annotation (Line(points={{-14,29.4},{-14,24}}, color={0,0,127})); - connect(vleBoundary_liquid.m_flow_in, stepVLEBounday_liquid.y) - annotation (Line(points={{-2,-24},{-2,-29.4}}, color={0,0,127})); - connect(evpCond.heatPort, heatBoundary.heatPort) annotation (Line( - points={{7.92,5.5},{7.92,12.75},{22,12.75},{22,20}}, - color={204,0,0}, - thickness=0.5)); - connect(stepVLEBounday_vapour1.y, vleBoundary_vapour2.m_flow_in) - annotation (Line(points={{6,29.4},{6,26.7},{6,24}}, color={0,0,127})); - connect(vleBoundary_vapour2.port, evpCond.vlePort_vapour[2]) annotation (Line( - points={{4,20},{4,20},{4,10},{0,10},{0,6},{0,6.375}}, - color={153,204,0}, - thickness=0.5)); - annotation ( - Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{ - 100,100}})), - experiment(StopTime=500, Tolerance=1e-005), - __Dymola_experimentSetupOutput(events=false)); -end TestEvpCond3; diff --git a/SorpLib/Components/EvpCond/Testers/package.mo b/SorpLib/Components/EvpCond/Testers/package.mo deleted file mode 100644 index 04d1e5404dd7db8b10df9c3d78db4cf16e7d92e4..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/Testers/package.mo +++ /dev/null @@ -1,7 +0,0 @@ -within SorpLib.Components.EvpCond; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - - -end Testers; diff --git a/SorpLib/Components/EvpCond/Testers/package.order b/SorpLib/Components/EvpCond/Testers/package.order deleted file mode 100644 index 9898f98568e4bade1d53ec07878f07c4c0ea1268..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/Testers/package.order +++ /dev/null @@ -1,3 +0,0 @@ -TestEvpCond1 -TestEvpCond2 -TestEvpCond3 diff --git a/SorpLib/Components/EvpCond/package.mo b/SorpLib/Components/EvpCond/package.mo deleted file mode 100644 index db6eba536388e4efb5813d24e8f117e8949d0827..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/package.mo +++ /dev/null @@ -1,7 +0,0 @@ -within SorpLib.Components; -package EvpCond -extends SorpLib.Internals.ClassTypes.ComponentPackage; - - - -end EvpCond; diff --git a/SorpLib/Components/EvpCond/package.order b/SorpLib/Components/EvpCond/package.order deleted file mode 100644 index c1523739f4ddad064cf4a4cd8213aac5f63932fe..0000000000000000000000000000000000000000 --- a/SorpLib/Components/EvpCond/package.order +++ /dev/null @@ -1,3 +0,0 @@ -EvpCond -Geometry -Testers diff --git a/SorpLib/Components/Fans/AffinityFan.mo b/SorpLib/Components/Fans/AffinityFan.mo new file mode 100644 index 0000000000000000000000000000000000000000..3d53f57b8d21813b235a7ee77a5cf3dc3d3b2f99 --- /dev/null +++ b/SorpLib/Components/Fans/AffinityFan.mo @@ -0,0 +1,133 @@ +within SorpLib.Components.Fans; +model AffinityFan "Model of a fan based on affinity laws" + extends BaseClasses.PartialAffinityFan( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculation of fluid properties + // + rho = Medium.density_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1, inStream(port_a.Xi_outflow), {1-sum(inStream(port_a.Xi_outflow))})) + "Instreaming density"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The affinity fan can be used to prescribe the mass or volume flow rate in hydraulic +components, such as tubes or heat exchangers. The model assumes a non-constant fan +efficiency that depends on the volume flow rate. Changes compared to a nominal operating +point are considered by affinity laws. + +<h4>Main equations</h4> +<p> +The model calculates the hydraulic, shaft, and drive power transmitted to the fluid +or required to drive the fan. The hydraulic power <i>P<sub>hydraulic</sub></i> +transmitted to the fluid is defined as: +</p> +<pre> + P<sub>hydraulic</sub> = ṁ / ρ<sub>in</sub> * Δp; +</pre> +<p> +Herein, <i>ṁ</i> is the mass flow rate, <i>ρ<sub>in</sub></i> describes the +fluid density at the inlet, and <i>Δp = p<sub>b</sub> - p<sub>a</sub></i> is the +pressure difference between port b and a. The mass flow rate <i>ṁ</i> follows +from the volume flow rate <i>V<sub>flow</sub></i> that depends on the rotational speed +<i>n</i>, the nominal volume flow rate <i>V<sub>flow,ref</sub></i>, and the nominal +rotational speed <i>n<sub>ref</sub></i>: +</p> +<pre> + V<sub>flow</sub> = ṁ / ρ<sub>in</sub> = V<sub>flow,ref</sub> * n / n<sub>ref</sub>; +</pre> +<p> +The shaft power <i>P<sub>shaft</sub></i> depends on the fan efficiency +<i>η<sub>fan</sub></i> and is defined as: +</p> +<pre> + P<sub>shaft</sub> = P<sub>hydraulic</sub> / η<sub>fan</sub>; +</pre> +<p> +with +</p> +<pre> + η<sub>fan</sub> = η<sub>fan,ref</sub> * (1 - f<sub>loss</sub> * ((ṁ / ρ<sub>in</sub>) / V<sub>flow,ref</sub> - 1) ^ 2); +</pre> +<p> +Herein, <i>f<sub>loss</sub></i> is a loss factor describing the dependency on the volume +flow rate, <i>η<sub>fan,ref</sub></i> is the efficiency at the nominal operating point, +and <i>V<sub>flow,ref</sub></i> is the nominal volume flow rate. The shaft power is completly +transmitted to the fluid, thus increasing the outflowing specific enthalpy of the fluid. +<br/><br/> +The drive power <i>P<sub>drive</sub></i> is required to drive the fan, depends on the +drive efficienciy <i>η<sub>drive</sub></i>, and is defined as: +</p> +<pre> + P<sub>drive</sub> = P<sub>shaft</sub> / η<sub>drive</sub>; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No flow reversal + </li> + <li> + Affinity laws apply to describe changes in operating conditions + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The affinity fan is typically used to prescripe the mass or volume flow rate +in hydraulic components, such as tubes or heat exchangers, if process controlelrs +are investigated and the flow rate changes. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>assumeIsenthalpicFan</i>: + Defines if the hydraulic losses are considered in the energy balance. + </li> + <li> + <i>calculateDrivePower</i>: + Defines if the driving power is calculates within the model. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 11, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AffinityFan; diff --git a/SorpLib/Components/Fans/BaseClasses/PartialAffinityFan.mo b/SorpLib/Components/Fans/BaseClasses/PartialAffinityFan.mo new file mode 100644 index 0000000000000000000000000000000000000000..addd4c08ff6ea6ef5681cdcb44a46e51998677ca --- /dev/null +++ b/SorpLib/Components/Fans/BaseClasses/PartialAffinityFan.mo @@ -0,0 +1,142 @@ +within SorpLib.Components.Fans.BaseClasses; +partial model PartialAffinityFan + "Base model for all fans using affinity laws" + extends SorpLib.Components.Fans.BaseClasses.PartialFan; + + // + // Definition of paramteres describring the fan's characteristics + // + parameter Modelica.Units.SI.Frequency n_ref = 50 + "Nominal rotational speed" + annotation (Dialog(tab="General", group="Fan Characteristics - Nominal point")); + parameter Modelica.Units.SI.VolumeFlowRate V_flow_ref = 10/1000/60 + "Nominal volume flow rate" + annotation (Dialog(tab="General", group="Fan Characteristics - Nominal point")); + parameter Modelica.Units.SI.Efficiency eta_fan_ref = 0.4 + "Nominal fan efficiency" + annotation (Dialog(tab="General", group="Fan Characteristics - Nominal point")); + parameter Real f_loss = 0.3 + "Loss factor describing the fan efficiency" + annotation (Dialog(tab="General", group="Fan Characteristics - Nominal point")); + + // + // Definition of parameters describing the inputs + // + parameter Boolean use_nInput = false + "=true, if n is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Inputs"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Frequency n_fixed = 50 + "Fixed rotational speed" + annotation (Dialog(tab="General",group="Inputs", + enable=not use_nInput)); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput n_input(final unit="1/s") if + use_nInput + "Input for rotational speed" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=90, + origin={0,-90}), + iconTransformation(extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-80}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput n_internal(final unit="1/s") + "Needed for connecting to conditional connector"; + + // + // Definition of variables + // +public + Modelica.Units.SI.Efficiency eta_fan + "Fan efficiency"; + +equation + // + // Assertions + // + assert(n_internal >= 0, + "Rotational speed cannot be negative!", + level=AssertionLevel.error); + + // + // Connectors + // + connect(n_internal, n_input); + + if not use_nInput then + n_internal = n_fixed + "Needed for connecting to conditional connector"; + end if; + + // + // Mass balance + // + m_flow = V_flow * rho + "Mass flow rate at port a"; + V_flow = V_flow_ref * (n_internal / n_ref) + "Volume flow rate at port a (affinity law)"; + + // + // Energy balance + // + if assumeIsenthalpicFan then + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy due to + forbidden flow revesal"; + port_b.h_outflow = inStream(port_a.h_outflow) + (1/eta_fan - 1) * dp / rho + "Increase of specific enthalpy due to internal losses of the fan"; + + else + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + port_b.h_outflow = inStream(port_a.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + + end if; + + // + // Power calculations + // + eta_fan = eta_fan_ref * (1 - f_loss * (V_flow / V_flow_ref - 1) ^ 2) + "Efficiency ot the fan dependent on the volume flow rate"; + + P_shaft = P_hydraulic / eta_fan + "Shaft power consumption of fan"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all fans using affinity laws and volume- +flow-dependent efficiencies. It defines fundamental parameters and variables required +by all affinity fans. Models that inherit properties from this partial model have +to redeclare the fluid ports. Moreover, the instreaming density must be calculated. +In this context, appropriate fluid property models are required. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Instreaming density <i>rho</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 11, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialAffinityFan; diff --git a/SorpLib/Components/Fans/BaseClasses/PartialFan.mo b/SorpLib/Components/Fans/BaseClasses/PartialFan.mo new file mode 100644 index 0000000000000000000000000000000000000000..cd891df189cce71fa04c64332470e0afce8e53eb --- /dev/null +++ b/SorpLib/Components/Fans/BaseClasses/PartialFan.mo @@ -0,0 +1,197 @@ +within SorpLib.Components.Fans.BaseClasses; +partial model PartialFan "Base model for all fans" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of paramteres describring the fan's characteristics + // + parameter Boolean assumeIsenthalpicFan = false + " = true, if internal losses do not influence the energy balance" + annotation (Dialog(tab="General", group="Fan Characteristics")); + parameter Boolean calculateDrivePower = true + " = true, if drive power is calcualted" + annotation (Dialog(tab="General", group="Fan Characteristics")); + + parameter Modelica.Units.SI.Efficiency eta_drive = 0.9 + "Efficiency of drive that is used to calculate drive power" + annotation (Dialog(tab="General", group="Fan Characteristics", + enable=calculateDrivePower)); + + // + // Definition or initialisation parameters + // + parameter Modelica.Units.SI.MassFlowRate m_flow_start = 1e-4 + "Start value for mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=m_flow_start)) + "Fluid port a" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}), + iconTransformation(extent={{-90,-10},{-70,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-m_flow_start)) + "Fluid port b" + annotation (Placement(transformation(extent={{70,-10},{90,10}}), + iconTransformation(extent={{70,-10},{90,10}})), + choicesAllMatching=true); + + // + // Definition of variables + // + Modelica.Units.SI.Density rho + "Instreaming density"; + + Modelica.Units.SI.PressureDifference dp + "Pressure difference between port a and b"; + Modelica.Units.SI.MassFlowRate m_flow + "Mass flow rate"; + Modelica.Units.SI.VolumeFlowRate V_flow + "Volume flow rate"; + + Modelica.Units.SI.Power P_hydraulic + "Hydraulic power consumption of the fan"; + Modelica.Units.SI.Power P_shaft + "Shaft power consumption of the fan"; + Modelica.Units.SI.Power P_drive + "Drive power consumption of the fan"; + Modelica.Units.SI.Power P_loss_internal + "Internal power losses of the fan (i.e., increase of outflowing specific + enthalpy)"; + +equation + // + // Assertions + // + assert(m_flow >= 0, + "Fan model cannot handle flow reversal!", + level=AssertionLevel.error); + + // + // Momentum balance + // + dp = port_b.p - port_a.p + "Pressure difference between port b and a"; + + // + // Mass balance + // + 0 = port_a.m_flow + port_b.m_flow + "Steady-state mass balance"; + + port_a.Xi_outflow = inStream(port_b.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + port_b.Xi_outflow = inStream(port_a.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + + port_a.m_flow = m_flow + "Mass flow rate at port a"; + + // + // Power calculations + // + P_hydraulic = V_flow * dp + "Hydraulic power consumption of the fan"; + P_drive = if calculateDrivePower then P_shaft / eta_drive else 0 + "Drive power consumption of fan"; + P_loss_internal = P_shaft - P_hydraulic + "Internal power losses of fan (i.e., increase outflowing specific enthalpy)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all fans. It defines fundamental +parameters and variables required by all fans. Models that inherit properties +from this partial model have to redeclare the fluid ports. Moreover, the mass +and energy balances must be completed, and the power calculations must be added. +In this context, appropriate fluid property models are required. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Instreaming density <i>rho</i>. + </li> + <br/> + <li> + Mass flow rate <i>m_flow</i> at port a. + </li> + <li> + Volume flow rate <i>V_flow</i> at port a. + </li> + <br/> + <li> + Outflowing specific enthalpy <i>port_a.h_outflow</i> at port a. + </li> + <li> + Outflowing specific enthalpy <i>port_b.h_outflow</i> at port b. + </li> + <br/> + <li> + Shaft power <i>P_shaft</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 10, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ + Ellipse( + extent={{-80,-80},{80,80}}, + lineColor={244,125,35}, + fillColor={244,125,35}, + fillPattern=FillPattern.Sphere), + Polygon( + points={{-68,42},{-68,-42},{80,0},{-68,42}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Line( + points={{40,0},{-20,0}}, + color={0,0,0}, + arrow={Arrow.Filled,Arrow.None}), + Ellipse( + extent={{-64,-4},{-24,4}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-20,-4},{20,4}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid, + origin={-44,0}, + rotation=90)})); +end PartialFan; diff --git a/SorpLib/Components/Fans/BaseClasses/PartialSimpleFan.mo b/SorpLib/Components/Fans/BaseClasses/PartialSimpleFan.mo new file mode 100644 index 0000000000000000000000000000000000000000..8e0cd89fa46cf6ef0c9b571480d54143f852f4ee --- /dev/null +++ b/SorpLib/Components/Fans/BaseClasses/PartialSimpleFan.mo @@ -0,0 +1,169 @@ +within SorpLib.Components.Fans.BaseClasses; +partial model PartialSimpleFan + "Base model for all simple fans with constant efficiencies" + extends SorpLib.Components.Fans.BaseClasses.PartialFan(final + calculateDrivePower=true); + + // + // Definition of paramteres describring the fan's characteristics + // + parameter Modelica.Units.SI.Efficiency eta_fan = 0.4 + "Efficiency of fan that is used to calculate shaft power" + annotation (Dialog(tab="General", group="Fan Characteristics")); + + // + // Definition of parameters describing the inputs + // + parameter SorpLib.Choices.PrescripedFanVariable prescribedInput= + SorpLib.Choices.PrescripedFanVariable.V_flow + "Prescribed input variable" + annotation (Dialog(tab="General", group="Inputs")); + + parameter Boolean use_mFlowInput = false + "=true, if m_flow is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Inputs", + enable=(prescribedInput == + SorpLib.Choices.PrescripedFanVariable.m_flow)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.MassFlowRate m_flow_fixed = 0.1 + "Fixed mass flow rate" + annotation (Dialog(tab="General",group="Inputs", + enable=(prescribedInput == + SorpLib.Choices.PrescripedFanVariable.m_flow) + and not use_mFlowInput)); + + parameter Boolean use_VFlowInput = false + "=true, if V_flow is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Inputs", + enable=(prescribedInput == + SorpLib.Choices.PrescripedFanVariable.V_flow)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.VolumeFlowRate V_flow_fixed = 10/1000/60 + "Fixed volume flow rate" + annotation (Dialog(tab="General",group="Inputs", + enable=(prescribedInput == + SorpLib.Choices.PrescripedFanVariable.V_flow) + and not use_VFlowInput)); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput m_flow_input(final unit="kg/s") if + (prescribedInput == SorpLib.Choices.PrescripedFanVariable.m_flow and + use_mFlowInput) + "Input for mass flow rate" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=90, + origin={0,-90}), + iconTransformation(extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-80}))); + + Modelica.Blocks.Interfaces.RealInput V_flow_input(final unit="m3/s") if + (prescribedInput == SorpLib.Choices.PrescripedFanVariable.V_flow and + use_VFlowInput) + "Input for volume flow rate" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=90, + origin={30,-90}), + iconTransformation(extent={{-10,-10},{10,10}}, + rotation=90, + origin={30,-80}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput m_flow_internal(final unit="kg/s") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput V_flow_internal(final unit="m3/s") + "Needed for connecting to conditional connector"; + +equation + // + // Connectors + // + connect(m_flow_internal, m_flow_input); + connect(V_flow_internal, V_flow_input); + + if not use_mFlowInput then + m_flow_internal = m_flow_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_VFlowInput then + V_flow_internal = V_flow_fixed + "Needed for connecting to conditional connector"; + end if; + + // + // Mass balance + // + if prescribedInput == SorpLib.Choices.PrescripedFanVariable.m_flow then + m_flow = m_flow_internal + "Mass flow rate at port a"; + V_flow = m_flow_internal / rho + "Volume flow rate at port a"; + + elseif prescribedInput == SorpLib.Choices.PrescripedFanVariable.V_flow then + m_flow = V_flow_internal * rho + "Mass flow rate at port a"; + V_flow = V_flow_internal + "Volume flow rate at port a"; + + end if; + + // + // Energy balance + // + if assumeIsenthalpicFan then + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy due to + forbidden flow revesal"; + port_b.h_outflow = inStream(port_a.h_outflow) + (1/eta_fan - 1) * dp / rho + "Increase of specific enthalpy due to internal losses of the fan"; + + else + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + port_b.h_outflow = inStream(port_a.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + + end if; + + // + // Power calculations + // + P_shaft = P_hydraulic / eta_fan + "Shaft power consumption of fan"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all simple fans with constant efficiencies. +It defines fundamental parameters and variables required by all simple fans. Models +that inherit properties from this partial model have to redeclare the fluid ports. +Moreover, the instreaming density must be calculated. In this context, appropriate +fluid property models are required. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Instreaming density <i>rho</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 10, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialSimpleFan; diff --git a/SorpLib/Components/Fans/BaseClasses/package.mo b/SorpLib/Components/Fans/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e3c3fe9d0a315e62473ad68488a0674158e432a3 --- /dev/null +++ b/SorpLib/Components/Fans/BaseClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Fans; +package BaseClasses "Base models and functions for all pumps" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial fan models, containing fundamental definitions for +pumps. The content of this package is only of interest when adding new fans to +the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Components/Fans/BaseClasses/package.order b/SorpLib/Components/Fans/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5ee395b1951701a875b850513a6bd76a441ce96d --- /dev/null +++ b/SorpLib/Components/Fans/BaseClasses/package.order @@ -0,0 +1,3 @@ +PartialFan +PartialSimpleFan +PartialAffinityFan diff --git a/SorpLib/Components/Fans/SimpleFan.mo b/SorpLib/Components/Fans/SimpleFan.mo new file mode 100644 index 0000000000000000000000000000000000000000..5e009a8c3386be929eed9bcb5c0dab39f2043597 --- /dev/null +++ b/SorpLib/Components/Fans/SimpleFan.mo @@ -0,0 +1,117 @@ +within SorpLib.Components.Fans; +model SimpleFan "Model of a simple fan with constant efficiencies" + extends BaseClasses.PartialSimpleFan( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculation of fluid properties + // + rho = Medium.density_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1, inStream(port_a.Xi_outflow), {1-sum(inStream(port_a.Xi_outflow))})) + "Instreaming density"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The simple fan can be used to prescribe the mass or volume flow rate in hydraulic +components, such as tubes or heat exchangers. The model assumes constant efficiencies +and can be used for ideal gases, gas-mixtures, or gas-vapor mixtures. + +<h4>Main equations</h4> +<p> +The model calculates the hydraulic, shaft, and drive power transmitted to the fluid +or required to drive the fan. The hydraulic power <i>P<sub>hydraulic</sub></i> +transmitted to the fluid is defined as: +</p> +<pre> + P<sub>hydraulic</sub> = ṁ / ρ<sub>in</sub> * Δp; +</pre> +<p> +Herein, <i>ṁ</i> is the mass flow rate, <i>ρ<sub>in</sub></i> describes the +fluid density at the inlet, and <i>Δp = p<sub>b</sub> - p<sub>a</sub></i> is the +pressure difference between port b and a. +<br/><br/> +The shaft power <i>P<sub>shaft</sub></i> depends on the fan efficiency +<i>η<sub>fan</sub></i> and is defined as: +</p> +<pre> + P<sub>shaft</sub> = P<sub>hydraulic</sub> / η<sub>fan</sub>; +</pre> +<p> +The shaft power is completly transmitted to the fluid, thus increasing the outflowing +specific enthalpy of the fluid. +<br/><br/> +The drive power <i>P<sub>drive</sub></i> is required to drive the fan, depends on the +drive efficienciy <i>η<sub>drive</sub></i>, and is defined as: +</p> +<pre> + P<sub>drive</sub> = P<sub>shaft</sub> / η<sub>drive</sub>; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No flow reversal + </li> + <li> + Constant efficiencies + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The simple fan is typically used to prescripe the mass or volume flow rate +in hydraulic components, such as tubes or heat exchangers. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>prescribedInput</i>: + Defines the variable that is prescribed (i.e., mass flow rate or volume + flow rate). + </li> + <li> + <i>assumeIsenthalpicFan</i>: + Defines if the hydraulic losses are considered in the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 10, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SimpleFan; diff --git a/SorpLib/Components/Fans/Tester/Test_AffinityFan.mo b/SorpLib/Components/Fans/Tester/Test_AffinityFan.mo new file mode 100644 index 0000000000000000000000000000000000000000..35ea49f4ce1bbacba72b7dbf99ba5806f7fad22f --- /dev/null +++ b/SorpLib/Components/Fans/Tester/Test_AffinityFan.mo @@ -0,0 +1,102 @@ +within SorpLib.Components.Fans.Tester; +model Test_AffinityFan "Tester for the affinity fan" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fans.AffinityFan fan(use_nInput=true, redeclare final + package Medium = Medium) "Affinity fan" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + + SorpLib.Components.Fittings.Resistors.GasTubeResistance pressureLoss( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.PortAInlet, + frictionPressureLoss=true, + fittingPressureLosss=false, + redeclare model PressureLossModel = + Fittings.PressureLossCorrelations.TubeInside.Blasius, + redeclare replaceable parameter Fittings.Records.GeometryTube geometry(l=5, + d_hyd_a=0.25) constrainedby + SorpLib.Components.Fittings.Records.GeometryTube, + redeclare final package Medium = Medium) "Pressure loss model" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_n( + amplitude=50, + f=1/250, + offset=50) + "Input signal for the rotational speed" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}}))); + +equation + // + // Connections + // + connect(fs_a.port, fan.port_a) annotation (Line( + points={{-60,0},{-38,0}}, + color={244,125,35}, + thickness=1)); + connect(pressureLoss.port_a, fan.port_b) annotation (Line( + points={{22,0},{-22,0}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, pressureLoss.port_b) annotation (Line( + points={{60,0},{38,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_n.y, fan.n_input) + annotation (Line(points={{-59,-30},{-30,-30},{-30,-8}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the affinity fan. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 11, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_AffinityFan; diff --git a/SorpLib/Components/Fans/Tester/Test_SimpleFan.mo b/SorpLib/Components/Fans/Tester/Test_SimpleFan.mo new file mode 100644 index 0000000000000000000000000000000000000000..ae63d5e789da60a625d8bfd3f1574c5da9cc9a96 --- /dev/null +++ b/SorpLib/Components/Fans/Tester/Test_SimpleFan.mo @@ -0,0 +1,102 @@ +within SorpLib.Components.Fans.Tester; +model Test_SimpleFan "Tester for the simple fan" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fans.SimpleFan fan(use_VFlowInput=true, redeclare final + package Medium = Medium) "Simple fan" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + + SorpLib.Components.Fittings.Resistors.GasTubeResistance pressureLoss( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.PortAInlet, + frictionPressureLoss=true, + fittingPressureLosss=false, + redeclare model PressureLossModel = + Fittings.PressureLossCorrelations.TubeInside.Blasius, + redeclare replaceable parameter Fittings.Records.GeometryTube geometry(l=5, + d_hyd_a=0.25) constrainedby + SorpLib.Components.Fittings.Records.GeometryTube, + redeclare final package Medium = Medium) "Pressure loss model" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_VFlow( + amplitude=100/1.2/60/60, + f=1/250, + offset=100/1.2/60/60) + "Input signal for volume flow rate" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}}))); + +equation + // + // Connections + // + connect(fs_a.port, fan.port_a) annotation (Line( + points={{-60,0},{-38,0}}, + color={244,125,35}, + thickness=1)); + connect(pressureLoss.port_a, fan.port_b) annotation (Line( + points={{22,0},{-22,0}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, pressureLoss.port_b) annotation (Line( + points={{60,0},{38,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_VFlow.y, fan.V_flow_input) + annotation (Line(points={{-59,-30},{-27,-30},{-27,-8}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the simple fan. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 10, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_SimpleFan; diff --git a/SorpLib/Components/Fans/Tester/package.mo b/SorpLib/Components/Fans/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5ef55412fbeb31e6f27b7c7f4106e4ea9d943f3e --- /dev/null +++ b/SorpLib/Components/Fans/Tester/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Components.Fans; +package Tester "Models to test and varify fan models" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented fans. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Fans/Tester/package.order b/SorpLib/Components/Fans/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..63eb6cdc212a4c9fe07a72ad12750f93e699e630 --- /dev/null +++ b/SorpLib/Components/Fans/Tester/package.order @@ -0,0 +1,2 @@ +Test_SimpleFan +Test_AffinityFan diff --git a/SorpLib/Components/Fans/package.mo b/SorpLib/Components/Fans/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5d0208c21af26908d064c7ab69dd0b204d547408 --- /dev/null +++ b/SorpLib/Components/Fans/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components; +package Fans "Fans to move fluids" + extends SorpLib.Icons.FansPackage; + + annotation (Documentation(info="<html> +<p> +This package contains fans. Ready-to-use models are based on the Modelica +Standard library (MSL). Fans are used to prescripe a mass or volume flow rate +to a hydraulic fluid. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Fans; diff --git a/SorpLib/Components/Fans/package.order b/SorpLib/Components/Fans/package.order new file mode 100644 index 0000000000000000000000000000000000000000..26d0d3c13a7f0ba29bb3bcf0eaaaf29d5fce1cec --- /dev/null +++ b/SorpLib/Components/Fans/package.order @@ -0,0 +1,4 @@ +BaseClasses +SimpleFan +AffinityFan +Tester diff --git a/SorpLib/Components/Fittings/BaseClasses/PartialInertiaInducer.mo b/SorpLib/Components/Fittings/BaseClasses/PartialInertiaInducer.mo new file mode 100644 index 0000000000000000000000000000000000000000..692b55900c8278261ad877cea53995db55f7fe34 --- /dev/null +++ b/SorpLib/Components/Fittings/BaseClasses/PartialInertiaInducer.mo @@ -0,0 +1,189 @@ +within SorpLib.Components.Fittings.BaseClasses; +partial model PartialInertiaInducer + "Base model for all inertia inducers" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of setup parameters + // + parameter Modelica.Units.SI.Length f_momentum = 0.1 + "Momentum factor describing acceleration of fluid mass" + annotation (Dialog(tab="General", group="Momentum Setup")); + + // + // Definition or initialisation parameters + // + parameter Integer initialisationType(min=1, max=3) = 3 + "Initialisation type: Fixed, steady-state, or free" + annotation (Dialog(tab="Initialisation", group="Type"), + choices( + choice=1 "Fixed", + choice=2 "Steady-state", + choice=3 "Free")); + + parameter Modelica.Units.SI.MassFlowRate m_flow_initial = 0.01 + "Initial value of mass flow rate" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid port a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}), + iconTransformation(extent={{-70,-10},{-50,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid ports b" + annotation (Placement(transformation(extent={{50,-10},{70,10}}), + iconTransformation(extent={{50,-10},{70,10}})), + choicesAllMatching=true); + + // + // Definition of variables + // + Modelica.Units.SI.PressureDifference dp + "Pressure difference between port a and b"; + + Modelica.Units.SI.MassFlowRate m_flow + "Mass flow rate"; + +initial equation + if initialisationType==1 then + m_flow = m_flow_initial + "Fixed intial value"; + + elseif initialisationType==2 then + der(m_flow) = 0 + "Steady-state initialisation"; + + end if; + +equation + // + // Momentum balance + // + dp = port_a.p - port_b.p + "Pressure difference between port a and b"; + der(m_flow) = dp * f_momentum + "Mass flow rate"; + + // + // Mass balance + // + 0 = port_a.m_flow + port_b.m_flow + "Steady-state mass balance"; + port_a.m_flow = m_flow + "Mass flow rate at port a"; + + port_a.Xi_outflow = inStream(port_b.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + port_b.Xi_outflow = inStream(port_a.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + + // + // Energy balance + // + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + port_b.h_outflow = inStream(port_a.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all inertia inducers. It defines fundamental +parameters and variables required by all inertia inducers. Models that inherit +properties from this partial model have to redeclare the fluid ports and to add a +medium model. +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle( + extent={{60,-50},{-60,50}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + lineThickness=1), + Ellipse( + extent={{-40,10},{-20,-10}}, + lineColor={135,135,135}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{-18,2},{-14,-2}}, + lineColor={135,135,135}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{-12,2},{-8,-2}}, + lineColor={135,135,135}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{-6,2},{-2,-2}}, + lineColor={135,135,135}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{2,2},{6,-2}}, + lineColor={135,135,135}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{8,2},{12,-2}}, + lineColor={135,135,135}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{14,2},{18,-2}}, + lineColor={135,135,135}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{20,10},{40,-10}}, + lineColor={135,135,135}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid), + Text( + extent={{-40,32},{40,10}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid, + textString="dṁ/dtau = ..."), + Line( + points={{-40,-16},{40,-16}}, + color={0,0,0}, + thickness=1, + arrow={Arrow.Open,Arrow.Open})})); +end PartialInertiaInducer; diff --git a/SorpLib/Components/Fittings/BaseClasses/PartialMultiPort.mo b/SorpLib/Components/Fittings/BaseClasses/PartialMultiPort.mo new file mode 100644 index 0000000000000000000000000000000000000000..9db8ff7bfe9b184a9ee349e2423c33ae4b626d8a --- /dev/null +++ b/SorpLib/Components/Fittings/BaseClasses/PartialMultiPort.mo @@ -0,0 +1,145 @@ +within SorpLib.Components.Fittings.BaseClasses; +partial model PartialMultiPort + "Base model for all multi port models (i.e., ideal splitter/junctions)" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of setup parameters + // + parameter Integer no_ports_b = 0 + "Number of ports at position b" + annotation (Dialog(connectorSizing=true)); + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid port a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}), + iconTransformation(extent={{-70,-10},{-50,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort ports_b[no_ports_b] + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + each final no_components=no_components) + "Fluid ports b" + annotation (Placement(transformation(extent={{50,-10},{70,10}}), + iconTransformation(extent={{50,-10},{70,10}})), + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Real denominator = Modelica.Constants.small + + sum({abs(ports_b[ind_b].m_flow) for ind_b in 1:no_ports_b}) + "Denominator used to calculate mixing stream variables"; + +equation + // + // Momentum balance + // + ports_b.p = fill(port_a.p, no_ports_b) + "No pressure loss"; + + // + // Mass balance + // + 0 = port_a.m_flow + sum(ports_b.m_flow) + "Steady-state mass balance"; + + for ind_c in 1:no_components-1 loop + port_a.Xi_outflow[ind_c] = + (sum({abs(ports_b[ind_b].m_flow) * inStream(ports_b[ind_b].Xi_outflow[ind_c]) + for ind_b in 1:no_ports_b}) + Modelica.Constants.small) / denominator + "Calculate ideal mixing stream variable for mass flow from port b to port a"; + end for; + + for ind_b in 1:no_ports_b loop + ports_b[ind_b].Xi_outflow = inStream(port_a.Xi_outflow) + "Expose stream variable of port due to splitting of mass flow from port a"; + end for; + + // + // Energy balance + // + port_a.h_outflow = + (sum({abs(ports_b[ind_b].m_flow) * inStream(ports_b[ind_b].h_outflow) + for ind_b in 1:no_ports_b}) + Modelica.Constants.small) / denominator + "Calculate ideal mixing stream variable for mass flow from port b to port a"; + + for ind_b in 1:no_ports_b loop + ports_b[ind_b].h_outflow = inStream(port_a.h_outflow) + "Expose stream variable of port due to splitting of mass flow from port a"; + end for; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all multi port models. It defines fundamental +parameters and variables required by all multi port models. Models that inherit +properties from this partial model have to redeclare the fluid ports and to add a +medium model. +<br/><br/> +This models is based on +<a href=\"Modelica://Modelica.Fluid.Fittings.MultiPort\">Modelica.Fluid.Fittings.MultiPort</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 20, 2023, by Mirko Engelpracht:<br/> + Minor revisions (documentation). + </li> + <li> + January 19, 2021, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle( + extent={{-60,100},{60,-100}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Line( + points={{20,80},{40,80}}, + color={0,0,0}, + thickness=0.5), + Line( + points={{20,40},{40,40}}, + color={0,0,0}, + thickness=0.5), + Line( + points={{-40,0},{-20,0}}, + color={0,0,0}, + thickness=0.5), + Line( + points={{20,-80},{40,-80}}, + color={0,0,0}, + thickness=0.5), + Line( + points={{20,80},{-20,0},{20,-80}}, + color={0,0,0}, + thickness=0.5), + Line( + points={{20,0},{40,0}}, + color={0,0,0}, + thickness=0.5), + Line( + points={{20,-40},{40,-40}}, + color={0,0,0}, + thickness=0.5)})); +end PartialMultiPort; diff --git a/SorpLib/Components/Fittings/BaseClasses/PartialOpenAdsorberPressureLoss.mo b/SorpLib/Components/Fittings/BaseClasses/PartialOpenAdsorberPressureLoss.mo new file mode 100644 index 0000000000000000000000000000000000000000..5e97483a040f95de55b9adc95cde85fd7baefc67 --- /dev/null +++ b/SorpLib/Components/Fittings/BaseClasses/PartialOpenAdsorberPressureLoss.mo @@ -0,0 +1,45 @@ +within SorpLib.Components.Fittings.BaseClasses; +partial model PartialOpenAdsorberPressureLoss + "Base model for all pressure loss models of open adsorbers" + extends SorpLib.Components.Fittings.BaseClasses.PartialPressureLoss( + final psi = geometry.psi, + redeclare replaceable parameter SorpLib.Components.Fittings.Records.GeometryOpenAdsorber geometry + constrainedby SorpLib.Components.Fittings.Records.GeometryOpenAdsorber); + +equation + // + // Calculate the hydraulic mass flow rate + // + m_flow_hyd = m_flow / geometry.no_hydraulicParallelFlows + "Hydraulic mass flow rate"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all pressure loss models applied in open +adsorbers. It defines fundamental parameters and variables required by all pressure +loss models. Models that inherit properties from this partial model have to complete +the friction-based pressure loss correlation. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Friction factor <i>lambda_mean_dd</i> for design flow direction (i.e., a->b). + </li> + <li> + Friction factor <i>lambda_mean_rdd</i> for reverse design flow direction (i.e., + a->b). + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PartialOpenAdsorberPressureLoss; diff --git a/SorpLib/Components/Fittings/BaseClasses/PartialPressureLoss.mo b/SorpLib/Components/Fittings/BaseClasses/PartialPressureLoss.mo new file mode 100644 index 0000000000000000000000000000000000000000..f0467988604980a3d46dcee8387ec6d00c8de59d --- /dev/null +++ b/SorpLib/Components/Fittings/BaseClasses/PartialPressureLoss.mo @@ -0,0 +1,1060 @@ +within SorpLib.Components.Fittings.BaseClasses; +partial model PartialPressureLoss + "Base model for all pressure loss models" + + // + // Definition of parameters regarding the calculation setup + // + parameter SorpLib.Choices.ResistorFluidProperties positionFluidProperties= + SorpLib.Choices.ResistorFluidProperties.Detailed + "Position of fluid properties used for calculations" + annotation (Dialog(tab="General", group="Calculation Setup", enable=false), + Evaluate=true); + parameter Boolean requireTransportPropreties = true + "= true, if transport properties are required" + annotation (Dialog(tab="General", group="Calculation Setup", enable=false), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean dpFromMFlow = true + " = true, if static pressure loss is calculated from mass flow rate; otherwise, + mass flow rate is calculated from static pressure loss" + annotation (Dialog(tab="General", group="Calculation Setup", enable=false), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of parameters regarding the geometry + // + replaceable parameter SorpLib.Components.Fittings.Records.GeometryGenericReistance geometry + constrainedby SorpLib.Components.Fittings.Records.GeometryGenericReistance + "Resistor geometry" + annotation (Dialog(tab="General", group="Geometry", enable=false), + HideResult=true, + choicesAllMatching=true); + + parameter Real psi(unit="1") = 1 + "Void fraction of the resistance (i.e., psi = 1 - V_particle / V)" + annotation (Dialog(tab="General", group="Geometry", enable=false), + HideResult=true); + final parameter Modelica.Units.SI.Diameter d_hyd_mean= + (geometry.d_hyd_a + geometry.d_hyd_b) / 2 + "Hydraulic diameter" + annotation (Dialog(tab="General", group="Geometry", enable=false), + HideResult=true); + final parameter Modelica.Units.SI.Area A_a= + Modelica.Constants.pi / 4 * geometry.d_hyd_a^2 * psi + "Cross-sectional area at port a" + annotation (Dialog(tab="General", group="Geometry", enable=false), + HideResult=true); + final parameter Modelica.Units.SI.Area A_b= + Modelica.Constants.pi / 4 * geometry.d_hyd_b^2 * psi + "Cross-sectional area at port b" + annotation (Dialog(tab="General", group="Geometry", enable=false), + HideResult=true); + final parameter Modelica.Units.SI.Area A_mean= + (A_a + A_b) / 2 + "Average cross-sectional area" + annotation (Dialog(tab="General", group="Geometry", enable=false), + HideResult=true); + + // + // Definition of parameters regarding fluid properties + // + parameter SorpLib.Components.Fittings.Records.FluidProperties constantFluidProperties + "Constant fluid properties that might be used for pressure loss calculations" + annotation (Dialog(tab="General", group="Fluid Properties", enable=false)); + + // + // Definition of parameters regarding fittings + // + parameter Boolean flowDirectionDependentZeta = false + " = true, if loss factors differ with flow direction (e.g., sudden expansion) + and area and density at port a or b are used" + annotation (Dialog(tab="General", group="Fittings", enable=false), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Real[:] zeta_a(each unit="1") = {0} + "Loss factors due to fittings at port a" + annotation (Dialog(tab="General", group="Fittings", enable=false)); + parameter Real[:] zeta_b(each unit="1") = zeta_a + "Loss factors due to fittings at port b" + annotation (Dialog(tab="General", group="Fittings", enable=false)); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics", enable=false), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Modelica.Units.SI.MassFlowRate m_flow_small = 1e-4 + "Regularization mass flow rate" + annotation (Dialog(tab="Advanced", group="Numerics", enable=false)); + + parameter Boolean showTotalPressures = false + "= true, if total pressures are calculated and shown" + annotation (Dialog(tab = "Advanced", group = "Diagnostics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Boolean showVelocities = false + "= true, if fluid velocities at ports are calculated and shown" + annotation (Dialog(tab = "Advanced", group = "Diagnostics", + enable=geometry.frictionPressureLoss), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Boolean showDarcyFrictionNumber = false + "= true, if Darcy friction number is calculated and shown" + annotation (Dialog(tab = "Advanced", group = "Diagnostics", + enable=geometry.frictionPressureLoss), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Boolean showIndividualPressureLosses = false + "= true, if individual pressure loss contributions are calculated and shown" + annotation (Dialog(tab = "Advanced", group = "Diagnostics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of inputs + // + input Modelica.Units.SI.MassFlowRate m_flow + "Mass flow rate" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + input SorpLib.Components.Fittings.Records.FluidProperties fluidProperties_a + "Fluid properties at port a for design flow direction (i.e., a->b)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input SorpLib.Components.Fittings.Records.FluidProperties fluidProperties_b + "Fluid properties at port b for design flow direction (i.e., a->b)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input SorpLib.Components.Fittings.Records.FluidProperties fluidProperties_a_ad + "Fluid properties at port a for reverse design flow direction (i.e., a<-b)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input SorpLib.Components.Fittings.Records.FluidProperties fluidProperties_b_ad + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Definition of outputs + // + output Modelica.Units.SI.PressureDifference dp_static + "Static pressure loss" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // + Modelica.Units.SI.MassFlowRate m_flow_hyd + "Hydraulic mass flow rate"; + + // + // Definition of protected veriables describing fluid properties + // +protected + Modelica.Units.SI.Density rho_mean_dd + "Average density at port a for design flow direction (i.e., a->b)"; + Modelica.Units.SI.ReynoldsNumber Re_mean_dd + "Average Reynolds number describing the flow regime for design flow + direction (i.e., a->b)"; + + Modelica.Units.SI.Density rho_mean_rdd + "Average density at port a for reverse design flow direction (i.e., b->a)"; + Modelica.Units.SI.ReynoldsNumber Re_mean_rdd + "Average Reynolds number describing the flow regime for reverse design flow + direction (i.e., b->a)"; + + Real lambda_mean_dd(unit="1") + "Average Darcy friction number for design flow direction (a->b)"; + Real lambda_mean_rdd(unit="1") + "Average Darcy friction number for reverse design flow direction (b->a)"; + + Modelica.Units.SI.PressureDifference dp_dyn_dd + "Dynamic pressure loss for design flow direction (a->b)"; + Modelica.Units.SI.PressureDifference dp_geo_dd + "Geodetic pressure loss for design flow direction (a->b)"; + Real f_fric_dd(unit="1/(kg.m)") + "Factor of friction-caused pressure loss for design flow direction (a->b)"; + Real f_fit_dd(unit="1/(kg.m)") + "Factor of fitting-caused pressure loss for design flow direction (a->b)"; + + Modelica.Units.SI.PressureDifference dp_dyn_rdd + "Dynamic pressure loss for reverse design flow direction (b->a)"; + Modelica.Units.SI.PressureDifference dp_geo_rdd + "Geodetic pressure loss for reverse design flow direction (b->a)"; + Real f_fric_rdd(unit="1/(kg.m)") + "Factor of friction-caused pressure loss for reverse design flow direction + (b->a)"; + Real f_fit_rdd(unit="1/(kg.m)") + "Factor of fitting-caused pressure loss for reverse design flow direction + (b->a)"; + + // + // Definition of variables required to calculate diagnostic variables + // + Modelica.Units.SI.Density rho_a + "Density at port a"; + Modelica.Units.SI.Density rho_b + "Density at port b"; + + Modelica.Units.SI.DynamicViscosity eta_a + "Dynamic viscosity at port a"; + Modelica.Units.SI.DynamicViscosity eta_b + "Dynamic viscosity at port b"; + + // + // Definition (and calculation) of diagnostic variables + // +public + Modelica.Units.SI.Velocity w_a + "Hydraulic fluid velocity at port a"; + Modelica.Units.SI.Velocity w_b + "Hydraulic fluid velocity at port b"; + Modelica.Units.SI.Velocity w_mean + "Average hydraulic fluid velocity"; + + Modelica.Units.SI.ReynoldsNumber Re_a= + abs(m_flow_hyd) * geometry.d_hyd_a / (A_a * eta_a) if + showDarcyFrictionNumber + "Reynolds number describing the flow regime at port a"; + Modelica.Units.SI.ReynoldsNumber Re_b= + abs(m_flow_hyd) * geometry.d_hyd_b / (A_b * eta_b) if + showDarcyFrictionNumber + "Reynolds number describing the flow regime at port b"; + Modelica.Units.SI.ReynoldsNumber Re_mean= + abs(m_flow_hyd) * (geometry.d_hyd_a / (A_a * eta_a) + + geometry.d_hyd_b / (A_b * eta_b)) / 2 if + showDarcyFrictionNumber + "Average Reynolds number describing the flow regime"; + + Real lambda_mean(unit="1")= + SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=lambda_mean_dd, + y2=lambda_mean_rdd, + x_small=m_flow_small) if + showDarcyFrictionNumber + "Average darcy friction number"; + + Modelica.Units.SI.Pressure p_total_a= + fluidProperties_a.p + (w_a^2 / 2 + + Modelica.Constants.g_n * geometry.z_a) * rho_a if + showTotalPressures + "Total pressure at port a"; + Modelica.Units.SI.Pressure p_total_b= + fluidProperties_b_ad.p + (w_b^2 / 2 + + Modelica.Constants.g_n * geometry.z_b) * rho_b if + showTotalPressures + "Total pressure at port b"; + Modelica.Units.SI.PressureDifference dp_total= + fluidProperties_a.p + (w_a^2 / 2 + + Modelica.Constants.g_n * geometry.z_a) * rho_a - + fluidProperties_b_ad.p - (w_b^2 / 2 + + Modelica.Constants.g_n * geometry.z_b) * rho_b if + showTotalPressures + "Total pressure difference"; + + Modelica.Units.SI.PressureDifference dp_dyn= + 1/2 * (rho_a * w_a^2 - rho_b * w_b^2) if + showIndividualPressureLosses + "Dynamic pressure difference between port a and b"; + Modelica.Units.SI.PressureDifference dp_geo = Modelica.Constants.g_n * + (geometry.z_a * rho_a - geometry.z_b * rho_b) if + showIndividualPressureLosses + "Geodetic pressure difference between port a and b"; + Modelica.Units.SI.PressureDifference dp_fric= + SorpLib.Numerics.regSquareWFactors( + x=m_flow_hyd, + delta_x=m_flow_small, + f_positive=1/(f_fric_dd+Modelica.Constants.small), + f_negative=1/(f_fric_rdd+Modelica.Constants.small)) if + showIndividualPressureLosses + "Pressure difference between port a and b due to friction"; + Modelica.Units.SI.PressureDifference dp_fit= + SorpLib.Numerics.regSquareWFactors( + x=m_flow_hyd, + delta_x=m_flow_small, + f_positive=1/(f_fit_dd+Modelica.Constants.small), + f_negative=1/(f_fit_rdd+Modelica.Constants.small)) if + showIndividualPressureLosses + "Pressure difference between port a and b due to fittings"; + +equation + // + // Assertations + // + if not geometry.dynamicPressureLoss then + assert(Modelica.Math.isEqual( + s1=geometry.d_hyd_a, + s2=geometry.d_hyd_b, + eps=Modelica.Constants.eps), + "Dynamic pressure loss is not considered: Hydraulic diameters must be " + + "equal to calculate sound results!", + level=AssertionLevel.error); + end if; + + if not geometry.geodeticPressureLoss then + assert(Modelica.Math.isEqual( + s1=geometry.z_a, + s2=geometry.z_b, + eps=Modelica.Constants.eps), + "Geodetic pressure loss is not considered: Heights must be equal to " + + "calculate sound results!", + level=AssertionLevel.error); + end if; + + // + // Calculate variables required to calculate diagnostic variables + // + if showVelocities or showTotalPressures or showIndividualPressureLosses then + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + rho_a = constantFluidProperties.rho + "Density at port a"; + rho_b = constantFluidProperties.rho + "Density at port b"; + + eta_a = constantFluidProperties.eta + "Dynamic viscosity at port a"; + eta_b = constantFluidProperties.eta + "Dynamic viscosity at port b"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + rho_a = fluidProperties_a.rho + "Density at port a"; + rho_b = fluidProperties_a.rho + "Density at port b"; + + eta_a = fluidProperties_a.eta + "Dynamic viscosity at port a"; + eta_b = fluidProperties_a.eta + "Dynamic viscosity at port b"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + rho_a = fluidProperties_b_ad.rho + "Density at port a"; + rho_b = fluidProperties_b_ad.rho + "Density at port b"; + + eta_a = fluidProperties_b_ad.eta + "Dynamic viscosity at port a"; + eta_b = fluidProperties_b_ad.eta + "Dynamic viscosity at port b"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet then + if avoid_events then + rho_a = SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=fluidProperties_a.rho, + y2=fluidProperties_b_ad.rho, + x_small=m_flow_small) + "Density at port a"; + rho_b = SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=fluidProperties_a.rho, + y2=fluidProperties_b_ad.rho, + x_small=m_flow_small) + "Density at port b"; + + eta_a = SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=fluidProperties_a.eta, + y2=fluidProperties_b_ad.eta, + x_small=m_flow_small) + "Dynamic viscosity at port a"; + eta_b = SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=fluidProperties_a.eta, + y2=fluidProperties_b_ad.eta, + x_small=m_flow_small) + "Dynamic viscosity at port b"; + + else + rho_a = SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=fluidProperties_a.rho, + y2=fluidProperties_b_ad.rho, + x_small=m_flow_small) + "Density at port a"; + rho_b = SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=fluidProperties_a.rho, + y2=fluidProperties_b_ad.rho, + x_small=m_flow_small) + "Density at port b"; + + eta_a = SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=fluidProperties_a.eta, + y2=fluidProperties_b_ad.eta, + x_small=m_flow_small) + "Dynamic viscosity at port a"; + eta_b = SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=fluidProperties_a.eta, + y2=fluidProperties_b_ad.eta, + x_small=m_flow_small) + "Dynamic viscosity at port b"; + + end if; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + rho_a = (fluidProperties_a.rho + fluidProperties_b_ad.rho) / 2 + "Density at port a"; + rho_b = (fluidProperties_a.rho + fluidProperties_b_ad.rho) / 2 + "Density at port b"; + + eta_a = (fluidProperties_a.eta + fluidProperties_b_ad.eta) / 2 + "Dynamic viscosity at port a"; + eta_b = (fluidProperties_a.eta + fluidProperties_b_ad.eta) / 2 + "Dynamic viscosity at port b"; + + else + if avoid_events then + rho_a = SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=fluidProperties_a.rho, + y2=fluidProperties_a_ad.rho, + x_small=m_flow_small) + "Density at port a"; + rho_b = SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=fluidProperties_b.rho, + y2=fluidProperties_b_ad.rho, + x_small=m_flow_small) + "Density at port a"; + + eta_a = SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=fluidProperties_a.eta, + y2=fluidProperties_a_ad.eta, + x_small=m_flow_small) + "Dynamic viscosity at port a"; + eta_b = SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=fluidProperties_b.eta, + y2=fluidProperties_b_ad.eta, + x_small=m_flow_small) + "Dynamic viscosity at port a"; + + else + rho_a = SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=fluidProperties_a.rho, + y2=fluidProperties_a_ad.rho, + x_small=m_flow_small) + "Density at port a"; + rho_b = SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=fluidProperties_b.rho, + y2=fluidProperties_b_ad.rho, + x_small=m_flow_small) + "Density at port a"; + + eta_a = SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=fluidProperties_a.eta, + y2=fluidProperties_a_ad.eta, + x_small=m_flow_small) + "Dynamic viscosity at port a"; + eta_b = SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=fluidProperties_b.eta, + y2=fluidProperties_b_ad.eta, + x_small=m_flow_small) + "Dynamic viscosity at port a"; + + end if; + end if; + + w_a = m_flow_hyd / (A_a * rho_a) + "Hydraulic fluid velocity at port a"; + w_b = m_flow_hyd / (A_b * rho_b) + "Hydraulic fluid velocity at port b"; + w_mean = (w_a + w_b) / 2 + "Average hydraulic fluid velocity"; + + else + rho_a = 0 + "Density at port a"; + rho_b = 0 + "Density at port b"; + + eta_a = 0 + "Dynamic viscosity at port a"; + eta_b = 0 + "Dynamic viscosity at port b"; + + w_a = 0 + "Hydraulic fluid velocity at port a"; + w_b = 0 + "Hydraulic fluid velocity at port b"; + w_mean = 0 + "Average hydraulic fluid velocity"; + + end if; + + // + // Calculate average properties for design flow direction (a->b) + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + rho_mean_dd = constantFluidProperties.rho + "Average density for design flow direction (i.e., a->b)"; + Re_mean_dd = abs(m_flow_hyd) / constantFluidProperties.eta * + (geometry.d_hyd_a / A_a + geometry.d_hyd_b / A_b) / 2 + "Average Reynolds number describing the flow regime for design flow + direction (i.e., a->b)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + rho_mean_dd = fluidProperties_a.rho + "Average density for design flow direction (i.e., a->b)"; + Re_mean_dd = abs(m_flow_hyd) / fluidProperties_a.eta * + (geometry.d_hyd_a / A_a + geometry.d_hyd_b / A_b) / 2 + "Average Reynolds number describing the flow regime for design flow + direction (i.e., a->b)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + rho_mean_dd = fluidProperties_b_ad.rho + "Average density for design flow direction (i.e., a->b)"; + Re_mean_dd = abs(m_flow_hyd) / fluidProperties_b_ad.eta * + (geometry.d_hyd_a / A_a + geometry.d_hyd_b / A_b) / 2 + "Average Reynolds number describing the flow regime for design flow + direction (i.e., a->b)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet then + rho_mean_dd = fluidProperties_a.rho + "Average density for design flow direction (i.e., a->b)"; + Re_mean_dd = abs(m_flow_hyd) / fluidProperties_a.eta * + (geometry.d_hyd_a / A_a + geometry.d_hyd_b / A_b) / 2 + "Average Reynolds number describing the flow regime for design flow + direction (i.e., a->b)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + rho_mean_dd = (fluidProperties_a.rho + fluidProperties_b_ad.rho) / 2 + "Average density for design flow direction (i.e., a->b)"; + Re_mean_dd = abs(m_flow_hyd) / + ((fluidProperties_a.eta + fluidProperties_b_ad.eta) / 2) * + (geometry.d_hyd_a / A_a + geometry.d_hyd_b / A_b) / 2 + "Average Reynolds number describing the flow regime for design flow + direction (i.e., a->b)"; + + else + rho_mean_dd = (fluidProperties_a.rho + fluidProperties_b.rho) / 2 + "Average density for design flow direction (i.e., a->b)"; + Re_mean_dd = abs(m_flow_hyd) * + (geometry.d_hyd_a / (A_a * fluidProperties_a.eta) + + geometry.d_hyd_b / (A_b * fluidProperties_b.eta)) / 2 + "Average Reynolds number describing the flow regime for design flow + direction (i.e., a->b)"; + + end if; + + // + // Calculate average properties for reverse design flow direction (b->a) + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + rho_mean_rdd = rho_mean_dd + "Average density for reverse design flow direction (i.e., b->a)"; + Re_mean_rdd = Re_mean_dd + "Average Reynolds number describing the flow regime for reverse flow + design direction (i.e., b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + rho_mean_rdd = rho_mean_dd + "Average density for reverse design flow direction (i.e., b->a)"; + Re_mean_rdd = Re_mean_dd + "Average Reynolds number describing the flow regime for reverse flow + design direction (i.e., b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + rho_mean_rdd = rho_mean_dd + "Average density for reverse design flow direction (i.e., b->a)"; + Re_mean_rdd = Re_mean_dd + "Average Reynolds number describing the flow regime for reverse flow + design direction (i.e., b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet then + rho_mean_rdd = fluidProperties_b_ad.rho + "Average density for reverse design flow direction (i.e., b->a)"; + Re_mean_rdd = abs(m_flow_hyd) / fluidProperties_b_ad.eta * + (geometry.d_hyd_a / A_a + geometry.d_hyd_b / A_b) / 2 + "Average Reynolds number describing the flow regime for reverse flow + design direction (i.e., b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + rho_mean_rdd = rho_mean_dd + "Average density for reverse design flow direction (i.e., b->a)"; + Re_mean_rdd = Re_mean_dd + "Average Reynolds number describing the flow regime for reverse flow + design direction (i.e., b->a)"; + + else + rho_mean_rdd = (fluidProperties_a_ad.rho + fluidProperties_b_ad.rho) / 2 + "Average density for reverse design flow direction (i.e., b->a)"; + Re_mean_rdd = abs(m_flow_hyd) * + (geometry.d_hyd_a / (A_a * fluidProperties_a_ad.eta) + + geometry.d_hyd_b / (A_b * fluidProperties_b_ad.eta)) / 2 + "Average Reynolds number describing the flow regime for reverse flow + design direction (i.e., b->a)"; + + end if; + + // + // Calculate factors required for dynamic pressure loss + // + if geometry.dynamicPressureLoss then + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + dp_dyn_dd = 1/2 * m_flow_hyd^2 * 1/constantFluidProperties.rho * + (1/A_b^2 - 1/A_a^2) + "Dynamic pressure loss for design flow direction (a->b)"; + dp_dyn_rdd = dp_dyn_dd + "Dynamic pressure loss for reverse design flow direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + dp_dyn_dd = 1/2 * m_flow_hyd^2 * 1/fluidProperties_a.rho * + (1/A_b^2 - 1/A_a^2) + "Dynamic pressure loss for design flow direction (a->b)"; + dp_dyn_rdd = dp_dyn_dd + "Dynamic pressure loss for reverse design flow direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + dp_dyn_dd = 1/2 * m_flow_hyd^2 * 1/fluidProperties_b_ad.rho * + (1/A_b^2 - 1/A_a^2) + "Dynamic pressure loss for design flow direction (a->b)"; + dp_dyn_rdd = dp_dyn_dd + "Dynamic pressure loss for reverse design flow direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet then + dp_dyn_dd = 1/2 * m_flow_hyd^2 * 1/fluidProperties_a.rho * + (1/A_b^2 - 1/A_a^2) + "Dynamic pressure loss for design flow direction (a->b)"; + dp_dyn_rdd = 1/2 * m_flow_hyd^2 * 1/fluidProperties_b_ad.rho * + (1/A_b^2 - 1/A_a^2) + "Dynamic pressure loss for reverse design flow direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + dp_dyn_dd = 1 / (fluidProperties_a.rho + fluidProperties_b_ad.rho) * + m_flow_hyd^2 * (1/A_b^2 - 1/A_a^2) + "Dynamic pressure loss for design flow direction (a->b)"; + dp_dyn_rdd = dp_dyn_dd + "Dynamic pressure loss for reverse design flow direction (b->a)"; + + else + dp_dyn_dd = 1/2 * m_flow_hyd^2 * (1 / (A_b^2 * fluidProperties_b.rho) - + 1 / (A_a^2 * fluidProperties_a.rho)) + "Dynamic pressure loss for design flow direction (a->b)"; + dp_dyn_rdd = 1/2 * m_flow_hyd^2 * (1 / (A_b^2 * fluidProperties_b_ad.rho) - + 1 / (A_a^2 * fluidProperties_a_ad.rho)) + "Dynamic pressure loss for reverse design flow direction (b->a)"; + + end if; + + else + dp_dyn_dd = 0 + "Dynamic pressure loss for design flow direction (a->b)"; + dp_dyn_rdd = 0 + "Dynamic pressure loss for reverse design flow direction (b->a)"; + + end if; + + // + // Calculate factors required for geodetic pressure loss + // + if geometry.geodeticPressureLoss then + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + dp_geo_dd = Modelica.Constants.g_n * constantFluidProperties.rho * + (geometry.z_b - geometry.z_a) + "Geodetic pressure loss for design flow direction (a->b)"; + dp_geo_rdd = dp_geo_dd + "Geodetic pressure loss for reverse design flow direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + dp_geo_dd = Modelica.Constants.g_n * fluidProperties_a.rho * + (geometry.z_b - geometry.z_a) + "Geodetic pressure loss for design flow direction (a->b)"; + dp_geo_rdd = dp_geo_dd + "Geodetic pressure loss for reverse design flow direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + dp_geo_dd = Modelica.Constants.g_n * fluidProperties_b_ad.rho * + (geometry.z_b - geometry.z_a) + "Geodetic pressure loss for design flow direction (a->b)"; + dp_geo_rdd = dp_geo_dd + "Geodetic pressure loss for reverse design flow direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet then + dp_geo_dd = Modelica.Constants.g_n * fluidProperties_a.rho * + (geometry.z_b - geometry.z_a) + "Geodetic pressure loss for design flow direction (a->b)"; + dp_geo_rdd = Modelica.Constants.g_n * fluidProperties_b_ad.rho * + (geometry.z_b - geometry.z_a) + "Geodetic pressure loss for reverse design flow direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + dp_geo_dd = Modelica.Constants.g_n * (fluidProperties_a.rho + + fluidProperties_b_ad.rho) / 2 * (geometry.z_b - geometry.z_a) + "Geodetic pressure loss for design flow direction (a->b)"; + dp_geo_rdd = dp_geo_dd + "Geodetic pressure loss for reverse design flow direction (b->a)"; + + else + dp_geo_dd = Modelica.Constants.g_n * (fluidProperties_b.rho * + geometry.z_b - fluidProperties_a.rho * geometry.z_a) + "Geodetic pressure loss for design flow direction (a->b)"; + dp_geo_rdd = Modelica.Constants.g_n * (fluidProperties_b_ad.rho * + geometry.z_b - fluidProperties_a_ad.rho * geometry.z_a) + "Geodetic pressure loss for reverse design flow direction (b->a)"; + + end if; + + else + dp_geo_dd = 0 + "Geodetic pressure loss for design flow direction (a->b)"; + dp_geo_rdd = 0 + "Geodetic pressure loss for reverse design flow direction (b->a)"; + + end if; + + // + // Calculate factors required for friction-caused pressure loss + // + if geometry.frictionPressureLoss then + f_fric_dd = 1/2 * 1 / (rho_mean_dd * A_mean^2) * + geometry.l / d_hyd_mean * lambda_mean_dd + "Factor of friction-caused pressure loss for design flow direction (a->b)"; + f_fric_rdd = 1/2 * 1 / (rho_mean_rdd * A_mean^2) * + geometry.l / d_hyd_mean * lambda_mean_rdd + "Factor of friction-caused pressure loss for reverse design flow direction + (b->a)"; + + else + f_fric_dd = 0 + "Factor of friction-caused pressure loss for design flow direction (a->b)"; + f_fric_rdd = 0 + "Factor of friction-caused pressure loss for reverse design flow direction + (b->a)"; + + end if; + + // + // Calculate factors required for fitting-caused pressure loss + // + if geometry.fittingPressureLosss then + if flowDirectionDependentZeta then + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + f_fit_dd = 1/2 * sum(zeta_a) / (constantFluidProperties.rho * A_a^2) + "Factor of fitting-caused pressure loss for design flow direction + (a->b)"; + f_fit_rdd = 1/2 * sum(zeta_b) / (constantFluidProperties.rho * A_b^2) + "Factor of fitting-caused pressure loss for reverse design flow + direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + f_fit_dd = 1/2 * sum(zeta_a) / (fluidProperties_a.rho * A_a^2) + "Factor of fitting-caused pressure loss for design flow direction + (a->b)"; + f_fit_rdd = 1/2 * sum(zeta_b) / (fluidProperties_a.rho * A_b^2) + "Factor of fitting-caused pressure loss for reverse design flow + direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + f_fit_dd = 1/2 * sum(zeta_a) / (fluidProperties_b_ad.rho * A_a^2) + "Factor of fitting-caused pressure loss for design flow direction + (a->b)"; + f_fit_rdd = 1/2 * sum(zeta_b) / (fluidProperties_b_ad.rho * A_b^2) + "Factor of fitting-caused pressure loss for reverse design flow + direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet then + f_fit_dd = 1/2 * sum(zeta_a) / (fluidProperties_a.rho * A_a^2) + "Factor of fitting-caused pressure loss for design flow direction + (a->b)"; + f_fit_rdd = 1/2 * sum(zeta_b) / (fluidProperties_b_ad.rho * A_b^2) + "Factor of fitting-caused pressure loss for reverse design flow + direction (b->a)"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + f_fit_dd = 1/2 * sum(zeta_a) / ((fluidProperties_a.rho + + fluidProperties_b_ad.rho) / 2 * A_a^2) + "Factor of fitting-caused pressure loss for design flow direction + (a->b)"; + f_fit_rdd = 1/2 * sum(zeta_b) / ((fluidProperties_a.rho + + fluidProperties_b_ad.rho) / 2 * A_b^2) + "Factor of fitting-caused pressure loss for reverse design flow + direction (b->a)"; + + else + f_fit_dd = 1/2 * sum(zeta_a) / (fluidProperties_a.rho * A_a^2) + "Factor of fitting-caused pressure loss for design flow direction + (a->b)"; + f_fit_rdd = 1/2 * sum(zeta_b) / (fluidProperties_b_ad.rho * A_b^2) + "Factor of fitting-caused pressure loss for reverse design flow + direction (b->a)"; + + end if; + + else + f_fit_dd = 1/2 * ((sum(zeta_a) + sum(zeta_b)) / 2) / + (rho_mean_dd * A_mean^2) + "Factor of fitting-caused pressure loss for design flow direction (a->b)"; + f_fit_rdd = 1/2 * ((sum(zeta_a) + sum(zeta_b)) / 2) / + (rho_mean_rdd * A_mean^2) + "Factor of fitting-caused pressure loss for reverse design flow direction + (b->a)"; + + end if; + + else + f_fit_dd = 0 + "Factor of fitting-caused pressure loss for design flow direction (a->b)"; + f_fit_rdd = 0 + "Factor of fitting-caused pressure loss for reverse design flow direction + (b->a)"; + + end if; + + // + // Calculate pressure difference as function of mass flow rate or vice versa + // + if dpFromMFlow then + if avoid_events then + if (geometry.dynamicPressureLoss or geometry.geodeticPressureLoss) and + not (geometry.frictionPressureLoss or geometry.fittingPressureLosss) then + dp_static = + SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=dp_dyn_dd + dp_geo_dd, + y2=dp_dyn_rdd + dp_geo_rdd, + x_small=m_flow_small) + "Static pressure difference between port a and b"; + + elseif not (geometry.dynamicPressureLoss or geometry.geodeticPressureLoss) and + (geometry.frictionPressureLoss or geometry.fittingPressureLosss) then + dp_static = + SorpLib.Numerics.regSquareWFactors_noEvent( + x=m_flow_hyd, + delta_x=m_flow_small, + f_positive=1 / (f_fric_dd + f_fit_dd + Modelica.Constants.small), + f_negative=1 / (f_fric_rdd + f_fit_rdd + Modelica.Constants.small)) + "Static pressure difference between port a and b"; + + else + dp_static = + SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=dp_dyn_dd + dp_geo_dd, + y2=dp_dyn_rdd + dp_geo_rdd, + x_small=m_flow_small) + + SorpLib.Numerics.regSquareWFactors_noEvent( + x=m_flow_hyd, + delta_x=m_flow_small, + f_positive=1 / (f_fric_dd + f_fit_dd + Modelica.Constants.small), + f_negative=1 / (f_fric_rdd + f_fit_rdd + Modelica.Constants.small)) + "Static pressure difference between port a and b"; + + end if; + + else + if (geometry.dynamicPressureLoss or geometry.geodeticPressureLoss) and + not (geometry.frictionPressureLoss or geometry.fittingPressureLosss) then + dp_static = + SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=dp_dyn_dd + dp_geo_dd, + y2=dp_dyn_rdd + dp_geo_rdd, + x_small=m_flow_small) + "Static pressure difference between port a and b"; + + elseif not (geometry.dynamicPressureLoss or geometry.geodeticPressureLoss) and + (geometry.frictionPressureLoss or geometry.fittingPressureLosss) then + dp_static = + SorpLib.Numerics.regSquareWFactors( + x=m_flow_hyd, + delta_x=m_flow_small, + f_positive=1 / (f_fric_dd + f_fit_dd + Modelica.Constants.small), + f_negative=1 / (f_fric_rdd + f_fit_rdd + Modelica.Constants.small)) + "Static pressure difference between port a and b"; + + else + dp_static = + SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=dp_dyn_dd + dp_geo_dd, + y2=dp_dyn_rdd + dp_geo_rdd, + x_small=m_flow_small) + + SorpLib.Numerics.regSquareWFactors( + x=m_flow_hyd, + delta_x=m_flow_small, + f_positive=1 / (f_fric_dd + f_fit_dd + Modelica.Constants.small), + f_negative=1 / (f_fric_rdd + f_fit_rdd + Modelica.Constants.small)) + "Static pressure difference between port a and b"; + + end if; + end if; + + else + if avoid_events then + if (geometry.dynamicPressureLoss or geometry.geodeticPressureLoss) and + not (geometry.frictionPressureLoss or geometry.fittingPressureLosss) then + dp_static = + SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=dp_dyn_dd + dp_geo_dd, + y2=dp_dyn_rdd + dp_geo_rdd, + x_small=m_flow_small) + "Static pressure difference between port a and b"; + + elseif not (geometry.dynamicPressureLoss or geometry.geodeticPressureLoss) and + (geometry.frictionPressureLoss or geometry.fittingPressureLosss) then + m_flow_hyd = + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_static, + delta_x=m_flow_small, + f_positive=1 / (f_fric_dd + f_fit_dd + Modelica.Constants.small), + f_negative=1 / (f_fric_rdd + f_fit_rdd + Modelica.Constants.small)) + "Hydraulic mass flow rate"; + + else + dp_static = + SorpLib.Numerics.regStep_noEvent( + x=m_flow_hyd, + y1=dp_dyn_dd + dp_geo_dd, + y2=dp_dyn_rdd + dp_geo_rdd, + x_small=m_flow_small) + + SorpLib.Numerics.regSquareWFactors_noEvent( + x=m_flow_hyd, + delta_x=m_flow_small, + f_positive=1 / (f_fric_dd + f_fit_dd + Modelica.Constants.small), + f_negative=1 / (f_fric_rdd + f_fit_rdd + Modelica.Constants.small)) + "Static pressure difference between port a and b"; + + end if; + + else + if (geometry.dynamicPressureLoss or geometry.geodeticPressureLoss) and + not (geometry.frictionPressureLoss or geometry.fittingPressureLosss) then + dp_static = + SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=dp_dyn_dd + dp_geo_dd, + y2=dp_dyn_rdd + dp_geo_rdd, + x_small=m_flow_small) + "Static pressure difference between port a and b"; + + elseif not (geometry.dynamicPressureLoss or geometry.geodeticPressureLoss) and + (geometry.frictionPressureLoss or geometry.fittingPressureLosss) then + m_flow_hyd = + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_static, + delta_x=m_flow_small, + f_positive=1 / (f_fric_dd + f_fit_dd + Modelica.Constants.small), + f_negative=1 / (f_fric_rdd + f_fit_rdd + Modelica.Constants.small)) + "Hydraulic mass flow rate"; + + else + dp_static = + SorpLib.Numerics.regStep( + x=m_flow_hyd, + y1=dp_dyn_dd + dp_geo_dd, + y2=dp_dyn_rdd + dp_geo_rdd, + x_small=m_flow_small) + + SorpLib.Numerics.regSquareWFactors( + x=m_flow_hyd, + delta_x=m_flow_small, + f_positive=1 / (f_fric_dd + f_fit_dd + Modelica.Constants.small), + f_negative=1 / (f_fric_rdd + f_fit_rdd + Modelica.Constants.small)) + "Static pressure difference between port a and b"; + + end if; + end if; + + end if; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Ellipse( + extent={{-80,80},{80,-80}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={0,127,0}, + fillPattern=FillPattern.Solid), + Text( + extent={{-60,60},{60,-60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid, + textString="ṁ += +f(Δp, ...)")}), Diagram(coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the base model for all pressure loss models. It defines +fundamental parameters and variables required by all pressure loss models. Models +that inherit properties from this partial model have to complete the friction- +based pressure loss correlation. Furthermore, the geometry record may be redeclared +and constrained. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Hydraulic mass flow rate <i>m_flow_hyd</i>. + </li> + <li> + Friction factor <i>lambda_mean_dd</i> for design flow direction (i.e., a->b). + </li> + <li> + Friction factor <i>lambda_mean_rdd</i> for reverse design flow direction (i.e., + a->b). + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PartialPressureLoss; diff --git a/SorpLib/Components/Fittings/BaseClasses/PartialResistance.mo b/SorpLib/Components/Fittings/BaseClasses/PartialResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..9cb3f4b58aa5311c66c570a911a8e74e15694a2d --- /dev/null +++ b/SorpLib/Components/Fittings/BaseClasses/PartialResistance.mo @@ -0,0 +1,484 @@ +within SorpLib.Components.Fittings.BaseClasses; +partial model PartialResistance + "Base model for all hydraulic resistors" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding calculation setup + // + parameter SorpLib.Choices.ResistorFluidProperties positionFluidProperties= + SorpLib.Choices.ResistorFluidProperties.ActualInlet + "Position of fluid properties used for calculations" + annotation (Dialog(tab="General", group="Calculation Setup"), + Evaluate=true, + HideResult = true); + parameter Boolean instreamingPropertiesByInput = false + " = true, if instreaming fluid properties are provied via inputs (i.e., + fluidProperties_a and fluidProperties_b_ad) if already calculated" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + parameter Boolean dpFromMFlow = true + " = true, if static pressure loss is calculated from mass flow rate; otherwise, + mass flow rate is calculated from static pressure loss" + annotation (Dialog(tab="General", group="Calculation Setup", + enable= not dynamicPressureLoss and not geodeticPressureLoss and + (frictionPressureLoss or fittingPressureLosss)), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + parameter Boolean dynamicPressureLoss = false + " = true, if dynamic pressure loss shall be included (i.e., different + velocities at port a and b due to change of cross-sectional areas and + densities)" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Boolean geodeticPressureLoss = false + " = true, if geodetic pressure loss shall be included (i.e., different + heights at port a and b)" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Boolean frictionPressureLoss = false + " = true, if pressure loss due to friction shall be included" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Boolean fittingPressureLosss = true + " = true, if pressure losses due to fittings shall be included" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of parameters regarding the resistance characterisation + // + replaceable model PressureLossModel = + SorpLib.Components.Fittings.BaseClasses.PartialPressureLoss + constrainedby SorpLib.Components.Fittings.BaseClasses.PartialPressureLoss( + positionFluidProperties=positionFluidProperties, + dpFromMFlow=dpFromMFlow, + geometry=geometry, + constantFluidProperties= + SorpLib.Components.Fittings.Records.FluidProperties( + p=p_ref, + T=T_ref, + rho=rho_ref, + eta=eta_ref), + flowDirectionDependentZeta=flowDirectionDependentZeta, + zeta_a=zeta_a, + zeta_b=zeta_b, + m_flow=m_flow, + fluidProperties_a=fluidProperties_a, + fluidProperties_b=fluidProperties_b, + fluidProperties_a_ad=fluidProperties_a_ad, + fluidProperties_b_ad=fluidProperties_b_ad, + avoid_events=avoid_events, + m_flow_small=m_flow_small) + "Pressure loss model" + annotation (Dialog(tab="Resistance Characterisation", group="Models"), + choicesAllMatching=true); + + replaceable parameter SorpLib.Components.Fittings.Records.GeometryGenericReistance geometry + constrainedby SorpLib.Components.Fittings.Records.GeometryGenericReistance( + final dynamicPressureLoss=dynamicPressureLoss, + final geodeticPressureLoss=geodeticPressureLoss, + final frictionPressureLoss=frictionPressureLoss, + final fittingPressureLosss=fittingPressureLosss) + "Resistor geometry" + annotation (Dialog(tab="Resistance Characterisation", group="Geometry"), + choicesAllMatching=true); + + parameter Modelica.Units.SI.Pressure p_ref = 1e5 + "Reference pressure that might be used for pressure loss calculations" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant)); + parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature that might be used for pressure loss calculations" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant)); + parameter Modelica.Units.SI.Density rho_ref = 997 + "Reference density that might be used for pressure loss calculations" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant)); + parameter Modelica.Units.SI.DynamicViscosity eta_ref = 8.9e-4 + "Reference dynamic viscosity that might be used for pressure loss calculations" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant)); + + parameter Boolean flowDirectionDependentZeta = false + " = true, if loss factors differ with flow direction (e.g., sudden expansion) + and area and density at port a or b are used" + annotation (Dialog(tab="Resistance Characterisation", group="Fittings", + enable=fittingPressureLosss), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Real[:] zeta_a(each unit="1") = {0} + "Loss factors due to fittings at port a" + annotation (Dialog(tab="Resistance Characterisation", group="Fittings", + enable=fittingPressureLosss)); + parameter Real[:] zeta_b(each unit="1") = zeta_a + "Loss factors due to fittings at port b" + annotation (Dialog(tab="Resistance Characterisation", group="Fittings", + enable=fittingPressureLosss and flowDirectionDependentZeta)); + + // + // Definition or initialisation parameters + // + parameter Modelica.Units.SI.MassFlowRate m_flow_start = 1e-4 + "Start value for mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Modelica.Units.SI.MassFlowRate m_flow_small = 1e-4 + "Regularization mass flow rate" + annotation (Dialog(tab="Advanced", group="Numerics")); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput p_a(final unit="Pa") = p_ref if + instreamingPropertiesByInput + "Pressure at port a for design flow direction (i.e., a->b)" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=instreamingPropertiesByInput)); + Modelica.Blocks.Interfaces.RealInput T_a(final unit="K") = T_ref if + instreamingPropertiesByInput + "Temperature at port a for design flow direction (i.e., a->b)" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=instreamingPropertiesByInput)); + Modelica.Blocks.Interfaces.RealInput rho_a(final unit="kg/m3") = rho_ref if + instreamingPropertiesByInput + "Density at port a for design flow direction (i.e., a->b)" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=instreamingPropertiesByInput)); + Modelica.Blocks.Interfaces.RealInput eta_a(final unit="Pa.s") = eta_ref if + instreamingPropertiesByInput + "Dynamic viscosity at port a for design flow direction (i.e., a->b)" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=instreamingPropertiesByInput)); + + Modelica.Blocks.Interfaces.RealInput p_b_ad(final unit="Pa") = p_ref if + instreamingPropertiesByInput + "Pressure at port b for reverse design flow direction (i.e., a<-b)" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=instreamingPropertiesByInput)); + Modelica.Blocks.Interfaces.RealInput T_b_ad(final unit="K") = T_ref if + instreamingPropertiesByInput + "Temperature at port b for reverse design flow direction (i.e., a<-b)" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=instreamingPropertiesByInput)); + Modelica.Blocks.Interfaces.RealInput rho_b_ad(final unit="kg/m3") = rho_ref if + instreamingPropertiesByInput + "Density at port b for reverse design flow direction (i.e., a<-b)" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=instreamingPropertiesByInput)); + Modelica.Blocks.Interfaces.RealInput eta_b_ad(final unit="Pa.s") = eta_ref if + instreamingPropertiesByInput + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)" + annotation (Dialog(tab="Resistance Characterisation", group="Fluid Properties", + enable=instreamingPropertiesByInput)); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput p_a_internal(final unit="Pa") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput T_a_internal(final unit="K") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput rho_a_internal(final unit="kg/m3") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput eta_a_internal(final unit="Pa.s") + "Needed for connecting to conditional connector"; + + Modelica.Blocks.Interfaces.RealInput p_b_ad_internal(final unit="Pa") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput T_b_ad_internal(final unit="K") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput rho_b_ad_internal(final unit="kg/m3") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput eta_b_ad_internal(final unit="Pa.s") + "Needed for connecting to conditional connector"; + + // + // Definition of ports + // +public + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=m_flow_start)) + "Fluid port a" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}), + iconTransformation(extent={{-90,-10},{-70,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-m_flow_start)) + "Fluid port b" + annotation (Placement(transformation(extent={{70,-10},{90,10}}), + iconTransformation(extent={{70,-10},{90,10}})), + choicesAllMatching=true); + + // + // Definition of models + // + PressureLossModel pressureLossModel + "Model to calculate the pressure loss"; + + // + // Definition of variables + // + SorpLib.Components.Fittings.Records.FluidProperties fluidProperties_a + "Fluid properties at port a for design flow direction (i.e., a->b)"; + SorpLib.Components.Fittings.Records.FluidProperties fluidProperties_b + "Fluid properties at port b for design flow direction (i.e., a->b)"; + SorpLib.Components.Fittings.Records.FluidProperties fluidProperties_a_ad + "Fluid properties at port a for reverse design flow direction (i.e., a<-b)"; + SorpLib.Components.Fittings.Records.FluidProperties fluidProperties_b_ad + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + Modelica.Units.SI.PressureDifference dp + "Static pressure difference between port a and b"; + Modelica.Units.SI.MassFlowRate m_flow + "Mass flow rate"; + +equation + // + // Assertions + // + assert(dynamicPressureLoss or geodeticPressureLoss or + frictionPressureLoss or fittingPressureLosss, + "At least one option (i.e., dynamic pressure loss, geodetic pressure " + + "loss, friction pressure loss, or fitting pressure loss) must be taken " + + "into account when calculating the pressure loss!", + level=AssertionLevel.error); + + if not dpFromMFlow then + assert(not dynamicPressureLoss and not geodeticPressureLoss and + (frictionPressureLoss or fittingPressureLosss), + "Mass flow rate can only be calculated from the static pressure loss " + + "if just friction- or fitting-caused pressure losses are considered!", + level=AssertionLevel.error); + end if; + + // + // Connectors + // + connect(p_a_internal, p_a); + connect(T_a_internal, T_a); + connect(rho_a_internal, rho_a); + connect(eta_a_internal, eta_a); + + connect(p_b_ad_internal, p_b_ad); + connect(T_b_ad_internal, T_b_ad); + connect(rho_b_ad_internal, rho_b_ad); + connect(eta_b_ad_internal, eta_b_ad); + + if not instreamingPropertiesByInput then + p_a_internal = p_ref + "Needed for connecting to conditional connector: Set dummy value as not + needed in this case"; + T_a_internal = T_ref + "Needed for connecting to conditional connector: Set dummy value as not + needed in this case"; + rho_a_internal = rho_ref + "Needed for connecting to conditional connector: Set dummy value as not + needed in this case"; + eta_a_internal = eta_ref + "Needed for connecting to conditional connector: Set dummy value as not + needed in this case"; + + p_b_ad_internal = p_ref + "Needed for connecting to conditional connector: Set dummy value as not + needed in this case"; + T_b_ad_internal = T_ref + "Needed for connecting to conditional connector: Set dummy value as not + needed in this case"; + rho_b_ad_internal = rho_ref + "Needed for connecting to conditional connector: Set dummy value as not + needed in this case"; + eta_b_ad_internal = eta_ref + "Needed for connecting to conditional connector: Set dummy value as not + needed in this case"; + end if; + + // + // Momentum balance + // + dp = port_a.p - port_b.p + "Pressure difference between port a and b"; + dp = pressureLossModel.dp_static + "Pressure loss"; + + // + // Mass balance + // + 0 = port_a.m_flow + port_b.m_flow + "Steady-state mass balance"; + port_a.m_flow = m_flow + "Mass flow rate at port a"; + + port_a.Xi_outflow = inStream(port_b.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + port_b.Xi_outflow = inStream(port_a.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + + // + // Energy balance + // + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + port_b.h_outflow = inStream(port_a.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all resistors. It defines fundamental +parameters and variables required by all resistors. Models that inherit properties +from this partial model have to redeclare the fluid ports. Moreover, fluid properties +at port a and b must be calculated for both the design and reverse the design flow +direction. In this context, appropriate fluid property models are required. Furthermore, +the geometry record and pressure loss model may be redeclared and constrained. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Pressure <i>fluidProperties_a.p</i> at port a for design flow direction + (i.e., a->b). + </li> + <li> + Temperature <i>fluidProperties_a.T</i> at port a for design flow direction + (i.e., a->b). + </li> + <li> + Density <i>fluidProperties_a.rho</i> at port a for design flow direction + (i.e., a->b). + </li> + <li> + Dynamic viscosity <i>fluidProperties_a.eta</i> at port a for design flow + direction (i.e., a->b). + </li> + <br/> + <li> + Pressure <i>fluidProperties_b.p</i> at port b for design flow direction + (i.e., a->b). + </li> + <li> + Temperature <i>fluidProperties_b.T</i> at port b for design flow direction + (i.e., a->b). + </li> + <li> + Density <i>fluidProperties_b.rho</i> at port b for design flow direction + (i.e., a->b). + </li> + <li> + Dynamic viscosity <i>fluidProperties_b.eta</i> at port b for design flow + direction (i.e., a->b). + </li> + <br/> + <li> + Pressure <i>fluidProperties_a_ad.p</i> at port a for reverse design flow + direction (i.e., b->a). + </li> + <li> + Temperature <i>fluidProperties_a_ad.T</i> at port a for reverse design flow + direction (i.e., b->a). + </li> + <li> + Density <i>fluidProperties_a_ad.rho</i> at port a for reverse design flow + direction (i.e., b->a). + </li> + <li> + Dynamic viscosity <i>fluidProperties_a_ad.eta</i> at port a for reverse design + flow direction (i.e., b->a). + </li> + <br/> + <li> + Pressure <i>fluidProperties_b_ad.p</i> at port b for reverse design flow + direction (i.e., b->a). + </li> + <li> + Temperature <i>fluidProperties_b_ad.T</i> at port b for reverse design flow + direction (i.e., b->a). + </li> + <li> + Density <i>fluidProperties_b_ad.rho</i> at port b for reverse design flow + direction (i.e., b->a). + </li> + <li> + Dynamic viscosity <i>fluidProperties_b_ad.eta</i> at port b for reverse design + flow direction (i.e., b->a). + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Adaptations due to restructering the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Polygon( + points={{-80,50},{-80,-50},{-50,-50},{-50,-50},{50,-50},{50,-50},{80,-50}, + {80,50},{-80,50}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Line( + points={{-60,-20},{-60,-20},{-60,20},{60,-20},{60,20}}, + color={0,0,0}, + thickness=1), + Text( + extent={{-60,40},{60,20}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid, + textString="ṁ = f(Δp, ...)"), + Line( + points={{-60,-30},{60,-30}}, + color={0,0,0}, + thickness=1, + arrow={Arrow.Open,Arrow.Open})})); +end PartialResistance; diff --git a/SorpLib/Components/Fittings/BaseClasses/PartialTJunction.mo b/SorpLib/Components/Fittings/BaseClasses/PartialTJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..3c29c9d4b88d133abb0d0ea522ec2e94a8d3abff --- /dev/null +++ b/SorpLib/Components/Fittings/BaseClasses/PartialTJunction.mo @@ -0,0 +1,408 @@ +within SorpLib.Components.Fittings.BaseClasses; +partial model PartialTJunction + "Base model for all T-junction elements" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding geometry + // + parameter Modelica.Units.SI.Volume V = 5e-5 + "Fluid volume of the T-junction" + annotation (Dialog(tab = "General", group = "Geometry")); + + // + // Definition of parameters regarding calculation setup + // + parameter SorpLib.Choices.IndependentVariablesVolume independentStateVariables= + SorpLib.Choices.IndependentVariablesVolume.phX + "Independent state variables" + annotation (Dialog(tab="General", group="Calculation Setup"), + Evaluate=true, + HideResult = true); + parameter Boolean pressureNoStateVariable = true + " = true, if pressure is not a state variable and is not needed to calculate + fluid properties like density (e.g., incompressible fluid)" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Boolean neglectTermVp = false + " = true, if term p * v is neglected for the specific internal energy (i.e., + u = h)" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition or initialisation parameters + // + parameter Modelica.Units.SI.Pressure p_initial = 1e5 + "Initial value of pressure" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + parameter Modelica.Units.SI.Temperature T_initial = 298.15 + "Initial value of temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=(independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX))); + parameter Modelica.Units.SI.SpecificEnthalpy h_initial = 0 + "Initial value of specific enthalpy" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=(independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX))); + parameter Modelica.Units.SI.MassFraction[no_components] X_i_initial= + fill(1/no_components, no_components) + "Initial values of mass fractions" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=no_components>1)); + + parameter Modelica.Units.SI.MassFlowRate m_flow_start = 1e-4 + "Start value for mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter SorpLib.Choices.BalanceEquations type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial + "Handling of the overall mass balance and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Choices.BalanceEquations type_independentMassBalances= + type_overallMassBalance + "Handling of independent mass balances and corresponding initialisations" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations", + enable=no_components>1), + Evaluate=true, + HideResult=true); + parameter SorpLib.Choices.BalanceEquations type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial + "Handling of the energy balance and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult = true); + + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=m_flow_start)) + "Fluid port a" + annotation (Placement(transformation(extent={{-10,-88},{10,-68}}), + iconTransformation(extent={{-10,-88},{10,-68}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-0.5*m_flow_start)) + "Fluid port b" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}), + iconTransformation(extent={{-90,-10},{-70,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_c + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-0.5*m_flow_start)) + "Fluid port c" + annotation (Placement(transformation(extent={{70,-10},{90,10}}), + iconTransformation(extent={{70,-10},{90,10}})), + choicesAllMatching=true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p( + start=p_initial, + stateSelect= if not pressureNoStateVariable then StateSelect.prefer + else StateSelect.avoid) + "Pressure"; + Modelica.Units.SI.Temperature T( + start=T_initial, + stateSelect= if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then StateSelect.prefer + else StateSelect.avoid) + "Temperature"; + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + Modelica.Units.SI.Density rho + "Density"; + Modelica.Units.SI.MassFraction[no_components] X_i( + start=X_i_initial, + each stateSelect=if no_components > 1 then StateSelect.prefer + else StateSelect.avoid) + "Mass fractions"; + + Modelica.Units.SI.SpecificEnthalpy h( + start=h_initial, + stateSelect= if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX then StateSelect.prefer + else StateSelect.avoid) + "Specific enthalpy"; + Modelica.Units.SI.SpecificEnthalpy[no_components] h_i + "Specific enthalpy of individual components"; + Modelica.Units.SI.SpecificInternalEnergy u + "Specific internal energy"; + + Modelica.Units.SI.Mass m + "Mass"; + Modelica.Units.SI.Mass[no_components] m_i + "Mass of individual components"; + Modelica.Units.SI.MassFlowRate dm_dtau + "Derivative of mass w.r.t. time"; + Modelica.Units.SI.MassFlowRate[no_components] dm_i_dtau + "Derivative of individual components' masses w.r.t. time"; + Modelica.Units.SI.MassFlowRate mc_flow + "Sum of all convective mass flow rates across boundaries"; + Modelica.Units.SI.MassFlowRate[no_components] mc_i_flow + "Sum of all individual components' convective mass flow rates across + boundaries"; + + Modelica.Units.SI.InternalEnergy U + "Internal energy"; + Real dU_dtau(final unit="W") + "Derivative of internal energy w.r.t. time"; + Modelica.Units.SI.EnthalpyFlowRate Hb_flow + "Sum of all enthalpy flow rates across boundaries"; + +initial equation + if not pressureNoStateVariable and type_overallMassBalance == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + p = p_initial + "Fixed initial value"; + + elseif not pressureNoStateVariable and type_overallMassBalance == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + der(p) = 0 + "Steady-state initialisation of overall mass balance"; + + end if; + + if type_independentMassBalances == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + X_i = X_i_initial + "Fixed initial values"; + + elseif type_independentMassBalances == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + der(X_i) = zeros(no_components) + "Steady-state initialisation of independent mass balances"; + + end if; + + if type_energyBalance == + SorpLib.Choices.BalanceEquations.TransientFixedInitial then + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + T = T_initial + "Fixed initial value"; + + else + h = h_initial + "Fixed initial value"; + + end if; + + elseif type_energyBalance == + SorpLib.Choices.BalanceEquations.TransientSteadyStateInitial then + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + der(T) = 0 + "Steady-state initial value"; + + else + der(h) = 0 + "Steady-state initial value"; + + end if; + end if; + +equation + // + // Property calculation + // + v = 1 / rho + "Specific volume"; + + u = if neglectTermVp then h else h - p * v + "Specific internal energy"; + + // + // Momentum balance + // + port_a.p = p + "Total pressure at the port (i.e., homogenous volume)"; + port_b.p = p + "Total pressure at the port (i.e., homogenous volume)"; + port_c.p = p + "Total pressure at the port (i.e., homogenous volume)"; + + // + // Mass balance + // + m = V / v + "Mass"; + m_i = m .* X_i + "Mass of individual components"; + + dm_dtau = mc_flow + "Overall mass balance"; + dm_i_dtau = mc_i_flow + "Individual components' mass balances"; + + if type_independentMassBalances== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_i_dtau = zeros(no_components) + "Steady-state independent mass balances"; + + else + dm_i_dtau = X_i .* dm_dtau .+ m .* der(X_i) + "Transient independent mass balances"; + + end if; + + mc_flow = port_a.m_flow + port_b.m_flow + port_c.m_flow + "Sum of all convective mass flow rates across boundaries"; + + if avoid_events then + for ind_comp in 1:no_components loop + if ind_comp <> no_components then + mc_i_flow[ind_comp] = + port_a.m_flow * noEvent(actualStream(port_a.Xi_outflow[ind_comp])) + + port_b.m_flow * noEvent(actualStream(port_b.Xi_outflow[ind_comp])) + + port_c.m_flow * noEvent(actualStream(port_c.Xi_outflow[ind_comp])) + "Sum of all convective mass flow rates of component ind_comp across + boundaries"; + + else + mc_i_flow[ind_comp] = mc_flow - sum(mc_i_flow[1:no_components-1]) + "Sum of all convective mass flow rates of last component across + boundaries"; + + end if; + end for; + + else + for ind_comp in 1:no_components loop + if ind_comp <> no_components then + mc_i_flow[ind_comp] = + port_a.m_flow * actualStream(port_a.Xi_outflow[ind_comp]) + + port_b.m_flow * actualStream(port_b.Xi_outflow[ind_comp]) + + port_c.m_flow * actualStream(port_c.Xi_outflow[ind_comp]) + "Sum of all convective mass flow rates of component ind_comp across + boundaries"; + + else + mc_i_flow[ind_comp] = mc_flow - sum(mc_i_flow[1:no_components-1]) + "Sum of all convective mass flow rates of last component across + boundaries"; + + end if; + end for; + end if; + + port_a.Xi_outflow = X_i[1:no_components-1] + "Independent mass fractions leaving the port (i.e., homogenous volume)"; + port_b.Xi_outflow = X_i[1:no_components-1] + "Independent mass fractions leaving the port (i.e., homogenous volume)"; + port_c.Xi_outflow = X_i[1:no_components-1] + "Independent mass fractions leaving the port (i.e., homogenous volume)"; + + // + // Energy balance + // + U = m * u + "Internal energy"; + + dU_dtau = Hb_flow + "Energy balane"; + + if avoid_events then + Hb_flow = + port_a.m_flow * noEvent(actualStream(port_a.h_outflow)) + + port_b.m_flow * noEvent(actualStream(port_b.h_outflow)) + + port_c.m_flow * noEvent(actualStream(port_c.h_outflow)) + "Sum of all enthalpy flow rates across boundaries"; + + else + Hb_flow = + port_a.m_flow * actualStream(port_a.h_outflow) + + port_b.m_flow * actualStream(port_b.h_outflow) + + port_c.m_flow * actualStream(port_c.h_outflow) + "Sum of all enthalpy flow rates across boundaries"; + + end if; + + port_a.h_outflow = h + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + port_b.h_outflow = h + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + port_c.h_outflow = h + "Specific enthalpy leaving the port (i.e., homogenous volume)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all T-junction elements. It defines +fundamental parameters and variables required by all T-junction elements. Models +that inherit properties from this partial model have to redeclare the fluid ports. +Furthermore, conservation equations must be completed, which may require additional +variables. In this context, appropriate fluid property models are required. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Temperature <i>T</i> or specific enthalpy <i>h</i>, depending on the independent + state variables. + </li> + <li> + Density <i>ρ</i>. + </li> + <li> + Specific enthalpies of all components <i>h<sub>i</sub></i>. + </li> + <br/> + <li> + Partial derivative of the overall mass w.r.t. time <i>dm_dtau</i>. + </li> + <li> + Partial derivative of the internal energy w.r.t. time <i>dU_dtau</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>"), Icon(graphics={Polygon( + points={{-80,50},{-80,-50},{-50,-50},{-50,-80},{50,-80},{50,-50},{80,-50}, + {80,50},{-80,50}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid)})); +end PartialTJunction; diff --git a/SorpLib/Components/Fittings/BaseClasses/PartialTubeInsidePressureLoss.mo b/SorpLib/Components/Fittings/BaseClasses/PartialTubeInsidePressureLoss.mo new file mode 100644 index 0000000000000000000000000000000000000000..fce5b44a6f937c168b77aa0eb53c85995e3ece65 --- /dev/null +++ b/SorpLib/Components/Fittings/BaseClasses/PartialTubeInsidePressureLoss.mo @@ -0,0 +1,45 @@ +within SorpLib.Components.Fittings.BaseClasses; +partial model PartialTubeInsidePressureLoss + "Base model for all tube-inside pressure loss models" + extends SorpLib.Components.Fittings.BaseClasses.PartialPressureLoss( + final psi = 1, + redeclare replaceable parameter SorpLib.Components.Fittings.Records.GeometryTube geometry + constrainedby SorpLib.Components.Fittings.Records.GeometryTube); + +equation + // + // Calculate the hydraulic mass flow rate + // + m_flow_hyd = m_flow / geometry.no_hydraulicParallelFlows + "Hydraulic mass flow rate"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all pressure loss models applied in tubes. +It defines fundamental parameters and variables required by all pressure loss models. +Models that inherit properties from this partial model have to complete the friction- +based pressure loss correlation. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Friction factor <i>lambda_mean_dd</i> for design flow direction (i.e., a->b). + </li> + <li> + Friction factor <i>lambda_mean_rdd</i> for reverse design flow direction (i.e., + a->b). + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PartialTubeInsidePressureLoss; diff --git a/SorpLib/Components/Fittings/BaseClasses/package.mo b/SorpLib/Components/Fittings/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9babbcde82fb90b6cf0efb4debe34686a7a4c500 --- /dev/null +++ b/SorpLib/Components/Fittings/BaseClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Fittings; +package BaseClasses "Base models and functions for all fittings" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial fitting models and functions, containing fundamental +definitions for fittings. The content of this package is only of interest when +adding new fittings to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Components/Fittings/BaseClasses/package.order b/SorpLib/Components/Fittings/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..dd99e0e2b053e7c34281ee124ea0c444adc4a47d --- /dev/null +++ b/SorpLib/Components/Fittings/BaseClasses/package.order @@ -0,0 +1,7 @@ +PartialInertiaInducer +PartialMultiPort +PartialResistance +PartialTJunction +PartialPressureLoss +PartialTubeInsidePressureLoss +PartialOpenAdsorberPressureLoss diff --git a/SorpLib/Components/Fittings/InertiaInducers/GasInertiaInducer.mo b/SorpLib/Components/Fittings/InertiaInducers/GasInertiaInducer.mo new file mode 100644 index 0000000000000000000000000000000000000000..08a494add6d2e031ec67447a20515b34dc09df30 --- /dev/null +++ b/SorpLib/Components/Fittings/InertiaInducers/GasInertiaInducer.mo @@ -0,0 +1,66 @@ +within SorpLib.Components.Fittings.InertiaInducers; +model GasInertiaInducer "Gas inertia inducer" + extends SorpLib.Components.Fittings.BaseClasses.PartialInertiaInducer( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The gas inertia inducer describes the change of the gas velocity due to its +inertia. Thus, sudden changes in the velocity (i.e., mass flow rate) caused by, +for example, a pressure drop can be puffered, which increases the numerical +stability. +</p> +<pre> + dm_flow/dτ = Δp * Ψ; +</pre> +<p> +Herein, the derivative of the mass flow rate <i>m_flow</i> w.r.t. time <i>τ</i> +is calculated from the pressure difference <i>Δp</i> and momentum factor +<i>Ψ</i>, which directly follows from a simplified momentum balance. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks to break algebraic loops. +</p> + +<h4>Dynamics</h4> +<p> +The model has the mass flow rate <i>m_flow</i> as dynamic state. +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end GasInertiaInducer; diff --git a/SorpLib/Components/Fittings/InertiaInducers/LiquidInertiaInducer.mo b/SorpLib/Components/Fittings/InertiaInducers/LiquidInertiaInducer.mo new file mode 100644 index 0000000000000000000000000000000000000000..491f60f8f1b6062574f6cfa1e0bd32fa7737147d --- /dev/null +++ b/SorpLib/Components/Fittings/InertiaInducers/LiquidInertiaInducer.mo @@ -0,0 +1,65 @@ +within SorpLib.Components.Fittings.InertiaInducers; +model LiquidInertiaInducer "Liquid inertia inducer" + extends SorpLib.Components.Fittings.BaseClasses.PartialInertiaInducer( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The liquid inertia inducer describes the change of the liquid velocity due to its +inertia. Thus, sudden changes in the velocity (i.e., mass flow rate) caused by, +for example, a pressure drop can be puffered, which increases the numerical +stability. +</p> +<pre> + dm_flow/dτ = Δp * Ψ; +</pre> +<p> +Herein, the derivative of the mass flow rate <i>m_flow</i> w.r.t. time <i>τ</i> +is calculated from the pressure difference <i>Δp</i> and momentum factor +<i>Ψ</i>, which directly follows from a simplified momentum balance. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks to break algebraic loops. +</p> + +<h4>Dynamics</h4> +<p> +The model has the mass flow rate <i>m_flow</i> as dynamic state. +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end LiquidInertiaInducer; diff --git a/SorpLib/Components/Fittings/InertiaInducers/Tester/Test_GasInertiaInducer.mo b/SorpLib/Components/Fittings/InertiaInducers/Tester/Test_GasInertiaInducer.mo new file mode 100644 index 0000000000000000000000000000000000000000..9fdf87c0e4ac60cb4e85415175ffb4e174f79b8f --- /dev/null +++ b/SorpLib/Components/Fittings/InertiaInducers/Tester/Test_GasInertiaInducer.mo @@ -0,0 +1,77 @@ +within SorpLib.Components.Fittings.InertiaInducers.Tester; +model Test_GasInertiaInducer "Tester for the gas inertia inducer" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar"), + use_mFlowInput=true, + T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 100000, + T_fixed=303.15) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.InertiaInducers.GasInertiaInducer inertiaInducer( + f_momentum=1e-5) "Inertia model" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow( + amplitude=2, + f=1/250, + offset=0) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, inertiaInducer.port_a) annotation (Line( + points={{-60,0},{-6,0}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, inertiaInducer.port_b) annotation (Line( + points={{60,0},{6,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_mFlow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{-70, + 0},{-70,2},{-61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the gas inertia model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasInertiaInducer; diff --git a/SorpLib/Components/Fittings/InertiaInducers/Tester/Test_LiquidInertiaInducer.mo b/SorpLib/Components/Fittings/InertiaInducers/Tester/Test_LiquidInertiaInducer.mo new file mode 100644 index 0000000000000000000000000000000000000000..8970bc63ca710950f52a20878855e52e45c38929 --- /dev/null +++ b/SorpLib/Components/Fittings/InertiaInducers/Tester/Test_LiquidInertiaInducer.mo @@ -0,0 +1,78 @@ +within SorpLib.Components.Fittings.InertiaInducers.Tester; +model Test_LiquidInertiaInducer + "Tester for the liquid inertia inducer" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar"), + use_mFlowInput=true, + T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 100000, + T_fixed=303.15) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.InertiaInducers.LiquidInertiaInducer inertiaInducer( + f_momentum=1e-5) "Inertia model" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow( + amplitude=2, + f=1/250, + offset=0) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, inertiaInducer.port_a) annotation (Line( + points={{-60,0},{-6,0}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, inertiaInducer.port_b) annotation (Line( + points={{60,0},{6,0}}, + color={28,108,200}, + thickness=1)); + + connect(input_mFlow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{-70, + 0},{-70,2},{-61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the liquid inertia model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_LiquidInertiaInducer; diff --git a/SorpLib/Components/Fittings/InertiaInducers/Tester/Test_VLEInertiaInducer.mo b/SorpLib/Components/Fittings/InertiaInducers/Tester/Test_VLEInertiaInducer.mo new file mode 100644 index 0000000000000000000000000000000000000000..f292bb99c86672e7cfe4805fe03b4a28409a495e --- /dev/null +++ b/SorpLib/Components/Fittings/InertiaInducers/Tester/Test_VLEInertiaInducer.mo @@ -0,0 +1,77 @@ +within SorpLib.Components.Fittings.InertiaInducers.Tester; +model Test_VLEInertiaInducer "Tester for the VLE inertia inducer" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar"), + use_mFlowInput=true, + T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 100000, + T_fixed=303.15) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.InertiaInducers.VLEInertiaInducer inertiaInducer( + f_momentum=1e-5) "Inertia model" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow( + amplitude=2, + f=1/250, + offset=0) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, inertiaInducer.port_a) annotation (Line( + points={{-60,0},{-6,0}}, + color={0,140,72}, + thickness=1)); + connect(fs_b.port, inertiaInducer.port_b) annotation (Line( + points={{60,0},{6,0}}, + color={0,140,72}, + thickness=1)); + + connect(input_mFlow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{-70, + 0},{-70,2},{-61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the inertia model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end Test_VLEInertiaInducer; diff --git a/SorpLib/Components/Fittings/InertiaInducers/Tester/package.mo b/SorpLib/Components/Fittings/InertiaInducers/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..39bc2d69dbd241fff7f8043d83087226fe8fe3c6 --- /dev/null +++ b/SorpLib/Components/Fittings/InertiaInducers/Tester/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Fittings.InertiaInducers; +package Tester "Models to test and varify multi port models" + extends Modelica.Icons.ExamplesPackage; + + + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented inertia inducers. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Fittings/InertiaInducers/Tester/package.order b/SorpLib/Components/Fittings/InertiaInducers/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..3410f8a2047733b2cee81a4719e7ce4a329ac19b --- /dev/null +++ b/SorpLib/Components/Fittings/InertiaInducers/Tester/package.order @@ -0,0 +1,3 @@ +Test_LiquidInertiaInducer +Test_GasInertiaInducer +Test_VLEInertiaInducer diff --git a/SorpLib/Components/Fittings/InertiaInducers/VLEInertiaInducer.mo b/SorpLib/Components/Fittings/InertiaInducers/VLEInertiaInducer.mo new file mode 100644 index 0000000000000000000000000000000000000000..d0e369abb5cca51d369c35fbe8f941a43c64f65a --- /dev/null +++ b/SorpLib/Components/Fittings/InertiaInducers/VLEInertiaInducer.mo @@ -0,0 +1,66 @@ +within SorpLib.Components.Fittings.InertiaInducers; +model VLEInertiaInducer "VLE inertia inducer" + extends SorpLib.Components.Fittings.BaseClasses.PartialInertiaInducer( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The VLE inertia inducer describes the change of the VLE velocity due to its +inertia. Thus, sudden changes in the velocity (i.e., mass flow rate) caused by, +for example, a pressure drop can be puffered, which increases the numerical +stability. +</p> +<pre> + dm_flow/dτ = Δp * Ψ; +</pre> +<p> +Herein, the derivative of the mass flow rate <i>m_flow</i> w.r.t. time <i>τ</i> +is calculated from the pressure difference <i>Δp</i> and momentum factor +<i>Ψ</i>, which directly follows from a simplified momentum balance. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks to break algebraic loops. +</p> + +<h4>Dynamics</h4> +<p> +The model has the mass flow rate <i>m_flow</i> as dynamic state. +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end VLEInertiaInducer; diff --git a/SorpLib/Components/Fittings/InertiaInducers/package.mo b/SorpLib/Components/Fittings/InertiaInducers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..aa0cbb0f69ad6559ebd1d597cef563ce5b68de6e --- /dev/null +++ b/SorpLib/Components/Fittings/InertiaInducers/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Fittings; +package InertiaInducers "Package containing inertia inducers" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains inertia inducers based on the Modelica Standard library +(MSL). Inertia inducers may be used to describe the acceleration of a fluid +caused by a sudden pressure change, thus also allowing to break algebraic loops. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end InertiaInducers; diff --git a/SorpLib/Components/Fittings/InertiaInducers/package.order b/SorpLib/Components/Fittings/InertiaInducers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c47972da06db8ad4ad3ca15f5b7cf98f365e58ae --- /dev/null +++ b/SorpLib/Components/Fittings/InertiaInducers/package.order @@ -0,0 +1,4 @@ +LiquidInertiaInducer +GasInertiaInducer +VLEInertiaInducer +Tester diff --git a/SorpLib/Components/Fittings/MultiPorts/GasMultiPort.mo b/SorpLib/Components/Fittings/MultiPorts/GasMultiPort.mo new file mode 100644 index 0000000000000000000000000000000000000000..52aafd0e262134d8b9f3ecda533d9e8dc6530153 --- /dev/null +++ b/SorpLib/Components/Fittings/MultiPorts/GasMultiPort.mo @@ -0,0 +1,46 @@ +within SorpLib.Components.Fittings.MultiPorts; +model GasMultiPort + "Gas multi port model (i.e., ideal splitter/junctions)" + extends SorpLib.Components.Fittings.BaseClasses.PartialMultiPort( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out ports_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The gas multi port model s may be used if several connections shall be made to +one port. If the connections were made directly to the port, the calculation of +mixture quantities (i.e., stream variables) would be carried out in the port: +This may lead to large linear systems of equations, which is usually not desired. +In contrast, no mixture quantities are calculated with this model. Instead, the +mixture quantities are calculated in a finite volume model or a comparable +model that must be located before port a. The calculated mixture quantities are +propagated to the other connections (i.e., port b). +<br/><br/> +This models is based on +<a href=\"Modelica://Modelica.Fluid.Fittings.MultiPort\">Modelica.Fluid.Fittings.MultiPort</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 20, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end GasMultiPort; diff --git a/SorpLib/Components/Fittings/MultiPorts/LiquidMultiPort.mo b/SorpLib/Components/Fittings/MultiPorts/LiquidMultiPort.mo new file mode 100644 index 0000000000000000000000000000000000000000..a25ff92d7d9c2615f8e6d0c71263a918a413353b --- /dev/null +++ b/SorpLib/Components/Fittings/MultiPorts/LiquidMultiPort.mo @@ -0,0 +1,45 @@ +within SorpLib.Components.Fittings.MultiPorts; +model LiquidMultiPort + "Liquid multi port model (i.e., ideal splitter/junctions)" + extends SorpLib.Components.Fittings.BaseClasses.PartialMultiPort( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out ports_b, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The liquid multi port model s may be used if several connections shall be made to +one port. If the connections were made directly to the port, the calculation of +mixture quantities (i.e., stream variables) would be carried out in the port: +This may lead to large linear systems of equations, which is usually not desired. +In contrast, no mixture quantities are calculated with this model. Instead, the +mixture quantities are calculated in a finite volume model or a comparable +model that must be located before port a. The calculated mixture quantities are +propagated to the other connections (i.e., port b). +<br/><br/> +This models is based on +<a href=\"Modelica://Modelica.Fluid.Fittings.MultiPort\">Modelica.Fluid.Fittings.MultiPort</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 20, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end LiquidMultiPort; diff --git a/SorpLib/Components/Fittings/MultiPorts/Tester/Test_GasMultiPort.mo b/SorpLib/Components/Fittings/MultiPorts/Tester/Test_GasMultiPort.mo new file mode 100644 index 0000000000000000000000000000000000000000..bab394c31b7e81c874ff2eac708a7dbcb2063b27 --- /dev/null +++ b/SorpLib/Components/Fittings/MultiPorts/Tester/Test_GasMultiPort.mo @@ -0,0 +1,84 @@ +within SorpLib.Components.Fittings.MultiPorts.Tester; +model Test_GasMultiPort "Tester for the gas multi port model" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 100000, + T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource[5] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + each use_mFlowInput=true, + h_fixed={100e3,200e3,300e3,400e3,500e3}) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.MultiPorts.GasMultiPort multiPort(no_ports_b=5) + "Multi port model to split connections at port a" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow( + amplitude=1, + f=1/250, + offset=1) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, multiPort.port_a) annotation (Line( + points={{-60,0},{-6,0}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, multiPort.ports_b) annotation (Line( + points={{60,0},{6,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_mFlow.y, fs_b[1].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[2].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[3].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[4].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[5].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the gas multi port model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasMultiPort; diff --git a/SorpLib/Components/Fittings/MultiPorts/Tester/Test_LiquidMultiPort.mo b/SorpLib/Components/Fittings/MultiPorts/Tester/Test_LiquidMultiPort.mo new file mode 100644 index 0000000000000000000000000000000000000000..b500bfde5b923924c6db0783bb9084fe86d2cb30 --- /dev/null +++ b/SorpLib/Components/Fittings/MultiPorts/Tester/Test_LiquidMultiPort.mo @@ -0,0 +1,84 @@ +within SorpLib.Components.Fittings.MultiPorts.Tester; +model Test_LiquidMultiPort "Tester for the liquid multi port model" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 100000, + T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource[5] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + each use_mFlowInput=true, + h_fixed={100e3,200e3,300e3,400e3,500e3}) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.MultiPorts.LiquidMultiPort multiPort(no_ports_b=5) + "Multi port model to split connections at port a" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow( + amplitude=1, + f=1/250, + offset=1) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, multiPort.port_a) annotation (Line( + points={{-60,0},{-6,0}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, multiPort.ports_b) annotation (Line( + points={{60,0},{6,0}}, + color={28,108,200}, + thickness=1)); + + connect(input_mFlow.y, fs_b[1].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[2].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[3].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[4].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[5].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the liquid multi port model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_LiquidMultiPort; diff --git a/SorpLib/Components/Fittings/MultiPorts/Tester/Test_VLEMultiPort.mo b/SorpLib/Components/Fittings/MultiPorts/Tester/Test_VLEMultiPort.mo new file mode 100644 index 0000000000000000000000000000000000000000..a34b97331edaf0477c54068323959c5d0e334243 --- /dev/null +++ b/SorpLib/Components/Fittings/MultiPorts/Tester/Test_VLEMultiPort.mo @@ -0,0 +1,88 @@ +within SorpLib.Components.Fittings.MultiPorts.Tester; +model Test_VLEMultiPort "Tester for the VLE multi port model" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 100000, + T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource[5] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + each use_mFlowInput=true, + h_fixed={100e3,200e3,300e3,400e3,500e3}) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.MultiPorts.VLEMultiPort multiPort(no_ports_b=5) + "Multi port model to split connections at port a" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow( + amplitude=1, + f=1/250, + offset=1) + "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, multiPort.port_a) annotation (Line( + points={{-60,0},{-6,0}}, + color={0,140,72}, + thickness=1)); + connect(fs_b.port, multiPort.ports_b) annotation (Line( + points={{60,0},{6,0}}, + color={0,140,72}, + thickness=1)); + + connect(input_mFlow.y, fs_b[1].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[2].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[3].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[4].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + connect(input_mFlow.y, fs_b[5].m_flow_input) + annotation (Line(points={{79,0},{70,0},{70,2},{61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the VLE multi port model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 20, 2023, by Mirko Engelpracht:<br/> + Minor revisions (documentation). + </li> + <li> + January 19, 2021, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end Test_VLEMultiPort; diff --git a/SorpLib/Components/Fittings/MultiPorts/Tester/package.mo b/SorpLib/Components/Fittings/MultiPorts/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..8f45612f5328fcb8217adc3d4f5aba3e822a4bc8 --- /dev/null +++ b/SorpLib/Components/Fittings/MultiPorts/Tester/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Components.Fittings.MultiPorts; +package Tester "Models to test and varify multi port models" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented multi port models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Fittings/MultiPorts/Tester/package.order b/SorpLib/Components/Fittings/MultiPorts/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..0c82979a85781f5021e3f7d8770cd4e4d904f8a2 --- /dev/null +++ b/SorpLib/Components/Fittings/MultiPorts/Tester/package.order @@ -0,0 +1,3 @@ +Test_LiquidMultiPort +Test_GasMultiPort +Test_VLEMultiPort diff --git a/SorpLib/Components/Fittings/MultiPorts/VLEMultiPort.mo b/SorpLib/Components/Fittings/MultiPorts/VLEMultiPort.mo new file mode 100644 index 0000000000000000000000000000000000000000..247da7cd67c6bc095ea763f0b77a724e253fffe5 --- /dev/null +++ b/SorpLib/Components/Fittings/MultiPorts/VLEMultiPort.mo @@ -0,0 +1,50 @@ +within SorpLib.Components.Fittings.MultiPorts; +model VLEMultiPort + "VLE multi port model (i.e., ideal splitter/junctions)" + extends SorpLib.Components.Fittings.BaseClasses.PartialMultiPort( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out ports_b, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The VLE multi port model s may be used if several connections shall be made to +one port. If the connections were made directly to the port, the calculation of +mixture quantities (i.e., stream variables) would be carried out in the port: +This may lead to large linear systems of equations, which is usually not desired. +In contrast, no mixture quantities are calculated with this model. Instead, the +mixture quantities are calculated in a finite volume model or a comparable +model that must be located before port a. The calculated mixture quantities are +propagated to the other connections (i.e., port b). +<br/><br/> +This models is based on +<a href=\"Modelica://Modelica.Fluid.Fittings.MultiPort\">Modelica.Fluid.Fittings.MultiPort</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 20, 2023, by Mirko Engelpracht:<br/> + Minor revisions (documentation). + </li> + <li> + January 19, 2021, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end VLEMultiPort; diff --git a/SorpLib/Components/Fittings/MultiPorts/package.mo b/SorpLib/Components/Fittings/MultiPorts/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2b195f616824a265e38299914ba88ce5fe131709 --- /dev/null +++ b/SorpLib/Components/Fittings/MultiPorts/package.mo @@ -0,0 +1,25 @@ +within SorpLib.Components.Fittings; +package MultiPorts "Package containing multi port models for efficient connection of multiple ports to one port" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains multi port models based on the Modelica Standard library +(MSL). These models may be used if several connections shall be made to one port. +If the connections were made directly to the port, the calculation of mixture +quantities (i.e., stream variables) would be carried out in the port: This may +lead to large linear systems of equations, which is usually not desired. In +contrast, no mixture quantities are calculated with this model. Instead, the +mixture quantities are calculated in a finite volume model or a comparable model +that must be located before port a. The calculated mixture quantities are +propagated to the other connections (i.e., port b). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end MultiPorts; diff --git a/SorpLib/Components/Fittings/MultiPorts/package.order b/SorpLib/Components/Fittings/MultiPorts/package.order new file mode 100644 index 0000000000000000000000000000000000000000..8ec22eea74d9b216908b0c6419a717aab070e4ab --- /dev/null +++ b/SorpLib/Components/Fittings/MultiPorts/package.order @@ -0,0 +1,4 @@ +LiquidMultiPort +GasMultiPort +VLEMultiPort +Tester diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/ConstantLambda.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/ConstantLambda.mo new file mode 100644 index 0000000000000000000000000000000000000000..8c4e6515ca0486c4b5977119f95d784eec672ca9 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/ConstantLambda.mo @@ -0,0 +1,163 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.OpenAdsorber; +model ConstantLambda + "Pressure loss model with friction contribution according to constant Darcy friction number" + extends SorpLib.Components.Fittings.BaseClasses.PartialOpenAdsorberPressureLoss( + final requireTransportPropreties=false); + + // + // Definition of parameters + // + parameter Real lambda_constant = 0.025 + "Constant Darcy friction number" + annotation (Dialog(tab="General", group="Calculation Setup")); + +equation + lambda_mean_dd = lambda_constant + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = lambda_constant + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'ConstantLambda' pressure loss model calculates the pressure loss of a resistance +for open adsorbers, with the friction-based pressure loss according to a constant Darcy +friction number. The model also includes dynamic, geodetic, and installation-related +pressure losses. The pressure loss is calculated as a function of the mass flow rate, +and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = λ<sub>constant</sub>; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Modifications due to restructering the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ConstantLambda; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/Kast.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/Kast.mo new file mode 100644 index 0000000000000000000000000000000000000000..f3ccbfff6b7e697aee96b5b727df8da1634161ea --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/Kast.mo @@ -0,0 +1,196 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.OpenAdsorber; +model Kast + "Pressure loss model with friction contribution according to Kast" + extends SorpLib.Components.Fittings.BaseClasses.PartialOpenAdsorberPressureLoss( + final requireTransportPropreties=true); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust pressure drop correlation" + annotation (Dialog(tab="General", group="Calculation Setup")); + parameter Real f_particle = 1.8 + "Particle-specific factor (i.e., 1.8 for spherical particles or 2.6 for sharp- + edged particles)" + annotation (Dialog(tab="General", group="Calculation Setup")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Diameter d_hyd_mean_ = d_hyd_mean / + (2/3 * geometry.psi / (1 - geometry.psi) * geometry.d_particle) + "Corrected hydraulic average diameter"; + +equation + lambda_mean_dd = f_correction * d_hyd_mean_ * ( + 64 / max(Re_mean_dd, 1e-12) + f_particle / max(Re_mean_dd, 1e-12) ^ (0.1)) + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = f_correction * d_hyd_mean_ * ( + 64 / max(Re_mean_rdd, 1e-12) + f_particle / max(Re_mean_rdd, 1e-12) ^ (0.1)) + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'Kast' pressure loss model calculates the pressure loss of a resistance for open +adsorbers, with the friction-based pressure loss according to the Blasius correlation. +The model also includes dynamic, geodetic, and installation-related pressure losses. +The pressure loss is calculated as a function of the mass flow rate, and there is +no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = 64 / Re + f<sub>particle</sub> / Re<sup>0.1</sup>; +</pre> +<p> +Herein, <i>Re</i> is the Reynold number and <i>f<sub>particle</sub></i> is a particle- +specifc facotr (i.e., 1.8 for spherical particles or 2.6 for sharp-edged particles). +Note that the average diameter <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +must be corrected to +</p> +<pre> + <SPAN STYLE=\"text-decoration:overline\">d</SPAN> = 2/3 * Ψ / (1 - Ψ) * d<sub>particle</sub>; +</pre> +<p> +with the void fraction <i>Ψ</i> and particle diameter <i>d<sub>particle</sub></i>. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Kast, W. (1998). Adsorption aus der Gasphase: Ingenieurwissenschaftliche Grundlagen und technische Verfahren (in German). VCH Verlagsgesellschaft, Weinheim, Basel, Cambridge, New York. DOI: https://doi.org/10.1002/bbpc.19900940122. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Modifications due to restructering the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Kast; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/LinearLambda.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/LinearLambda.mo new file mode 100644 index 0000000000000000000000000000000000000000..d7dd3c5042251ff627137fd8e97a75600dcad7db --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/LinearLambda.mo @@ -0,0 +1,163 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.OpenAdsorber; +model LinearLambda + "Pressure loss model with friction contribution according to Darcy friction number that is linearly dependent on the mass flow rate" + extends SorpLib.Components.Fittings.BaseClasses.PartialOpenAdsorberPressureLoss( + final requireTransportPropreties=false); + + // + // Definition of parameters + // + parameter Real lambda_linear(final unit="s/kg") = 0.025 + "Darcy friction factor at mass flow rate of 1 kg/s" + annotation (Dialog(tab="General", group="Calculation Setup")); + +equation + lambda_mean_dd = lambda_linear * abs(m_flow_hyd) + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = lambda_linear * abs(m_flow_hyd) + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'LinearLambda' pressure loss model calculates the pressure loss of a resistance +for open adsorbers, with the friction-based pressure loss according to a Darcy friction +number that is linearly dependent on the mass flow rate. The model also includes +dynamic, geodetic, and installation-related pressure losses. The pressure loss is +calculated as a function of the mass flow rate, and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = λ<sub>linear</sub> * ṁ<sub>hyd</sub>; +</pre> +<p> +Herein, <i>λ<sub>linear</sub></i> is the Darcy friction number at a mass +flow rate of 1 kg/s. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end LinearLambda; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/QuadraticLambda.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/QuadraticLambda.mo new file mode 100644 index 0000000000000000000000000000000000000000..d37d3d750a42a52a0d02a6b385685561a69a7678 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/QuadraticLambda.mo @@ -0,0 +1,163 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.OpenAdsorber; +model QuadraticLambda + "Pressure loss model with friction contribution according to Darcy friction number that is quadratically dependent on the mass flow rate" + extends SorpLib.Components.Fittings.BaseClasses.PartialOpenAdsorberPressureLoss( + final requireTransportPropreties=false); + + // + // Definition of parameters + // + parameter Real lambda_quadratic(final unit="s2/kg2") = 0.025 + "Darcy friction factor at mass flow rate of 1 kg/s" + annotation (Dialog(tab="General", group="Calculation Setup")); + +equation + lambda_mean_dd = lambda_quadratic * m_flow_hyd^2 + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = lambda_quadratic * m_flow_hyd^2 + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'QuadraticLambda' pressure loss model calculates the pressure loss of a resistance +for open adsorbers, with the friction-based pressure loss according to a Darcy friction +number that is quadratically dependent on the mass flow rate. The model also includes +dynamic, geodetic, and installation-related pressure losses. The pressure loss is +calculated as a function of the mass flow rate, and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = λ<sub>quadratic</sub> * ṁ<sub>hyd</sub><sup>2</sup>; +</pre> +<p> +Herein, <i>λ<sub>quadratic</sub></i> is the Darcy friction number at a mass +flow rate of 1 kg/s. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end QuadraticLambda; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/ZeroFriction.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/ZeroFriction.mo new file mode 100644 index 0000000000000000000000000000000000000000..47b6f382d159e3d929b2bfc2d0dae8cb877736fc --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/ZeroFriction.mo @@ -0,0 +1,148 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.OpenAdsorber; +model ZeroFriction + "Pressure loss model without friction contribution" + extends SorpLib.Components.Fittings.BaseClasses.PartialOpenAdsorberPressureLoss( + final requireTransportPropreties=false); + +equation + lambda_mean_dd = 0 + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = 0 + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'ZeroFriction' pressure loss model calculates the pressure loss of an resistance +for open adsorbers. The model includes dynamic, geodetic, and installation-related +pressure losses but not friction. The pressure loss is calculated as a function of +the mass flow rate, and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +This model assumes zero friction, so it does not calculate friction-based +pressure losses: +</p> +<pre> + λ = 0; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The 'ZeroFriction' pressure loss model is used within tubes if friction shall +not be included. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Modifications due to restructering the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ZeroFriction; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/package.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..7fe2e52eb7db7486a47e94d08a9087026b6990a8 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/package.mo @@ -0,0 +1,40 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations; +package OpenAdsorber "Pressure loss correlations for fluids flowing through open adsorbers" +extends Modelica.Icons.FunctionsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains pressure loss correlations that can be used within tubes +to calculate friction-based pressure losses: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.ZeroFriction\">ZeroFriction</a>: + No friction is considered. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.ConstantLambda\">ConstantLambda</a>: + Constant Darcy friction number. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.LinearLambda\">LinearLambda</a>: + Darcy friction number that is linearly dependent on the mass flow rate. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.QuadraticLambda\">QuadraticLambda</a>: + Darcy friction number that is quadratically dependent on the mass flow rate. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Kast\">Kast</a>: + Darcy friction number according to Kast for packed beds. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end OpenAdsorber; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/package.order b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/package.order new file mode 100644 index 0000000000000000000000000000000000000000..10f68c9ab0e6d2f01c21241ae156774e931d0fa8 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/OpenAdsorber/package.order @@ -0,0 +1,5 @@ +ZeroFriction +ConstantLambda +LinearLambda +QuadraticLambda +Kast diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/Blasius.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/Blasius.mo new file mode 100644 index 0000000000000000000000000000000000000000..53d76d56e24697c5ae25b43fbeee42bc20d52490 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/Blasius.mo @@ -0,0 +1,213 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside; +model Blasius + "Pressure loss model with friction contribution according to Blasius" + extends SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss( + final requireTransportPropreties=true); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust pressure drop correlation" + annotation (Dialog(tab="General", group="Calculation Setup")); + + parameter Modelica.Units.SI.ReynoldsNumber Re_transition = 100 + "Transition length to change between laminar and turbulent flow regime" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + parameter Integer noDiffTransition = 3 + "Specification how often transition function can be differentiated" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // +protected + Real wf_dd = if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent(Re_mean_dd, 2300, Re_transition, + noDiffTransition) else SorpLib.Numerics.smoothTransition(Re_mean_dd, 2300, + Re_transition, noDiffTransition) + "Weighting factor for the design direction"; + Real wf_rdd = if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent(Re_mean_rdd, 2300, Re_transition, + noDiffTransition) else SorpLib.Numerics.smoothTransition(Re_mean_rdd, 2300, + Re_transition, noDiffTransition) + "Weighting factor for the reverse design direction"; + +equation + lambda_mean_dd = f_correction* ( + wf_dd * 64 / max(Re_mean_dd, 1e-12) + (1-wf_dd) * + 0.3164 * max(Re_mean_dd, 1e-12) ^ (-0.25)) + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = f_correction * + (wf_rdd * 64 / max(Re_mean_rdd, 1e-12) + (1-wf_rdd) * + 0.3164 * max(Re_mean_rdd, 1e-12) ^ (-0.25)) + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'Blasius' pressure loss model calculates the pressure loss of a tube resistance, with +the friction-based pressure loss according to the Blasius correlation. The model also +includes dynamic, geodetic, and installation-related pressure losses. The pressure loss +is calculated as a function of the mass flow rate, and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The laminar Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = 64 / Re <strong>for</strong> Re ≤ 2300; +</pre> +<p> +and the turbulent Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = 0.3164 / Re<sup>0.25</sup> <strong>for</strong> 2300 ≤ Re ≤ 10<sup>5</sup>; +</pre> +<p> +Herein, <i>Re</i> is the Reynold number. Smooth transition is applied using the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition\">SorpLib.Numerics.smoothTransition</a> +to change between laminar and turbulent flow regime. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> + <li> + Smooth tube + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Kast, W., (Revised by Hermann Nirschl), and Gaddis, E.S., and Wirth, KE., and Stichlmair, J. (2010). L1 Pressure Drop in Single Phase Flow. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_70. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Modifications due to restructering the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Blasius; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/Colebrook.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/Colebrook.mo new file mode 100644 index 0000000000000000000000000000000000000000..5d8abaaf39b89a8bc288d89fb1701c2024943823 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/Colebrook.mo @@ -0,0 +1,289 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside; +model Colebrook + "Pressure loss model with friction contribution according to Colebrook" + extends SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss( + final requireTransportPropreties=true); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust pressure drop correlation" + annotation (Dialog(tab="General", group="Calculation Setup")); + + parameter Boolean useExplicitFormulation = true + " = true, if explicit formulation usign the Lambert W function shall be + used; otherwise, use implicit formulation" + annotation (Dialog(tab="Advanced", group="Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useExactLambertWFunction = false + " = true, if exact iterative solution of the Lambert W function shall be + used; otherwise, use closed form approximation" + annotation (Dialog(tab="Advanced", group="Numerics", + enable=useExplicitFormulation), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.ReynoldsNumber Re_transition = 2000 + "Transition length to change between laminar and turbulent flow regime" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + parameter Integer noDiffTransition = 3 + "Specification how often transition function can be differentiated" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // +protected + Real lambda_mean_turb_dd + "Average Darcy friction factor for the design direction"; + Real lambda_mean_turb_rdd + "Average Darcy friction factor for the reverse design direction"; + + Real wf_dd = if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent(Re_mean_dd, 2300, Re_transition, + noDiffTransition) else SorpLib.Numerics.smoothTransition(Re_mean_dd, 2300, + Re_transition, noDiffTransition) + "Weighting factor for the design direction"; + Real wf_rdd = if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent(Re_mean_rdd, 2300, Re_transition, + noDiffTransition) else SorpLib.Numerics.smoothTransition(Re_mean_rdd, 2300, + Re_transition, noDiffTransition) + "Weighting factor for the reverse design direction"; + +equation + // + // Calculate turbulent Darcy friction factor + // + if useExplicitFormulation then + if useExactLambertWFunction then + lambda_mean_turb_dd = 1 / (2 * + Modelica.Fluid.Dissipation.Utilities.Functions.General.LambertWIter( + log(10) * Re_mean_dd / (2 * 2.51) * 10 ^ ((geometry.roughness * Re_mean_dd) / + (2 * 2.51 * 14.8 * d_hyd_mean))) / log(10) - (geometry.roughness * Re_mean_dd) / + (2.51 * 14.8 * d_hyd_mean)) ^ 2 + "Average Darcy friction factor for the design direction"; + lambda_mean_turb_rdd = 1 / (2 * + Modelica.Fluid.Dissipation.Utilities.Functions.General.LambertWIter( + log(10) * Re_mean_rdd / (2 * 2.51) * 10 ^ ((geometry.roughness * Re_mean_rdd) / + (2 * 2.51 * 14.8 * d_hyd_mean))) / log(10) - (geometry.roughness * Re_mean_rdd) / + (2.51 * 14.8 * d_hyd_mean)) ^ 2 + "Average Darcy friction factor for the reverse design direction"; + + else + lambda_mean_turb_dd = 1 / (2 * + Modelica.Fluid.Dissipation.Utilities.Functions.General.LambertW( + log(10) * Re_mean_dd / (2 * 2.51) * 10 ^ ((geometry.roughness * Re_mean_dd) / + (2 * 2.51 * 14.8 * d_hyd_mean))) / log(10) - (geometry.roughness * Re_mean_dd) / + (2.51 * 14.8 * d_hyd_mean)) ^ 2 + "Average Darcy friction factor for the design direction"; + lambda_mean_turb_rdd = 1 / (2 * + Modelica.Fluid.Dissipation.Utilities.Functions.General.LambertW( + log(10) * Re_mean_rdd / (2 * 2.51) * 10 ^ ((geometry.roughness * Re_mean_rdd) / + (2 * 2.51 * 14.8 * d_hyd_mean))) / log(10) - (geometry.roughness * Re_mean_rdd) / + (2.51 * 14.8 * d_hyd_mean)) ^ 2 + "Average Darcy friction factor for the reverse design direction"; + + end if; + + else + 1 / sqrt(max(lambda_mean_turb_dd, 1e-12)) = -2 * Modelica.Math.log10( + 2.51 / (max(Re_mean_dd, 1e-12) * sqrt(max(lambda_mean_turb_dd, 1e-12))) + + geometry.roughness / d_hyd_mean / 3.71) + "Average Darcy friction factor for the design direction"; + 1 / sqrt(max(lambda_mean_turb_rdd, 1e-12)) = -2 * Modelica.Math.log10( + 2.51 / (max(Re_mean_rdd, 1e-12) * sqrt(max(lambda_mean_turb_rdd, 1e-12))) + + geometry.roughness / d_hyd_mean / 3.71) + "Average Darcy friction factor for the reverse design direction"; + + end if; + + // + // Calculate overall Darcy friction factor + // + lambda_mean_dd = f_correction* ( + wf_dd * 64 / max(Re_mean_dd, 1e-12) + (1-wf_dd) * lambda_mean_turb_dd) + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = f_correction* ( + wf_rdd * 64 / max(Re_mean_rdd, 1e-12) + (1-wf_rdd) * lambda_mean_turb_rdd) + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'Colebrook' pressure loss model calculates the pressure loss of a tube resistance, +with the friction-based pressure loss according to the Colebrook correlation. The +model also includes dynamic, geodetic, and installation-related pressure losses. The +pressure loss is calculated as a function of the mass flow rate, and there is no +inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The laminar Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = 64 / Re <strong>for</strong> Re ≤ 2300; +</pre> +<p> +and the turbulent Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + 1 / <strong>sqrt</strong>(λ) = -2 <strong>log</strong>(2.51 / (Re * <strong>sqrt</strong>(λ)) + ε / 3.71) <strong>for</strong> 4000 ≤ Re; +</pre> +<p> +Herein, <i>Re</i> is the Reynold number and <i>ε</i> is the relative +roughness. Smooth transition is applied using the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition\">SorpLib.Numerics.smoothTransition</a> +to change between laminar and turbulent flow regime. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> + <li> + Rough tube + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>useExplicitFormulation</i>: + Defines if explicit formulation of the turbulent Darcy friction factor shall be + used by applying the Lambert W function. + </li> + <li> + <i>useExactLambertWFunction</i>: + Defines if approximation or exact solution (i.e., iteration) of the Lambert W + function shall be used. + </li> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Kast, W., (Revised by Hermann Nirschl), and Gaddis, E.S., and Wirth, KE., and Stichlmair, J. (2010). L1 Pressure Drop in Single Phase Flow. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_70. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Colebrook; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/ConstantLambda.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/ConstantLambda.mo new file mode 100644 index 0000000000000000000000000000000000000000..a278933b7ed51f2efc693e1dad57b20ca34acc06 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/ConstantLambda.mo @@ -0,0 +1,163 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside; +model ConstantLambda + "Pressure loss model with friction contribution according to constant Darcy friction number" + extends SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss( + final requireTransportPropreties=false); + + // + // Definition of parameters + // + parameter Real lambda_constant = 0.025 + "Constant Darcy friction number" + annotation (Dialog(tab="General", group="Calculation Setup")); + +equation + lambda_mean_dd = lambda_constant + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = lambda_constant + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'ConstantLambda' pressure loss model calculates the pressure loss of a tube +resistance, withthe friction-based pressure loss according to a constant Darcy +friction number. The model also includes dynamic, geodetic, and installation-related +pressure losses. The pressure loss is calculated as a function of the mass flow rate, +and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = λ<sub>constant</sub>; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Modifications due to restructering the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ConstantLambda; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/Konakov.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/Konakov.mo new file mode 100644 index 0000000000000000000000000000000000000000..06e10cb8f198af2763f688dc46b6b34b98e993e8 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/Konakov.mo @@ -0,0 +1,213 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside; +model Konakov + "Pressure loss model with friction contribution according to Konakov" + extends SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss( + final requireTransportPropreties=true); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust pressure drop correlation" + annotation (Dialog(tab="General", group="Calculation Setup")); + + parameter Modelica.Units.SI.ReynoldsNumber Re_transition = 100 + "Transition length to change between laminar and turbulent flow regime" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + parameter Integer noDiffTransition = 3 + "Specification how often transition function can be differentiated" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // +protected + Real wf_dd = if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent(Re_mean_dd, 2300, Re_transition, + noDiffTransition) else SorpLib.Numerics.smoothTransition(Re_mean_dd, 2300, + Re_transition, noDiffTransition) + "Weighting factor for the design direction"; + Real wf_rdd = if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent(Re_mean_rdd, 2300, Re_transition, + noDiffTransition) else SorpLib.Numerics.smoothTransition(Re_mean_rdd, 2300, + Re_transition, noDiffTransition) + "Weighting factor for the reverse design direction"; + +equation + lambda_mean_dd = f_correction* ( + wf_dd * 64 / max(Re_mean_dd, 1e-12) + (1-wf_dd) * + 1/(1.8*Modelica.Math.log10(max(Re_mean_dd, 1e-12)) - 1.5)^2) + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = f_correction* ( + wf_rdd * 64 / max(Re_mean_rdd, 1e-12) + (1-wf_rdd) * + 1/(1.8*Modelica.Math.log10(max(Re_mean_rdd, 1e-12)) - 1.5)^2) + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'Konakov' pressure loss model calculates the pressure loss of a tube resistance, with +the friction-based pressure loss according to the Konakov correlation. The model also +includes dynamic, geodetic, and installation-related pressure losses. The pressure loss +is calculated as a function of the mass flow rate, and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The laminar Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = 64 / Re <strong>for</strong> Re ≤ 2300; +</pre> +<p> +and the turbulent Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = 1 / [1.8 * <strong>log</strong>(Re) - 1.5]<sup>2</sup> <strong>for</strong> 2300 ≤ Re ≤ 10<sup>6</sup>; +</pre> +<p> +Herein, <i>Re</i> is the Reynold number. Smooth transition is applied using the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition\">SorpLib.Numerics.smoothTransition</a> +to change between laminar and turbulent flow regime. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> + <li> + Smooth tube + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Kast, W., (Revised by Hermann Nirschl), and Gaddis, E.S., and Wirth, KE., and Stichlmair, J. (2010). L1 Pressure Drop in Single Phase Flow. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_70. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Modifications due to restructering the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Konakov; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/LinearLambda.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/LinearLambda.mo new file mode 100644 index 0000000000000000000000000000000000000000..63498bfe628484ab1b21d7a00c778630777773a2 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/LinearLambda.mo @@ -0,0 +1,163 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside; +model LinearLambda + "Pressure loss model with friction contribution according to Darcy friction number that is linearly dependent on the mass flow rate" + extends SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss( + final requireTransportPropreties=false); + + // + // Definition of parameters + // + parameter Real lambda_linear(final unit="s/kg") = 0.025 + "Darcy friction factor at mass flow rate of 1 kg/s" + annotation (Dialog(tab="General", group="Calculation Setup")); + +equation + lambda_mean_dd = lambda_linear * abs(m_flow_hyd) + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = lambda_linear * abs(m_flow_hyd) + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'LinearLambda' pressure loss model calculates the pressure loss of a tube +resistance, withthe friction-based pressure loss according to a Darcy friction +number that is linearly dependent on the mass flow rate. The model also includes +dynamic, geodetic, and installation-related pressure losses. The pressure loss is +calculated as a function of the mass flow rate, and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = λ<sub>linear</sub> * ṁ<sub>hyd</sub>; +</pre> +<p> +Herein, <i>λ<sub>linear</sub></i> is the Darcy friction number at a mass +flow rate of 1 kg/s. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end LinearLambda; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/MishraGupaSchmidt.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/MishraGupaSchmidt.mo new file mode 100644 index 0000000000000000000000000000000000000000..50a1fec4fb5344203e0120f20e6d43d3fa31fb3e --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/MishraGupaSchmidt.mo @@ -0,0 +1,241 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside; +model MishraGupaSchmidt + "Pressure loss model with friction contribution according to Mishra, Gupa, and Schmidt" + extends SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss( + final requireTransportPropreties=true); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust pressure drop correlation" + annotation (Dialog(tab="General", group="Calculation Setup")); + + parameter Modelica.Units.SI.Diameter d_avg_helix = 0.1 + "Average diameter of the helix tube (i.e., top-view projection)" + annotation (Dialog(tab="General", group="Geometry")); + parameter Modelica.Units.SI.Height h_helix = 0.025 + "Inclinde of the helix tube" + annotation (Dialog(tab="General", group="Geometry")); + final parameter Modelica.Units.SI.Diameter d_bend_avg_helix = d_avg_helix * + (1 + (h_helix / Modelica.Constants.pi / d_avg_helix) ^ 2) + "Average bending diameter of the helix tube" + annotation (Dialog(tab="General", group="Geometry", enable=false)); + + final parameter Modelica.Units.SI.ReynoldsNumber Re_crit = 2300 * + (1 + 8.6 * (d_hyd_mean / d_bend_avg_helix) ^ (0.45)) + "Critical Reynolds number" + annotation (Dialog(tab="Advanced", group="Numerics", enable=false)); + parameter Modelica.Units.SI.ReynoldsNumber Re_transition = 100 + "Transition length to change between laminar and turbulent flow regime" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + parameter Integer noDiffTransition = 3 + "Specification how often transition function can be differentiated" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // +protected + Real wf_dd = if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent(Re_mean_dd, 2300, Re_transition, + noDiffTransition) else SorpLib.Numerics.smoothTransition(Re_mean_dd, 2300, + Re_transition, noDiffTransition) + "Weighting factor for the design direction"; + Real wf_rdd = if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent(Re_mean_rdd, 2300, Re_transition, + noDiffTransition) else SorpLib.Numerics.smoothTransition(Re_mean_rdd, 2300, + Re_transition, noDiffTransition) + "Weighting factor for the reverse design direction"; + +equation + lambda_mean_dd = f_correction* (wf_dd * 64 / max(Re_mean_dd, 1e-12) * (1 + + 0.033 * Modelica.Math.log10(max(Re_mean_dd * sqrt(d_hyd_mean / + d_bend_avg_helix), 1e-12)) ^ 4) + (1-wf_dd) * 0.3164 * + max(Re_mean_dd, 1e-12) ^ (-0.25) * (1 + 0.095 * sqrt(d_hyd_mean / + d_bend_avg_helix) * max(Re_mean_dd, 1e-12) ^ (0.25))) + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = f_correction* (wf_rdd * 64 / max(Re_mean_rdd, 1e-12) * (1 + + 0.033 * Modelica.Math.log10(max(Re_mean_rdd * sqrt(d_hyd_mean / + d_bend_avg_helix), 1e-12)) ^ 4) + (1-wf_rdd) * 0.3164 * + max(Re_mean_rdd, 1e-12) ^ (-0.25) * (1 + 0.095 * sqrt(d_hyd_mean / + d_bend_avg_helix) * max(Re_mean_rdd, 1e-12) ^ (0.25))) + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'MishraGupaSchmidt' pressure loss model calculates the pressure loss of a tube +resistance, with the friction-based pressure loss according to the Mishra, Gupa, and +Schmidt correlation. The model also includes dynamic, geodetic, and installation-related +pressure losses. The pressure loss is calculated as a function of the mass flow rate, +and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The laminar Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = 64 / Re * [1 + 0.033 * (<strong>log</strong>(Re * <strong>sqrt</strong>(d/D)))<sup>4</sup>] <strong>for</strong> Re ≤ Re<sub>crit</sub>; +</pre> +<p> +and the turbulent Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ =0.3164 / Re<sup>0.25</sup> * [1 + 0.095 * <strong>sqrt</strong>(d/D) * Re<sup>0.25</sup>] <strong>for</strong> Re<sub>crit</sub> ≤ Re ≤ 10<sup>5</sup>; +</pre> +<p> +Herein, <i>Re</i> is the Reynold number, <i>d</i> is the hydraulic diameter, and <i>D</i> is +the average diameter of the helix tube: +</p> +<pre> + D = D* * [1 + (h / π / D*)<sup>2</sup>]; +</pre> +<p> +Herein, <i>D*</i> is the average diameter assuming a horizontal approximation, and <i>h</i> +is the inclinde of the helix tube. Smooth transition is applied using the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition\">SorpLib.Numerics.smoothTransition</a> +to change between laminar and turbulent flow regime, with the critical Renolds number +<i>Re<sub>crit</sub></i> calculated as: +</p> +<pre> + Re<sub>crit</sub> = 2300 * [1 + 8.6 (d / D*)<sup>0.45</sup>]; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> + <li> + Smooth helix tube + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Kast, W., (Revised by Hermann Nirschl), and Gaddis, E.S., and Wirth, KE., and Stichlmair, J. (2010). L1 Pressure Drop in Single Phase Flow. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_70. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MishraGupaSchmidt; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/PrandtlKarman.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/PrandtlKarman.mo new file mode 100644 index 0000000000000000000000000000000000000000..200ff919ccc4f1db68a1b77ecdcbd389d68cba82 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/PrandtlKarman.mo @@ -0,0 +1,278 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside; +model PrandtlKarman + "Pressure loss model with friction contribution according to Prandtl and Karman" + extends SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss( + final requireTransportPropreties=true); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust pressure drop correlation" + annotation (Dialog(tab="General", group="Calculation Setup")); + + parameter Boolean useExplicitFormulation = true + " = true, if explicit formulation usign the Lambert W function shall be + used; otherwise, use implicit formulation" + annotation (Dialog(tab="Advanced", group="Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useExactLambertWFunction = false + " = true, if exact iterative solution of the Lambert W function shall be + used; otherwise, use closed form approximation" + annotation (Dialog(tab="Advanced", group="Numerics", + enable=useExplicitFormulation), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.ReynoldsNumber Re_transition = 100 + "Transition length to change between laminar and turbulent flow regime" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + parameter Integer noDiffTransition = 3 + "Specification how often transition function can be differentiated" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // +protected + Real lambda_mean_turb_dd + "Average Darcy friction factor for the design direction"; + Real lambda_mean_turb_rdd + "Average Darcy friction factor for the reverse design direction"; + + Real wf_dd = if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent(Re_mean_dd, 2300, Re_transition, + noDiffTransition) else SorpLib.Numerics.smoothTransition(Re_mean_dd, 2300, + Re_transition, noDiffTransition) + "Weighting factor for the design direction"; + Real wf_rdd = if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent(Re_mean_rdd, 2300, Re_transition, + noDiffTransition) else SorpLib.Numerics.smoothTransition(Re_mean_rdd, 2300, + Re_transition, noDiffTransition) + "Weighting factor for the reverse design direction"; + +equation + // + // Calculate turbulent Darcy friction factor + // + if useExplicitFormulation then + if useExactLambertWFunction then + lambda_mean_turb_dd = 1.32547 / + Modelica.Fluid.Dissipation.Utilities.Functions.General.LambertWIter( + 0.458338 * Re_mean_dd) ^2 + "Average Darcy friction factor for the design direction"; + lambda_mean_turb_rdd = 1.32547 / + Modelica.Fluid.Dissipation.Utilities.Functions.General.LambertWIter( + 0.458338 * Re_mean_rdd) ^2 + "Average Darcy friction factor for the reverse design direction"; + + else + lambda_mean_turb_dd = 1.32547 / + Modelica.Fluid.Dissipation.Utilities.Functions.General.LambertW(0.458338 * + Re_mean_dd) ^2 + "Average Darcy friction factor for the design direction"; + lambda_mean_turb_rdd = 1.32547 / + Modelica.Fluid.Dissipation.Utilities.Functions.General.LambertW(0.458338 * + Re_mean_rdd) ^2 + "Average Darcy friction factor for the reverse design direction"; + + end if; + + else + 1 / sqrt(max(lambda_mean_turb_dd, 1e-12)) = -0.8 + 2 * Modelica.Math.log10( + max(Re_mean_dd, 1e-12) * sqrt(max(lambda_mean_turb_dd, 1e-12))) + "Average Darcy friction factor for the design direction"; + 1 / sqrt(max(lambda_mean_turb_rdd, 1e-12)) = -0.8 + 2 * Modelica.Math.log10( + max(Re_mean_rdd, 1e-12) * sqrt(max(lambda_mean_turb_rdd, 1e-12))) + "Average Darcy friction factor for the reverse design direction"; + + end if; + + // + // Calculate overall Darcy friction factor + // + lambda_mean_dd = f_correction* ( + wf_dd * 64 / max(Re_mean_dd, 1e-12) + (1-wf_dd) * lambda_mean_turb_dd) + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = f_correction* ( + wf_rdd * 64 / max(Re_mean_rdd, 1e-12) + (1-wf_rdd) * lambda_mean_turb_rdd) + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'PrandtlKarman' pressure loss model calculates the pressure loss of a tube +resistance, with the friction-based pressure loss according to the Prandtl and Karman +correlation. The model also includes dynamic, geodetic, and installation-related +pressure losses. The pressure loss is calculated as a function of the mass flow +rate, and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The laminar Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = 64 / Re <strong>for</strong> Re ≤ 2300; +</pre> +<p> +and the turbulent Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + 1 / <strong>sqrt</strong>(λ) = 2 <strong>log</strong>(Re * <strong>sqrt</strong>(λ)) - 0.8 <strong>for</strong> 2300 ≤ Re; +</pre> +<p> +Herein, <i>Re</i> is the Reynold number. Smooth transition is applied using the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition\">SorpLib.Numerics.smoothTransition</a> +to change between laminar and turbulent flow regime. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> + <li> + Smooth tube + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>useExplicitFormulation</i>: + Defines if explicit formulation of the turbulent Darcy friction factor shall be + used by applying the Lambert W function. + </li> + <li> + <i>useExactLambertWFunction</i>: + Defines if approximation or exact solution (i.e., iteration) of the Lambert W + function shall be used. + </li> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Kast, W., (Revised by Hermann Nirschl), and Gaddis, E.S., and Wirth, KE., and Stichlmair, J. (2010). L1 Pressure Drop in Single Phase Flow. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_70. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PrandtlKarman; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/QuadraticLambda.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/QuadraticLambda.mo new file mode 100644 index 0000000000000000000000000000000000000000..b5401091d39d24c4ec47974947d5d29c9792b4b6 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/QuadraticLambda.mo @@ -0,0 +1,163 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside; +model QuadraticLambda + "Pressure loss model with friction contribution according to Darcy friction number that is quadratically dependent on the mass flow rate" + extends SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss( + final requireTransportPropreties=false); + + // + // Definition of parameters + // + parameter Real lambda_quadratic(final unit="s2/kg2") = 0.025 + "Darcy friction factor at mass flow rate of 1 kg/s" + annotation (Dialog(tab="General", group="Calculation Setup")); + +equation + lambda_mean_dd = lambda_quadratic * m_flow_hyd^2 + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = lambda_quadratic * m_flow_hyd^2 + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'QuadraticLambda' pressure loss model calculates the pressure loss of a tube +resistance, withthe friction-based pressure loss according to a Darcy friction +number that is quadratically dependent on the mass flow rate. The model also includes +dynamic, geodetic, and installation-related pressure losses. The pressure loss is +calculated as a function of the mass flow rate, and there is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +The Darcy friction factor <i>λ</i> is defined as +</p> +<pre> + λ = λ<sub>quadratic</sub> * ṁ<sub>hyd</sub><sup>2</sup>; +</pre> +<p> +Herein, <i>λ<sub>quadratic</sub></i> is the Darcy friction number at a mass +flow rate of 1 kg/s. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pressure loss model is used within tubes if friction shall be included.. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>Re_transition</i>: + Defines the transition length to change between laminar and turbulent flow + regime. + </li> + <li> + <i>noDiffTransition</i>: + Defines how often the transition function can be differentiated. + </li> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end QuadraticLambda; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/ZeroFriction.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/ZeroFriction.mo new file mode 100644 index 0000000000000000000000000000000000000000..aba9b282b809cc0ec84f8bd3c932f7b05378e1ff --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/ZeroFriction.mo @@ -0,0 +1,148 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside; +model ZeroFriction + "Pressure loss model without friction contribution" + extends SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss( + final requireTransportPropreties=false); + +equation + lambda_mean_dd = 0 + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = 0 + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'ZeroFriction' pressure loss model calculates the pressure loss of a tube resistance. +The model includes dynamic, geodetic, and installation-related pressure losses but not +friction. The pressure loss is calculated as a function of the mass flow rate, and there +is no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +This model assumes zero friction, so it does not calculate friction-based +pressure losses: +</p> +<pre> + λ = 0; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The 'ZeroFriction' pressure loss model is used within tubes if friction shall +not be included. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Modifications due to restructering the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ZeroFriction; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/package.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c14288a9be4602c81871c376eff8fedf8629f695 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/package.mo @@ -0,0 +1,56 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations; +package TubeInside "Pressure loss correlations for fluids flowing through pipes" +extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains pressure loss correlations that can be used within tubes +to calculate friction-based pressure losses: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.ZeroFriction\">ZeroFriction</a>: + No friction is considered. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.ConstantLambda\">ConstantLambda</a>: + Constant Darcy friction number. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.LinearLambda\">LinearLambda</a>: + Darcy friction number that is linearly dependent on the mass flow rate. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.QuadraticLambda\">QuadraticLambda</a>: + Darcy friction number that is quadratically dependent on the mass flow rate. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Blasius\">Blasius</a>: + Darcy friction number according to Blasius for smooth, straight tubes. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Konakov\">Konakov</a>: + Darcy friction number according to Konakov for smooth, straight tubes. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.PrandtlKarman\">PrandtlKarman</a>: + Darcy friction number according to Prandtl and Karman for smooth, straight tubes. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Colebrook\">Colebrook</a>: + Darcy friction number according to Colebrook for rough, straight tubes. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.MishraGupaSchmidt\">MishraGupaSchmidt</a>: + Darcy friction number according to Mishra, Gupa, and Schmidt for smooth, helix tubes. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end TubeInside; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/package.order b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/package.order new file mode 100644 index 0000000000000000000000000000000000000000..daf3698e4bb256c1ee520dc12996dac4e3d31e73 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/TubeInside/package.order @@ -0,0 +1,9 @@ +ZeroFriction +ConstantLambda +LinearLambda +QuadraticLambda +Blasius +Konakov +PrandtlKarman +Colebrook +MishraGupaSchmidt diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/ZeroFriction.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/ZeroFriction.mo new file mode 100644 index 0000000000000000000000000000000000000000..40a20e9c01b942b04c74902f1adb53901a3e2b78 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/ZeroFriction.mo @@ -0,0 +1,148 @@ +within SorpLib.Components.Fittings.PressureLossCorrelations; +model ZeroFriction + "Pressure loss model without friction contribution" + extends BaseClasses.PartialPressureLoss( + final psi = 1, + final requireTransportPropreties=false); + +equation + m_flow_hyd = m_flow + "Hydraulic mass flow rate"; + + lambda_mean_dd = 0 + "Average Darcy friction number for design flow direction (a->b)"; + lambda_mean_rdd = 0 + "Average Darcy friction number for reverse design flow direction (b->a)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The 'ZeroFriction' pressure loss model calculates the pressure loss of a generic +resistance. The model includes dynamic, geodetic, and installation-related pressure +losses but not friction. The pressure loss is calculated as a function of the mass +flow rate, and there may be no inverse function. +</p> + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +This model assumes zero friction, so it does not calculate friction-based +pressure losses: +</p> +<pre> + λ = 0; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The 'ZeroFriction' pressure loss model is used within generic resistors as they +do not account for friction-based pressure losses. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <br/> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses and + contains parameters defining which pressure losses shall be included. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <br/> + <li> + <i>showTotalPressures</i>: + Defines if the total pressure shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showVelocities</i>: + Defines if velocities shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showDarcyFrictionNumber</i>: + Defines if the Darcy friction number shall be calculated (i.e., diagnostics). + </li> + <li> + <i>showIndividualPressureLosses</i>: + Defines if individual pressure losses shall be calculated (i.e., diagnostics). + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ZeroFriction; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/package.mo b/SorpLib/Components/Fittings/PressureLossCorrelations/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..6c0694f77406d1629fb44575b54eac0a49cd6ea0 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/package.mo @@ -0,0 +1,35 @@ +within SorpLib.Components.Fittings; +package PressureLossCorrelations "Package containing pressure loss correlations for hydraulic resistors" +extends Modelica.Icons.FunctionsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains pressure loss correlations that can be used within resistance +models. The pressure loss correlations calculate the pressure drop as a function +of mass flow rate. Pressure loss correlations are implemented for the following +resistance types: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside\">TubeInside</a>: + Pressure loss correlations for fluids flowing through a tube. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.OpenAdsorber\">OpenAdsorber</a>: + Pressure loss correlations for fluids flowing through an open adsorber containing, + e.g., a packed bed. + </li> +</ul> +<p> +Furthermore, a 'ZeroFriction' pressure loss correlation exists for generic resistance +models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructering the library. + </li> +</ul> +</html>")); +end PressureLossCorrelations; diff --git a/SorpLib/Components/Fittings/PressureLossCorrelations/package.order b/SorpLib/Components/Fittings/PressureLossCorrelations/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5dea82bbaa89d566a8b48a4fd6d8161f3cb10a05 --- /dev/null +++ b/SorpLib/Components/Fittings/PressureLossCorrelations/package.order @@ -0,0 +1,3 @@ +TubeInside +OpenAdsorber +ZeroFriction diff --git a/SorpLib/Components/Fittings/Records/FluidProperties.mo b/SorpLib/Components/Fittings/Records/FluidProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..32b6a90dae9e10ac21c91380d470bdbb55287ac0 --- /dev/null +++ b/SorpLib/Components/Fittings/Records/FluidProperties.mo @@ -0,0 +1,33 @@ +within SorpLib.Components.Fittings.Records; +record FluidProperties + "This record contains fluid properties required for resistors" + extends Modelica.Icons.Record; + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p + "Pressure"; + Modelica.Units.SI.Temperature T + "Temperature"; + Modelica.Units.SI.Density rho + "Density"; + Modelica.Units.SI.DynamicViscosity eta + "Dynamic viscosity"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains fluid properties required for resistances. +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end FluidProperties; diff --git a/SorpLib/Components/Fittings/Records/GeometryGenericReistance.mo b/SorpLib/Components/Fittings/Records/GeometryGenericReistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..158724c01d637d99f61335fe128dd0bb90cc9c56 --- /dev/null +++ b/SorpLib/Components/Fittings/Records/GeometryGenericReistance.mo @@ -0,0 +1,73 @@ +within SorpLib.Components.Fittings.Records; +record GeometryGenericReistance + "This record contains the geometry of generic resistors" + extends Modelica.Icons.Record; + + // + // Definition of parameters regarding the calculation setup + // + parameter Boolean dynamicPressureLoss = false + " = true, if dynamic pressure loss shall be included (i.e., different + velocities at port a and b due to change of cross-sectional areas)" + annotation (Dialog(tab="General", group="Calculation Setup", enable=false), + choices(checkBox=true), + Evaluate=true); + parameter Boolean geodeticPressureLoss = false + " = true, if geodetic pressure loss shall be included (i.e., different + heights at port a and b)" + annotation (Dialog(tab="General", group="Calculation Setup", enable=false), + choices(checkBox=true), + Evaluate=true); + parameter Boolean frictionPressureLoss = true + " = true, if pressure loss due to friction shall be included" + annotation (Dialog(tab="General", group="Calculation Setup", enable=false), + choices(checkBox=true), + Evaluate=true); + parameter Boolean fittingPressureLosss = false + " = true, if pressure losses due to fittings shall be included" + annotation (Dialog(tab="General", group="Calculation Setup", enable=false), + choices(checkBox=true), + Evaluate=true); + + // + // Definition of parameters regarding the geometry + // + parameter Modelica.Units.SI.Length l = 1 + "Length (i.e., distance between port a and b)" + annotation (Dialog(tab="General", group="Geometry", + enable=frictionPressureLoss)); + parameter Modelica.Units.SI.Diameter d_hyd_a = 0.01 + "Hydraulic diameter at port a" + annotation (Dialog(tab="General", group="Geometry", + enable=dynamicPressureLoss or frictionPressureLoss or + fittingPressureLosss)); + parameter Modelica.Units.SI.Diameter d_hyd_b = d_hyd_a + "Hydraulic diameter at port b" + annotation (Dialog(tab="General", group="Geometry", + enable=dynamicPressureLoss or frictionPressureLoss or + fittingPressureLosss)); + parameter Modelica.Units.SI.Height z_a = 1 + "Height at port a (only relevant if geodetic pressure loss is included)" + annotation (Dialog(tab="General", group="Geometry", + enable=geodeticPressureLoss)); + parameter Modelica.Units.SI.Height z_b = z_a + "Height at port b (only relevant if geodetic pressure loss is included)" + annotation (Dialog(tab="General", group="Geometry", + enable=geodeticPressureLoss)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters required by all hydraulic resistors. +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryGenericReistance; diff --git a/SorpLib/Components/Fittings/Records/GeometryOpenAdsorber.mo b/SorpLib/Components/Fittings/Records/GeometryOpenAdsorber.mo new file mode 100644 index 0000000000000000000000000000000000000000..0215cdebc5743d742e181f1b2bc1d92dba0f0506 --- /dev/null +++ b/SorpLib/Components/Fittings/Records/GeometryOpenAdsorber.mo @@ -0,0 +1,37 @@ +within SorpLib.Components.Fittings.Records; +record GeometryOpenAdsorber + "This record contains the geometry of resistors for open adsorber" + extends SorpLib.Components.Fittings.Records.GeometryGenericReistance; + + // + // Definition of parameters regarding the geometry + // + parameter Modelica.Units.SI.Diameter d_particle = 0.7 / 1000 + "Diameter of the adsorbent particle" + annotation (Dialog(tab="General", group="Geometry")); + parameter Real psi(unit="1") = 0.32 + "Void fraction of the open adsorber (i.e., 1 for free adsorber)" + annotation (Dialog(tab="General", group="Geometry")); + parameter Integer no_hydraulicParallelFlows = 1 + "Number of hydraulically parallel flows (e.g., for heat exchanger tubes)" + annotation (Dialog(tab="General", group="Geometry", + enable=dynamicPressureLoss or frictionPressureLoss or + fittingPressureLosss)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters required by hydraulic resistors for +open adsorbers. +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryOpenAdsorber; diff --git a/SorpLib/Components/Fittings/Records/GeometryTube.mo b/SorpLib/Components/Fittings/Records/GeometryTube.mo new file mode 100644 index 0000000000000000000000000000000000000000..838e2e9fc4044b9c94ce6df90ad7947ce7dbe3f4 --- /dev/null +++ b/SorpLib/Components/Fittings/Records/GeometryTube.mo @@ -0,0 +1,35 @@ +within SorpLib.Components.Fittings.Records; +record GeometryTube + "This record contains the geometry of resistors for tubes" + extends SorpLib.Components.Fittings.Records.GeometryGenericReistance; + + // + // Definition of parameters regarding the geometry + // + parameter Modelica.Units.SI.Length roughness = 7.5e-7 + "Absolute roughness of tubes" + annotation (Dialog(tab="General", group="Geometry", + enable=frictionPressureLoss)); + parameter Integer no_hydraulicParallelFlows = 1 + "Number of hydraulically parallel flows (e.g., for heat exchanger tubes)" + annotation (Dialog(tab="General", group="Geometry", + enable=dynamicPressureLoss or frictionPressureLoss or + fittingPressureLosss)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters required by hydraulic resistors for +tubes. +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryTube; diff --git a/SorpLib/Components/Fittings/Records/package.mo b/SorpLib/Components/Fittings/Records/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..14be88b3fa8899bf2580b18b96952d715d95d361 --- /dev/null +++ b/SorpLib/Components/Fittings/Records/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Fittings; +package Records "Package containing records" + extends Modelica.Icons.RecordsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains definitions of records. These records are used to cluster +variables and tidy up the model output. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Records; diff --git a/SorpLib/Components/Fittings/Records/package.order b/SorpLib/Components/Fittings/Records/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6827d69fe49a9fd85a9d22e766e0e0e801224a59 --- /dev/null +++ b/SorpLib/Components/Fittings/Records/package.order @@ -0,0 +1,4 @@ +FluidProperties +GeometryGenericReistance +GeometryTube +GeometryOpenAdsorber diff --git a/SorpLib/Components/Fittings/Resistors/GasGenericResistance.mo b/SorpLib/Components/Fittings/Resistors/GasGenericResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..859e65055e6daf77ce92d1ed405f0828f30bc88d --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/GasGenericResistance.mo @@ -0,0 +1,448 @@ +within SorpLib.Components.Fittings.Resistors; +model GasGenericResistance "Gas generic resistance" + extends SorpLib.Components.Fittings.BaseClasses.PartialResistance( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX, + final frictionPressureLoss=false, + redeclare final model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.ZeroFriction, + fittingPressureLosss=true); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Medium.ThermodynamicState state_a + "Fluid properties at port a for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_b + "Fluid properties at port b for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_a_ad + "Fluid properties at port a for reverse design flow direction (i.e., a<-b)"; + Medium.ThermodynamicState state_b_ad + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + +equation + // + // Calculate state properties (only if needed) + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_b + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + if instreamingPropertiesByInput then + state_b_ad = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet or + positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=port_b.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = Medium.setState_phX( + p=port_a.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + end if; + + // + // Pass and calculate further state properties + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + fluidProperties_a.p = p_ref + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = T_ref + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = rho_ref + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = eta_ref + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = p_ref + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = T_ref + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = rho_ref + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = p_ref + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = T_ref + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = rho_ref + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = p_ref + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = T_ref + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = rho_ref + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = eta_ref + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + else + fluidProperties_a.p = if not instreamingPropertiesByInput then + port_a.p else p_a_internal + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_a) else T_a_internal + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_a) else rho_a_internal + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a) else eta_ref) else eta_a_internal + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = port_b.p + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = Medium.temperature(state=state_b) + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = Medium.density(state=state_b) + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b) else eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = port_a.p + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = Medium.temperature(state=state_a_ad) + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = Medium.density(state=state_a_ad) + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a_ad) else eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = if not instreamingPropertiesByInput then + port_b.p else p_b_ad_internal + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_b_ad) else T_b_ad_internal + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_b_ad) else rho_b_ad_internal + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b_ad) else eta_ref) else eta_b_ad_internal + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The gas generic resistance can be used to describe dynamic, geodetic, and +fitting-based pressure losses. Friction-based pressure losses are not considered. + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +This model assumes zero friction, so it does not calculate friction-based +pressure losses: +</p> +<pre> + λ = 0; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The generic resistance is typically used to described pressure losses caused +by fittings, e.g., sliders, bends, or changes in cross-section. +</p> + + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>instreamingPropertiesByInput</i>: + Defines if the instreaming fluid properties are provided via an input, so + they do not need to be calculated internally. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <li> + <i>dynamicPressureLoss</i>: + Defines if dynamic pressure losses are considered. + </li> + <li> + <i>geodeticPressureLoss</i>: + Defines if geodetic pressure losses are considered. + </li> + <li> + <i>fittingPressureLosss</i>: + Defines if fitting-based pressure losses are considered. + </li> + <br/> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end GasGenericResistance; diff --git a/SorpLib/Components/Fittings/Resistors/GasOpenAdsorberResistance.mo b/SorpLib/Components/Fittings/Resistors/GasOpenAdsorberResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..bfb37e450a712cccc87bab48f11dc24fb4cd290b --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/GasOpenAdsorberResistance.mo @@ -0,0 +1,461 @@ +within SorpLib.Components.Fittings.Resistors; +model GasOpenAdsorberResistance "Gas resistance for open adsorbers" + extends SorpLib.Components.Fittings.BaseClasses.PartialResistance( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX, + redeclare replaceable model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.OpenAdsorber.ZeroFriction + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialOpenAdsorberPressureLoss, + redeclare replaceable parameter SorpLib.Components.Fittings.Records.GeometryOpenAdsorber geometry + constrainedby SorpLib.Components.Fittings.Records.GeometryOpenAdsorber); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Medium.ThermodynamicState state_a + "Fluid properties at port a for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_b + "Fluid properties at port b for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_a_ad + "Fluid properties at port a for reverse design flow direction (i.e., a<-b)"; + Medium.ThermodynamicState state_b_ad + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + +equation + // + // Calculate state properties (only if needed) + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_b + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + if instreamingPropertiesByInput then + state_b_ad = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet or + positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=port_b.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = Medium.setState_phX( + p=port_a.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + end if; + + // + // Pass and calculate further state properties + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + fluidProperties_a.p = p_ref + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = T_ref + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = rho_ref + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = eta_ref + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = p_ref + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = T_ref + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = rho_ref + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = p_ref + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = T_ref + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = rho_ref + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = p_ref + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = T_ref + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = rho_ref + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = eta_ref + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + else + fluidProperties_a.p = if not instreamingPropertiesByInput then + port_a.p else p_a_internal + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_a) else T_a_internal + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_a) else rho_a_internal + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a) else eta_ref) else eta_a_internal + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = port_b.p + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = Medium.temperature(state=state_b) + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = Medium.density(state=state_b) + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b) else eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = port_a.p + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = Medium.temperature(state=state_a_ad) + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = Medium.density(state=state_a_ad) + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a_ad) else eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = if not instreamingPropertiesByInput then + port_b.p else p_b_ad_internal + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_b_ad) else T_b_ad_internal + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_b_ad) else rho_b_ad_internal + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b_ad) else eta_ref) else eta_b_ad_internal + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The gas resistance for open adsorbers can be used to describe dynamic, geodetic, friction-based +and fitting-based pressure losses. + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +Different models can be used to calculate friction-based pressure losses. These models +cover laminar and turbulent flow regimes and are valid for smooth or rough tubes. Please +check +<a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside\">SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside</a> +for more information on available pressure loss correlations. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The resistance for open adsorbers is typically used to describe pressure losses within +open adsorbers. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>instreamingPropertiesByInput</i>: + Defines if the instreaming fluid properties are provided via an input, so + they do not need to be calculated internally. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <li> + <i>dynamicPressureLoss</i>: + Defines if dynamic pressure losses are considered. + </li> + <li> + <i>geodeticPressureLoss</i>: + Defines if geodetic pressure losses are considered. + </li> + <li> + <i>frictionPressureLosss</i>: + Defines if friction-based pressure losses are considered. + </li> + <li> + <i>fittingPressureLosss</i>: + Defines if fitting-based pressure losses are considered. + </li> + <br/> + <li> + <i>PressureLossModel</i>: + Defines the pressure loss model for the friction-based pressure loss. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Adaptations due to restructering the library. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasOpenAdsorberResistance; diff --git a/SorpLib/Components/Fittings/Resistors/GasTubeResistance.mo b/SorpLib/Components/Fittings/Resistors/GasTubeResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..035feabd6f2b7393302d2a31f6b14aa47d1095d2 --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/GasTubeResistance.mo @@ -0,0 +1,460 @@ +within SorpLib.Components.Fittings.Resistors; +model GasTubeResistance "Gas tube resistance" + extends SorpLib.Components.Fittings.BaseClasses.PartialResistance( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX, + redeclare replaceable model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.ZeroFriction + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss, + redeclare replaceable parameter SorpLib.Components.Fittings.Records.GeometryTube geometry + constrainedby SorpLib.Components.Fittings.Records.GeometryTube); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Medium.ThermodynamicState state_a + "Fluid properties at port a for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_b + "Fluid properties at port b for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_a_ad + "Fluid properties at port a for reverse design flow direction (i.e., a<-b)"; + Medium.ThermodynamicState state_b_ad + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + +equation + // + // Calculate state properties (only if needed) + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_b + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + if instreamingPropertiesByInput then + state_b_ad = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet or + positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=port_b.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = Medium.setState_phX( + p=port_a.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + end if; + + // + // Pass and calculate further state properties + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + fluidProperties_a.p = p_ref + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = T_ref + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = rho_ref + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = eta_ref + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = p_ref + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = T_ref + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = rho_ref + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = p_ref + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = T_ref + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = rho_ref + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = p_ref + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = T_ref + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = rho_ref + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = eta_ref + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + else + fluidProperties_a.p = if not instreamingPropertiesByInput then + port_a.p else p_a_internal + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_a) else T_a_internal + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_a) else rho_a_internal + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a) else eta_ref) else eta_a_internal + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = port_b.p + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = Medium.temperature(state=state_b) + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = Medium.density(state=state_b) + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b) else eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = port_a.p + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = Medium.temperature(state=state_a_ad) + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = Medium.density(state=state_a_ad) + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a_ad) else eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = if not instreamingPropertiesByInput then + port_b.p else p_b_ad_internal + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_b_ad) else T_b_ad_internal + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_b_ad) else rho_b_ad_internal + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b_ad) else eta_ref) else eta_b_ad_internal + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The gas tube resistance can be used to describe dynamic, geodetic, friction-based +and fitting-based pressure losses. + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +Different models can be used to calculate friction-based pressure losses. These models +cover laminar and turbulent flow regimes and are valid for smooth or rough tubes. Please +check +<a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside\">SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside</a> +for more information on available pressure loss correlations. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The tube resistance is typically used to describe pressure losses within tubes. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>instreamingPropertiesByInput</i>: + Defines if the instreaming fluid properties are provided via an input, so + they do not need to be calculated internally. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <li> + <i>dynamicPressureLoss</i>: + Defines if dynamic pressure losses are considered. + </li> + <li> + <i>geodeticPressureLoss</i>: + Defines if geodetic pressure losses are considered. + </li> + <li> + <i>frictionPressureLosss</i>: + Defines if friction-based pressure losses are considered. + </li> + <li> + <i>fittingPressureLosss</i>: + Defines if fitting-based pressure losses are considered. + </li> + <br/> + <li> + <i>PressureLossModel</i>: + Defines the pressure loss model for the friction-based pressure loss. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Adaptations due to restructering the library. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasTubeResistance; diff --git a/SorpLib/Components/Fittings/Resistors/LiquidGenericResistance.mo b/SorpLib/Components/Fittings/Resistors/LiquidGenericResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..571c9107819bf771e99cb8718e8c84dfab010ef4 --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/LiquidGenericResistance.mo @@ -0,0 +1,447 @@ +within SorpLib.Components.Fittings.Resistors; +model LiquidGenericResistance "Liquid generic resistance" + extends SorpLib.Components.Fittings.BaseClasses.PartialResistance( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + final no_components=Medium.nX, + final frictionPressureLoss=false, + redeclare final model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.ZeroFriction, + fittingPressureLosss=true); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Medium.ThermodynamicState state_a + "Fluid properties at port a for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_b + "Fluid properties at port b for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_a_ad + "Fluid properties at port a for reverse design flow direction (i.e., a<-b)"; + Medium.ThermodynamicState state_b_ad + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + +equation + // + // Calculate state properties (only if needed) + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_b + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + if instreamingPropertiesByInput then + state_b_ad = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet or + positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=port_b.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = Medium.setState_phX( + p=port_a.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + end if; + + // + // Pass and calculate further state properties + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + fluidProperties_a.p = p_ref + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = T_ref + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = rho_ref + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = eta_ref + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = p_ref + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = T_ref + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = rho_ref + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = p_ref + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = T_ref + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = rho_ref + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = p_ref + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = T_ref + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = rho_ref + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = eta_ref + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + else + fluidProperties_a.p = if not instreamingPropertiesByInput then + port_a.p else p_a_internal + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_a) else T_a_internal + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_a) else rho_a_internal + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a) else eta_ref) else eta_a_internal + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = port_b.p + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = Medium.temperature(state=state_b) + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = Medium.density(state=state_b) + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b) else eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = port_a.p + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = Medium.temperature(state=state_a_ad) + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = Medium.density(state=state_a_ad) + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a_ad) else eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = if not instreamingPropertiesByInput then + port_b.p else p_b_ad_internal + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_b_ad) else T_b_ad_internal + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_b_ad) else rho_b_ad_internal + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b_ad) else eta_ref) else eta_b_ad_internal + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The liquid generic resistance can be used to describe dynamic, geodetic, and +fitting-based pressure losses. Friction-based pressure losses are not considered. + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +This model assumes zero friction, so it does not calculate friction-based +pressure losses: +</p> +<pre> + λ = 0; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The generic resistance is typically used to described pressure losses caused +by fittings, e.g., sliders, bends, or changes in cross-section. +</p> + + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>instreamingPropertiesByInput</i>: + Defines if the instreaming fluid properties are provided via an input, so + they do not need to be calculated internally. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <li> + <i>dynamicPressureLoss</i>: + Defines if dynamic pressure losses are considered. + </li> + <li> + <i>geodeticPressureLoss</i>: + Defines if geodetic pressure losses are considered. + </li> + <li> + <i>fittingPressureLosss</i>: + Defines if fitting-based pressure losses are considered. + </li> + <br/> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end LiquidGenericResistance; diff --git a/SorpLib/Components/Fittings/Resistors/LiquidTubeResistance.mo b/SorpLib/Components/Fittings/Resistors/LiquidTubeResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..b5cfc4f4a6f22bebb3a049d944f03ad007c50484 --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/LiquidTubeResistance.mo @@ -0,0 +1,460 @@ +within SorpLib.Components.Fittings.Resistors; +model LiquidTubeResistance "Liquid tube resistance" + extends SorpLib.Components.Fittings.BaseClasses.PartialResistance( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + final no_components=Medium.nX, + redeclare replaceable model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.ZeroFriction + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss, + redeclare replaceable parameter SorpLib.Components.Fittings.Records.GeometryTube geometry + constrainedby SorpLib.Components.Fittings.Records.GeometryTube); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Medium.ThermodynamicState state_a + "Fluid properties at port a for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_b + "Fluid properties at port b for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_a_ad + "Fluid properties at port a for reverse design flow direction (i.e., a<-b)"; + Medium.ThermodynamicState state_b_ad + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + +equation + // + // Calculate state properties (only if needed) + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_b + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + if instreamingPropertiesByInput then + state_b_ad = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet or + positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=port_b.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = Medium.setState_phX( + p=port_a.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + end if; + + // + // Pass and calculate further state properties + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + fluidProperties_a.p = p_ref + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = T_ref + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = rho_ref + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = eta_ref + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = p_ref + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = T_ref + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = rho_ref + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = p_ref + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = T_ref + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = rho_ref + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = p_ref + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = T_ref + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = rho_ref + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = eta_ref + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + else + fluidProperties_a.p = if not instreamingPropertiesByInput then + port_a.p else p_a_internal + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_a) else T_a_internal + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_a) else rho_a_internal + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a) else eta_ref) else eta_a_internal + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = port_b.p + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = Medium.temperature(state=state_b) + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = Medium.density(state=state_b) + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b) else eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = port_a.p + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = Medium.temperature(state=state_a_ad) + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = Medium.density(state=state_a_ad) + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a_ad) else eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = if not instreamingPropertiesByInput then + port_b.p else p_b_ad_internal + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_b_ad) else T_b_ad_internal + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_b_ad) else rho_b_ad_internal + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b_ad) else eta_ref) else eta_b_ad_internal + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The liquid tube resistance can be used to describe dynamic, geodetic, friction-based +and fitting-based pressure losses. + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +Different models can be used to calculate friction-based pressure losses. These models +cover laminar and turbulent flow regimes and are valid for smooth or rough tubes. Please +check +<a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside\">SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside</a> +for more information on available pressure loss correlations. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The tube resistance is typically used to describe pressure losses within tubes. +</p> + + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>instreamingPropertiesByInput</i>: + Defines if the instreaming fluid properties are provided via an input, so + they do not need to be calculated internally. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <li> + <i>dynamicPressureLoss</i>: + Defines if dynamic pressure losses are considered. + </li> + <li> + <i>geodeticPressureLoss</i>: + Defines if geodetic pressure losses are considered. + </li> + <li> + <i>frictionPressureLosss</i>: + Defines if friction-based pressure losses are considered. + </li> + <li> + <i>fittingPressureLosss</i>: + Defines if fitting-based pressure losses are considered. + </li> + <br/> + <li> + <i>PressureLossModel</i>: + Defines the pressure loss model for the friction-based pressure loss. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Adaptations due to restructering the library. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end LiquidTubeResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/Test_GasGenericResistance.mo b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasGenericResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..7c853ff06ac05d835fca63c2bad8875878f360e3 --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasGenericResistance.mo @@ -0,0 +1,115 @@ +within SorpLib.Components.Fittings.Resistors.Tester; +model Test_GasGenericResistance + "Tester for the gas generic resistance" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGases.N2 + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium model of the ideal gas" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of models + // + SorpLib.Components.Fittings.Resistors.GasGenericResistance resistance( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.Constant, + dynamicPressureLoss=true, + geodeticPressureLoss=true, + instreamingPropertiesByInput=false, + fittingPressureLosss=true, + rho_ref(displayUnit="kg/m3"), + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry( + d_hyd_a=0.15, + d_hyd_b=0.1, + z_a=9, + z_b=10), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Sine input_m_flow( + amplitude=1, + f=1/500, + phase=1.5707963267949, + offset=0) "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=5e5, + duration=2500, + offset=5e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, resistance.port_a) annotation (Line( + points={{-60,0},{-8,0}}, + color={244,125,35}, + thickness=1)); + connect(resistance.port_b, fs_b.port) annotation (Line( + points={{8,0},{60,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_m_flow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{ + -70,0},{-70,2},{-61.2,2}}, + color={0,0,127})); + connect(input_p.y, fs_b.p_input) annotation (Line(points={{79,0},{70,0},{70,5}, + {61.2,5}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=2500, + Tolerance=1e-06), Documentation(info="<html> +<p> +This model checks the gas generic resistance model using an ideal gas. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasGenericResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/Test_GasOpenAdsorberResistance.mo b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasOpenAdsorberResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..cd737e4fca2ce237a9ec78814df38754c325138d --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasOpenAdsorberResistance.mo @@ -0,0 +1,128 @@ +within SorpLib.Components.Fittings.Resistors.Tester; +model Test_GasOpenAdsorberResistance + "Tester for the gas resistance for open adsorbers" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGases.N2 + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium model of the ideal gas" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.OpenAdsorber.Kast + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialOpenAdsorberPressureLoss + "Pressure loss model" + annotation (Dialog(tab="General", group="Models"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of models + // + SorpLib.Components.Fittings.Resistors.GasOpenAdsorberResistance resistance( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dynamicPressureLoss=false, + geodeticPressureLoss=false, + frictionPressureLoss=true, + fittingPressureLosss=false, + instreamingPropertiesByInput=false, + rho_ref(displayUnit="kg/m3"), + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry( + d_hyd_a=0.15, + z_a=9, + psi=0.5), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final model PressureLossModel = PressureLossModel, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Sine input_m_flow( + amplitude=0.5, + f=1/500, + phase=1.5707963267949, + offset=0) "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=5e5, + duration=2500, + offset=5e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, resistance.port_a) annotation (Line( + points={{-60,0},{-8,0}}, + color={244,125,35}, + thickness=1)); + connect(resistance.port_b, fs_b.port) annotation (Line( + points={{8,0},{60,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_m_flow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{ + -70,0},{-70,2},{-61.2,2}}, + color={0,0,127})); + connect(input_p.y, fs_b.p_input) annotation (Line(points={{79,0},{70,0},{70,5}, + {61.2,5}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=2500, + Tolerance=1e-06, + __Dymola_Algorithm="Dassl"), Documentation(info="<html> +<p> +This model checks the gas resistance model for open adsorbers using an +ideal gas. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasOpenAdsorberResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/Test_GasTubeResistance.mo b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasTubeResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..054a411af908332cef2a51e6664b90a6117dca8d --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasTubeResistance.mo @@ -0,0 +1,122 @@ +within SorpLib.Components.Fittings.Resistors.Tester; +model Test_GasTubeResistance "Tester for the gas tube resistance" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGases.N2 + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium model of the ideal gas" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.ConstantLambda + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss + "Pressure loss model" + annotation (Dialog(tab="General", group="Models"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of models + // + SorpLib.Components.Fittings.Resistors.GasTubeResistance resistance( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dynamicPressureLoss=false, + geodeticPressureLoss=false, + frictionPressureLoss=true, + fittingPressureLosss=false, + instreamingPropertiesByInput=false, + rho_ref(displayUnit="kg/m3"), + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry(d_hyd_a=0.15, z_a=9), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final model PressureLossModel = PressureLossModel, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Sine input_m_flow( + amplitude=1, + f=1/500, + phase=1.5707963267949, + offset=0) "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=5e5, + duration=2500, + offset=5e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, resistance.port_a) annotation (Line( + points={{-60,0},{-8,0}}, + color={244,125,35}, + thickness=1)); + connect(resistance.port_b, fs_b.port) annotation (Line( + points={{8,0},{60,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_m_flow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{-70, + 0},{-70,2},{-61.2,2}}, color={0,0,127})); + connect(input_p.y, fs_b.p_input) annotation (Line(points={{79,0},{70,0},{70,5}, + {61.2,5}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=2500, + Tolerance=1e-06, + __Dymola_Algorithm="Dassl"), Documentation(info="<html> +<p> +This model checks the gas tube resistance model using an ideal gas. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasTubeResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/Test_GasVaporMixtureGenericResistance.mo b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasVaporMixtureGenericResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..182c21012283eaf16f098689b467bf2704cea4db --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasVaporMixtureGenericResistance.mo @@ -0,0 +1,109 @@ +within SorpLib.Components.Fittings.Resistors.Tester; +model Test_GasVaporMixtureGenericResistance + "Tester for the gas generic resistance" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of models + // + SorpLib.Components.Fittings.Resistors.GasGenericResistance resistance( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dpFromMFlow=true, + dynamicPressureLoss=false, + geodeticPressureLoss=false, + instreamingPropertiesByInput=false, + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry(d_hyd_a=0.15, z_a=9), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Sine input_m_flow( + amplitude=1, + f=1/500, + phase=1.5707963267949, + offset=0) "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=5e5, + duration=2500, + offset=5e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, resistance.port_a) annotation (Line( + points={{-60,0},{-8,0}}, + color={244,125,35}, + thickness=1)); + connect(resistance.port_b, fs_b.port) annotation (Line( + points={{8,0},{60,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_m_flow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{ + -70,0},{-70,2},{-61.2,2}}, + color={0,0,127})); + connect(input_p.y, fs_b.p_input) annotation (Line(points={{79,0},{70,0},{70,5}, + {61.2,5}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the gas generic resistance model using an ideal gas-vapor +mixture. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasVaporMixtureGenericResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/Test_GasVaporMixtureOpenAdsorberResistance.mo b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasVaporMixtureOpenAdsorberResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..ed3c6c180df3edb24b4c9d596325dbee67002460 --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasVaporMixtureOpenAdsorberResistance.mo @@ -0,0 +1,127 @@ +within SorpLib.Components.Fittings.Resistors.Tester; +model Test_GasVaporMixtureOpenAdsorberResistance + "Tester for the gas resistance for open adsorbers" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.OpenAdsorber.Kast + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialOpenAdsorberPressureLoss + "Pressure loss model" + annotation (Dialog(tab="General", group="Models"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of models + // + SorpLib.Components.Fittings.Resistors.GasOpenAdsorberResistance resistance( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dynamicPressureLoss=false, + geodeticPressureLoss=false, + frictionPressureLoss=true, + fittingPressureLosss=false, + instreamingPropertiesByInput=false, + rho_ref(displayUnit="kg/m3"), + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry( + d_hyd_a=0.15, + z_a=9, + psi=0.5), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final model PressureLossModel = PressureLossModel, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Sine input_m_flow( + amplitude=0.5, + f=1/500, + phase=1.5707963267949, + offset=0) "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=5e5, + duration=2500, + offset=5e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, resistance.port_a) annotation (Line( + points={{-60,0},{-8,0}}, + color={244,125,35}, + thickness=1)); + connect(resistance.port_b, fs_b.port) annotation (Line( + points={{8,0},{60,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_m_flow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{-70, + 0},{-70,2},{-61.2,2}}, color={0,0,127})); + connect(input_p.y, fs_b.p_input) annotation (Line(points={{79,0},{70,0},{70,5}, + {61.2,5}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=2500, + Tolerance=1e-06, + __Dymola_Algorithm="Dassl"), Documentation(info="<html> +<p> +This model checks the gas tube resistance model using an ideal gas-vapor +mixture. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasVaporMixtureOpenAdsorberResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/Test_GasVaporMixtureTubeResistance.mo b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasVaporMixtureTubeResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..e32de3f80944107df6c0b1175c865ad075a08dbd --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/Test_GasVaporMixtureTubeResistance.mo @@ -0,0 +1,125 @@ +within SorpLib.Components.Fittings.Resistors.Tester; +model Test_GasVaporMixtureTubeResistance + "Tester for the gas tube resistance" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Colebrook + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss + "Pressure loss model" + annotation (Dialog(tab="General", group="Models"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of models + // + SorpLib.Components.Fittings.Resistors.GasTubeResistance resistance( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dynamicPressureLoss=false, + geodeticPressureLoss=false, + frictionPressureLoss=true, + fittingPressureLosss=false, + instreamingPropertiesByInput=false, + rho_ref(displayUnit="kg/m3"), + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry(d_hyd_a=0.15, z_a=9), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final model PressureLossModel = PressureLossModel, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Sine input_m_flow( + amplitude=1, + f=1/500, + phase=1.5707963267949, + offset=0) "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=5e5, + duration=2500, + offset=5e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, resistance.port_a) annotation (Line( + points={{-60,0},{-8,0}}, + color={244,125,35}, + thickness=1)); + connect(resistance.port_b, fs_b.port) annotation (Line( + points={{8,0},{60,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_m_flow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{ + -70,0},{-70,2},{-61.2,2}}, + color={0,0,127})); + connect(input_p.y, fs_b.p_input) annotation (Line(points={{79,0},{70,0},{70,5}, + {61.2,5}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=2500, + Tolerance=1e-06, + __Dymola_Algorithm="Dassl"), Documentation(info="<html> +<p> +This model checks the gas tube resistance model using an ideal gas-vapor +mixture. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasVaporMixtureTubeResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/Test_LiquidGenericResistance.mo b/SorpLib/Components/Fittings/Resistors/Tester/Test_LiquidGenericResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..8635ad53d48ab0553c3f73400cf4c255dc4587cd --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/Test_LiquidGenericResistance.mo @@ -0,0 +1,185 @@ +within SorpLib.Components.Fittings.Resistors.Tester; +model Test_LiquidGenericResistance + "Tester for the liquid generic resistance" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,20},{-50,40}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,20},{50,40}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a_wVolume( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-40},{-50,-20}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b_wVolume( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-40},{50,-20}}))); + + // + // Definition of models + // + SorpLib.Components.Fittings.Resistors.LiquidGenericResistance resistance( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dynamicPressureLoss=true, + geodeticPressureLoss=true, + instreamingPropertiesByInput=false, + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry( + d_hyd_b=0.008, + z_a=9, + z_b=10), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,20},{10,40}}))); + + SorpLib.Components.Fittings.Resistors.LiquidGenericResistance + resistance_wVolume( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dynamicPressureLoss=true, + geodeticPressureLoss=true, + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry( + d_hyd_b=0.008, + z_a=9, + z_b=10), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,-40},{10,-20}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume volume_a( + p_initial=600000, + T_initial=288.15, + mc_flow_initialX=-1, + useHeatPorts=false, + useHeatPortsY=false, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + redeclare final package Medium = Medium) "Volume at port a" + annotation (Placement(transformation(extent={{-40,-40},{-20,-20}}))); + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume volume_b( + p_initial=500000, + T_initial=288.15, + mc_flow_initialX=-1, + useHeatPorts=false, + useHeatPortsY=false, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + redeclare final package Medium = Medium) "Volume at port b" + annotation (Placement(transformation(extent={{20,-40},{40,-20}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Sine input_m_flow( + amplitude=1, + f=1/500, + phase=1.5707963267949, + offset=0) "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=5e5, + duration=2500, + offset=5e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, resistance.port_a) annotation (Line( + points={{-60,30},{-8,30}}, + color={28,108,200}, + thickness=1)); + connect(resistance.port_b, fs_b.port) annotation (Line( + points={{8,30},{60,30}}, + color={28,108,200}, + thickness=1)); + connect(fs_a_wVolume.port, volume_a.cfp_xMinus[1]) annotation (Line( + points={{-60,-30},{-50,-30},{-50,-28.2},{-34.2,-28.2}}, + color={28,108,200}, + thickness=1)); + connect(volume_a.cfp_xPlus[1], resistance_wVolume.port_a) annotation (Line( + points={{-22.2,-28.2},{-16,-28.2},{-16,-30},{-8,-30}}, + color={28,108,200}, + thickness=1)); + connect(resistance_wVolume.port_b, volume_b.cfp_xMinus[1]) annotation (Line( + points={{8,-30},{16,-30},{16,-28.2},{25.8,-28.2}}, + color={28,108,200}, + thickness=1)); + connect(volume_b.cfp_xPlus[1], fs_b_wVolume.port) annotation (Line( + points={{37.8,-28.2},{50,-28.2},{50,-30},{60,-30}}, + color={28,108,200}, + thickness=1)); + + connect(input_m_flow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{-70, + 0},{-70,32},{-61.2,32}}, color={0,0,127})); + connect(input_m_flow.y, fs_a_wVolume.m_flow_input) annotation (Line(points={{-79, + 0},{-70,0},{-70,-28},{-61.2,-28}}, color={0,0,127})); + connect(input_p.y, fs_b.p_input) annotation (Line(points={{79,0},{70,0},{70,35}, + {61.2,35}}, color={0,0,127})); + connect(input_p.y, fs_b_wVolume.p_input) annotation (Line(points={{79,0},{70,0}, + {70,-25},{61.2,-25}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the liquid generic resistance model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_LiquidGenericResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/Test_LiquidTubeResistance.mo b/SorpLib/Components/Fittings/Resistors/Tester/Test_LiquidTubeResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..77ed3f86a0e0ec3c000af42fcd66d65cde87131f --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/Test_LiquidTubeResistance.mo @@ -0,0 +1,199 @@ +within SorpLib.Components.Fittings.Resistors.Tester; +model Test_LiquidTubeResistance + "Tester for the liquid tube resistance" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Colebrook + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss + "Pressure loss model" + annotation (Dialog(tab="General", group="Models"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,20},{-50,40}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,20},{50,40}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a_wVolume( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-40},{-50,-20}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b_wVolume( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-40},{50,-20}}))); + + // + // Definition of models + // + SorpLib.Components.Fittings.Resistors.LiquidTubeResistance resistance( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dynamicPressureLoss=true, + geodeticPressureLoss=true, + frictionPressureLoss=true, + instreamingPropertiesByInput=false, + redeclare final model PressureLossModel = PressureLossModel, + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry( + d_hyd_b=0.008, + z_a=9, + z_b=10), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,20},{10,40}}))); + + SorpLib.Components.Fittings.Resistors.LiquidTubeResistance + resistance_wVolume( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dynamicPressureLoss=true, + geodeticPressureLoss=true, + frictionPressureLoss=true, + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry( + d_hyd_b=0.008, + z_a=9, + z_b=10), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final model PressureLossModel = PressureLossModel, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,-40},{10,-20}}))); + + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume volume_a( + p_initial=600000, + T_initial=288.15, + mc_flow_initialX=-1, + useHeatPorts=false, + useHeatPortsY=false, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + redeclare final package Medium = Medium) "Volume at port a" + annotation (Placement(transformation(extent={{-40,-40},{-20,-20}}))); + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume volume_b( + p_initial=500000, + T_initial=288.15, + mc_flow_initialX=-1, + useHeatPorts=false, + useHeatPortsY=false, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + redeclare final package Medium = Medium) "Volume at port b" + annotation (Placement(transformation(extent={{20,-40},{40,-20}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Sine input_m_flow( + amplitude=1, + f=1/500, + phase=1.5707963267949, + offset=0) "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=5e5, + duration=2500, + offset=5e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, resistance.port_a) annotation (Line( + points={{-60,30},{-8,30}}, + color={28,108,200}, + thickness=1)); + connect(resistance.port_b, fs_b.port) annotation (Line( + points={{8,30},{60,30}}, + color={28,108,200}, + thickness=1)); + connect(fs_a_wVolume.port, volume_a.cfp_xMinus[1]) annotation (Line( + points={{-60,-30},{-50,-30},{-50,-28.2},{-34.2,-28.2}}, + color={28,108,200}, + thickness=1)); + connect(volume_a.cfp_xPlus[1], resistance_wVolume.port_a) annotation (Line( + points={{-22.2,-28.2},{-16,-28.2},{-16,-30},{-8,-30}}, + color={28,108,200}, + thickness=1)); + connect(resistance_wVolume.port_b, volume_b.cfp_xMinus[1]) annotation (Line( + points={{8,-30},{16,-30},{16,-28.2},{25.8,-28.2}}, + color={28,108,200}, + thickness=1)); + connect(volume_b.cfp_xPlus[1], fs_b_wVolume.port) annotation (Line( + points={{37.8,-28.2},{50,-28.2},{50,-30},{60,-30}}, + color={28,108,200}, + thickness=1)); + + connect(input_m_flow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{-70, + 0},{-70,32},{-61.2,32}}, color={0,0,127})); + connect(input_m_flow.y, fs_a_wVolume.m_flow_input) annotation (Line(points={{-79, + 0},{-70,0},{-70,-28},{-61.2,-28}}, color={0,0,127})); + connect(input_p.y, fs_b.p_input) annotation (Line(points={{79,0},{70,0},{70,35}, + {61.2,35}}, color={0,0,127})); + connect(input_p.y, fs_b_wVolume.p_input) annotation (Line(points={{79,0},{70,0}, + {70,-25},{61.2,-25}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the liquid tube resistance model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_LiquidTubeResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/Test_VLEGenericResistance.mo b/SorpLib/Components/Fittings/Resistors/Tester/Test_VLEGenericResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..6b9e7f42c12232949c947443780b5d7bef8dcb59 --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/Test_VLEGenericResistance.mo @@ -0,0 +1,109 @@ +within SorpLib.Components.Fittings.Resistors.Tester; +model Test_VLEGenericResistance "Tester for the VLE generic resistance" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.VLESource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of models + // + SorpLib.Components.Fittings.Resistors.VLEGenericResistance resistance( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dynamicPressureLoss=true, + geodeticPressureLoss=true, + instreamingPropertiesByInput=false, + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry( + d_hyd_b=0.008, + z_a=9, + z_b=10), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Sine input_m_flow( + amplitude=1, + f=1/500, + phase=1.5707963267949, + offset=0) "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=5e5, + duration=2500, + offset=5e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, resistance.port_a) annotation (Line( + points={{-60,0},{-8,0}}, + color={0,140,72}, + thickness=1)); + connect(resistance.port_b, fs_b.port) annotation (Line( + points={{8,0},{60,0}}, + color={0,140,72}, + thickness=1)); + + connect(input_m_flow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{ + -70,0},{-70,2},{-61.2,2}}, + color={0,0,127})); + connect(input_p.y, fs_b.p_input) annotation (Line(points={{79,0},{70,0},{70,5}, + {61.2,5}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the VLE generic resistance model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_VLEGenericResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/Test_VLETubeResistance.mo b/SorpLib/Components/Fittings/Resistors/Tester/Test_VLETubeResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..da7b652e7f739b31c36be7d9691e8059a19cf3af --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/Test_VLETubeResistance.mo @@ -0,0 +1,121 @@ +within SorpLib.Components.Fittings.Resistors.Tester; +model Test_VLETubeResistance "Tester for the VLE tube resistance" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Colebrook + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss + "Pressure loss model" + annotation (Dialog(tab="General", group="Models"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.VLESource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of models + // + SorpLib.Components.Fittings.Resistors.VLETubeResistance resistance( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.ActualInlet, + dynamicPressureLoss=true, + geodeticPressureLoss=true, + frictionPressureLoss=true, + instreamingPropertiesByInput=false, + redeclare final model PressureLossModel = PressureLossModel, + flowDirectionDependentZeta=true, + zeta_b={0.1,0.1,0.1}, + geometry( + d_hyd_b=0.008, + z_a=9, + z_b=10), + zeta_a={0.1,0.2,0.4}, + m_flow_start=-1, + redeclare final package Medium = Medium) + "Resistance model without volumes at inlet and outlet" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // + Modelica.Blocks.Sources.Sine input_m_flow( + amplitude=1, + f=1/500, + phase=1.5707963267949, + offset=0) "Input signal for mass flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=5e5, + duration=2500, + offset=5e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, resistance.port_a) annotation (Line( + points={{-60,0},{-8,0}}, + color={0,140,72}, + thickness=1)); + connect(resistance.port_b, fs_b.port) annotation (Line( + points={{8,0},{60,0}}, + color={0,140,72}, + thickness=1)); + + connect(input_m_flow.y, fs_a.m_flow_input) annotation (Line(points={{-79,0},{ + -70,0},{-70,2},{-61.2,2}}, + color={0,0,127})); + connect(input_p.y, fs_b.p_input) annotation (Line(points={{79,0},{70,0},{70,5}, + {61.2,5}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the VLE tube resistance model. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_VLETubeResistance; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/package.mo b/SorpLib/Components/Fittings/Resistors/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..3e41d93e681c937861a91789905fcb7ef61c7b38 --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Fittings.Resistors; +package Tester "Models to test and varify multi port models" + extends Modelica.Icons.ExamplesPackage; + + + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented inertia inducers. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Fittings/Resistors/Tester/package.order b/SorpLib/Components/Fittings/Resistors/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6bb858e0049a3803f93d641bad5f3a9dc2896ef0 --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/Tester/package.order @@ -0,0 +1,10 @@ +Test_LiquidGenericResistance +Test_LiquidTubeResistance +Test_GasGenericResistance +Test_GasVaporMixtureGenericResistance +Test_GasTubeResistance +Test_GasVaporMixtureTubeResistance +Test_GasOpenAdsorberResistance +Test_GasVaporMixtureOpenAdsorberResistance +Test_VLEGenericResistance +Test_VLETubeResistance diff --git a/SorpLib/Components/Fittings/Resistors/VLEGenericResistance.mo b/SorpLib/Components/Fittings/Resistors/VLEGenericResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..1dc18c7410d158b425e73b8172f6537eb8fb540c --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/VLEGenericResistance.mo @@ -0,0 +1,448 @@ +within SorpLib.Components.Fittings.Resistors; +model VLEGenericResistance "VLE generic resistance" + extends SorpLib.Components.Fittings.BaseClasses.PartialResistance( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + final no_components=Medium.nX, + final frictionPressureLoss=false, + redeclare final model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.ZeroFriction, + fittingPressureLosss=true); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Medium.ThermodynamicState state_a + "Fluid properties at port a for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_b + "Fluid properties at port b for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_a_ad + "Fluid properties at port a for reverse design flow direction (i.e., a<-b)"; + Medium.ThermodynamicState state_b_ad + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + +equation + // + // Calculate state properties (only if needed) + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_b + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + if instreamingPropertiesByInput then + state_b_ad = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet or + positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=port_b.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = Medium.setState_phX( + p=port_a.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + end if; + + // + // Pass and calculate further state properties + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + fluidProperties_a.p = p_ref + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = T_ref + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = rho_ref + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = eta_ref + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = p_ref + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = T_ref + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = rho_ref + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = p_ref + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = T_ref + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = rho_ref + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = p_ref + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = T_ref + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = rho_ref + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = eta_ref + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + else + fluidProperties_a.p = if not instreamingPropertiesByInput then + port_a.p else p_a_internal + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_a) else T_a_internal + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_a) else rho_a_internal + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a) else eta_ref) else eta_a_internal + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = port_b.p + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = Medium.temperature(state=state_b) + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = Medium.density(state=state_b) + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b) else eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = port_a.p + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = Medium.temperature(state=state_a_ad) + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = Medium.density(state=state_a_ad) + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a_ad) else eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = if not instreamingPropertiesByInput then + port_b.p else p_b_ad_internal + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_b_ad) else T_b_ad_internal + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_b_ad) else rho_b_ad_internal + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b_ad) else eta_ref) else eta_b_ad_internal + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The VLE generic resistance can be used to describe dynamic, geodetic, and +fitting-based pressure losses. Friction-based pressure losses are not considered. + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +This model assumes zero friction, so it does not calculate friction-based +pressure losses: +</p> +<pre> + λ = 0; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The generic resistance is typically used to described pressure losses caused +by fittings, e.g., sliders, bends, or changes in cross-section. +</p> + + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>instreamingPropertiesByInput</i>: + Defines if the instreaming fluid properties are provided via an input, so + they do not need to be calculated internally. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <li> + <i>dynamicPressureLoss</i>: + Defines if dynamic pressure losses are considered. + </li> + <li> + <i>geodeticPressureLoss</i>: + Defines if geodetic pressure losses are considered. + </li> + <li> + <i>fittingPressureLosss</i>: + Defines if fitting-based pressure losses are considered. + </li> + <br/> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end VLEGenericResistance; diff --git a/SorpLib/Components/Fittings/Resistors/VLETubeResistance.mo b/SorpLib/Components/Fittings/Resistors/VLETubeResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..86841fa4e56b6a6cc38194c0fcb3a5fb0b7a9f6c --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/VLETubeResistance.mo @@ -0,0 +1,461 @@ +within SorpLib.Components.Fittings.Resistors; +model VLETubeResistance "VLE tube resistance" + extends SorpLib.Components.Fittings.BaseClasses.PartialResistance( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + final no_components=Medium.nX, + redeclare replaceable model PressureLossModel = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.ZeroFriction + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss, + redeclare replaceable parameter SorpLib.Components.Fittings.Records.GeometryTube geometry + constrainedby SorpLib.Components.Fittings.Records.GeometryTube); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Medium.ThermodynamicState state_a + "Fluid properties at port a for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_b + "Fluid properties at port b for design flow direction (i.e., a->b)"; + Medium.ThermodynamicState state_a_ad + "Fluid properties at port a for reverse design flow direction (i.e., a<-b)"; + Medium.ThermodynamicState state_b_ad + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + +equation + // + // Calculate state properties (only if needed) + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortAInlet then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + state_b_ad = state_b + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.PortBInlet then + if instreamingPropertiesByInput then + state_b_ad = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b = state_a + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_a + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + elseif positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.ActualInlet or + positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.AverageInstreaming then + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = state_b + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + if instreamingPropertiesByInput then + state_a = Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Fluid properties at port a for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_b_ad = state_a + "Fluid properties at port b for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + else + state_a = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port a for design flow direction (i.e., a->b)"; + state_b_ad = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + state_b = Medium.setState_phX( + p=port_b.p, + h=inStream(port_a.h_outflow), + X=inStream(port_a.Xi_outflow)) + "Fluid properties at port b for design flow direction (i.e., a->b): + Not needed, so set dummy values"; + state_a_ad = Medium.setState_phX( + p=port_a.p, + h=inStream(port_b.h_outflow), + X=inStream(port_b.Xi_outflow)) + "Fluid properties at port a for reverse design flow direction (i.e., a<-b): + Not needed, so set dummy values"; + + end if; + + // + // Pass and calculate further state properties + // + if positionFluidProperties== + SorpLib.Choices.ResistorFluidProperties.Constant then + fluidProperties_a.p = p_ref + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = T_ref + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = rho_ref + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = eta_ref + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = p_ref + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = T_ref + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = rho_ref + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = p_ref + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = T_ref + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = rho_ref + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = p_ref + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = T_ref + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = rho_ref + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = eta_ref + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + else + fluidProperties_a.p = if not instreamingPropertiesByInput then + port_a.p else p_a_internal + "Pressure at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_a) else T_a_internal + "Temperature at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_a) else rho_a_internal + "Density at port a for design flow direction (i.e., a->b)"; + fluidProperties_a.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a) else eta_ref) else eta_a_internal + "Dynamic viscosity at port a for design flow direction (i.e., a->b)"; + + fluidProperties_b.p = port_b.p + "Pressure at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.T = Medium.temperature(state=state_b) + "Temperature at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.rho = Medium.density(state=state_b) + "Density at port b for design flow direction (i.e., a->b)"; + fluidProperties_b.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b) else eta_ref + "Dynamic viscosity at port b for design flow direction (i.e., a->b)"; + + fluidProperties_a_ad.p = port_a.p + "Pressure at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.T = Medium.temperature(state=state_a_ad) + "Temperature at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.rho = Medium.density(state=state_a_ad) + "Density at port a for reverse design flow direction (i.e., a<-b)"; + fluidProperties_a_ad.eta = if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_a_ad) else eta_ref + "Dynamic viscosity at port a for reverse design flow direction (i.e., a<-b)"; + + fluidProperties_b_ad.p = if not instreamingPropertiesByInput then + port_b.p else p_b_ad_internal + "Pressure at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.T = if not instreamingPropertiesByInput then + Medium.temperature(state=state_b_ad) else T_b_ad_internal + "Temperature at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.rho = if not instreamingPropertiesByInput then + Medium.density(state=state_b_ad) else rho_b_ad_internal + "Density at port b for reverse design flow direction (i.e., a<-b)"; + fluidProperties_b_ad.eta = if not instreamingPropertiesByInput then + (if pressureLossModel.requireTransportPropreties then + Medium.dynamicViscosity(state=state_b_ad) else eta_ref) else eta_b_ad_internal + "Dynamic viscosity at port b for reverse design flow direction (i.e., a<-b)"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The VLE tube resistance can be used to describe dynamic, geodetic, friction-based +and fitting-based pressure losses. + +<h4>Main equations</h4> +<p> +The static pressure drop <i>Δp<sub>static</sub></i> is calculated as a function +of the hydraulic mass flow rate <i>ṁ<sub>hyd</sub> </i> and follows from the +extended Bernoulli equation for incompressible fluids: +</p> +<pre> + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * [ρ<sub>b</sub> * w<sub>b</sub><sup>2</sup> - ρ<sub>a</sub> * w<sub>a</sub><sup>2</sup>] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * <SPAN STYLE=\"text-decoration:overline\">w</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; + + Δp<sub>static</sub> = p<sub>a</sub> - p<sub>b</sub> = 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * [1 / (ρ<sub>b</sub> * A<sub>b</sub><sup>2</sup>) - 1 / (ρ<sub>a</sub> * A<sub>a</sub><sup>2</sup>)] + g * [ρ<sub>b</sub> * z<sub>b</sub> - ρ<sub>a</sub> * z<sub>a</sub>] + 1/2 * ṁ<sub>hyd</sub><sup>2</sup> * 1/<SPAN STYLE=\"text-decoration:overline\">ρ</SPAN> * 1/<SPAN STYLE=\"text-decoration:overline\">A</SPAN><sup>2</sup> * [∑ ζ<sub>i</sub> + l/ <SPAN STYLE=\"text-decoration:overline\">d</SPAN> * λ]; +</pre> +<p> +Herein, <i>ρ<sub>a</sub></i>/<i>ρ<sub>b</sub></i> describes the fluid density +at port a/b, <i>w<sub>a</sub></i>/<i>w<sub>b</sub></i> is the fluid velocity at port a/b, +<i>z<sub>a</sub></i>/<i>z<sub>b</sub></i> is geodetic height port a/b, and <i>A<sub>a</sub></i>/<i>A<sub>b</sub></i> +is the cross-sectional area at port a/b. The variable <i> <SPAN STYLE=\"text-decoration:overline\">ρ</SPAN></i> +is the average fluid density, <i> <SPAN STYLE=\"text-decoration:overline\">A</SPAN></i> is +the average cross-sectional area, <i><SPAN STYLE=\"text-decoration:overline\">d</SPAN></i> +is the average diameter, <i> <SPAN STYLE=\"text-decoration:overline\">w</SPAN></i> is the +average fluid velocity, <i>l</i> is the length, and <i>λ</i> is the Darcy friction factor. +<br/><br/> +The used fluid properties can be selected via the option <i>positionFluidProperties</i>, +and it is possible to choose constant fluid properties or fluid properties at the current +flow inlet. Note that the equation of the static pressure loss is implemented both for +the design direction (a->b) and reverse the design direction (b->a) to enable flow reversal + via the numerically robust functions +<a href=\"Modelica://SorpLib.Numerics.regStep\">SorpLib.Numerics.regStep</a> and +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> + +<h4>Friction-based pressure loss</h4> +<p> +Different models can be used to calculate friction-based pressure losses. These models +cover laminar and turbulent flow regimes and are valid for smooth or rough tubes. Please +check +<a href=\"Modelica://SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside\">SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside</a> +for more information on available pressure loss correlations. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state flow regime + </li> + <li> + Incompressible fluid (i.e., may not be applicable for gases/gas mixtures) + </li> + <li> + Applies along a streamline and not for an entire flow field + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The tube resistance is typically used to describe pressure losses within tubes. +</p> + + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>positionFluidProperties</i>: + Defines the position of the fluid property calculation used to calculate + pressure losses. + </li> + <li> + <i>instreamingPropertiesByInput</i>: + Defines if the instreaming fluid properties are provided via an input, so + they do not need to be calculated internally. + </li> + <li> + <i>dpFromMFlow</i>: + Defines if static pressure loss is calculated from hydraulic mass flow rate + or vice versa. + </li> + <li> + <i>dynamicPressureLoss</i>: + Defines if dynamic pressure losses are considered. + </li> + <li> + <i>geodeticPressureLoss</i>: + Defines if geodetic pressure losses are considered. + </li> + <li> + <i>frictionPressureLosss</i>: + Defines if friction-based pressure losses are considered. + </li> + <li> + <i>fittingPressureLosss</i>: + Defines if fitting-based pressure losses are considered. + </li> + <br/> + <li> + <i>PressureLossModel</i>: + Defines the pressure loss model for the friction-based pressure loss. + </li> + <li> + <i>flowDirectionDependentZeta</i>: + Defines if the fitting-caused pressure loss is dependent on the flow direction. + </li> + <li> + <i>geometry</i>: + Defines the resistance geometry required to calculate pressure losses. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 22, 2023, by Mirko Engelpracht:<br/> + Adaptations due to restructering the library. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end VLETubeResistance; diff --git a/SorpLib/Components/Fittings/Resistors/package.mo b/SorpLib/Components/Fittings/Resistors/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f7e66e63f1ecc8b6b5e26bbe484bfbb378979f4b --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/package.mo @@ -0,0 +1,23 @@ +within SorpLib.Components.Fittings; +package Resistors "Package containing hydraulic resistors" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains hydraulic resistors based on the Modelica Standard library +(MSL). Hydraulic resistors can be used to calculate pressure losses as a function +of mass flow rate and vice versa. These resistors can be used on their own, to +represent pressure losses caused by fittings. Alternatively, these resistors can +be used in components such as pipes or open adsorbers to calculate pressure losses +due to friction, geostatic height differences, or cross-section changes (i.e., +velocity changes). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructering the library. + </li> +</ul> +</html>")); +end Resistors; diff --git a/SorpLib/Components/Fittings/Resistors/package.order b/SorpLib/Components/Fittings/Resistors/package.order new file mode 100644 index 0000000000000000000000000000000000000000..0805c812218418c8b2b347743873fc9233427ebc --- /dev/null +++ b/SorpLib/Components/Fittings/Resistors/package.order @@ -0,0 +1,8 @@ +LiquidGenericResistance +LiquidTubeResistance +GasGenericResistance +GasTubeResistance +GasOpenAdsorberResistance +VLEGenericResistance +VLETubeResistance +Tester diff --git a/SorpLib/Components/Fittings/TJunctions/GasMixtureTJunction.mo b/SorpLib/Components/Fittings/TJunctions/GasMixtureTJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..e17d9e1d55daea1b92635f54b36aff51b9dd692d --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/GasMixtureTJunction.mo @@ -0,0 +1,316 @@ +within SorpLib.Components.Fittings.TJunctions; +model GasMixtureTJunction "Gas mixture T-junction element" + extends SorpLib.Components.Fittings.BaseClasses.PartialTJunction( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_c, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX, + final pressureNoStateVariable = Medium.singleState, + final neglectTermVp = false, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + h_initial= + Medium.specificEnthalpy_pTX(p=p_initial, T=T_initial, X=Medium.reference_X), + X_i_initial=Medium.reference_X, + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_independentMassBalances= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture + "Medium model of the ideal gas mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the calculation setup + // + parameter Boolean idealGasMixture = true + " = true, if medium is an ideal gas mixture and govering equations are + explicitly written for an ideal gas mixture" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity at constant pressure"; + Modelica.Media.Common.IsobaricVolumeExpansionCoefficient beta + "Isobaric expnasion coefficient"; + Modelica.Media.Common.IsothermalCompressibility kappa + "Isothermal compressibility"; + Modelica.Media.Common.JouleThomsonCoefficient my + "Joule-Thomson coefficient"; + +equation + // + // Assertations + // + assert(pressureNoStateVariable or not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + // + // Calculation of properties + // + if independentStateVariables == + SorpLib.Choices.IndependentVariablesVolume.pTX then + state = Medium.setState_pTX(p=p, T=T, X=X_i) + "Thermodynamic state required to calculate medium properties"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + else + state = Medium.setState_phX(p=p, h=h, X=X_i) + "Thermodynamic state required to calculate medium properties"; + T = Medium.temperature(state=state) + "Temperature"; + + end if; + + rho = Medium.density(state=state) + "Density"; + + for ind in 1:no_components loop + h_i[ind] = Medium.specificEnthalpy_i_T(ind_component=ind, T=T) + "Specific enthalpy of individual components"; + end for; + + cp = if ((independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + beta = if (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + kappa = if (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + my = if (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp))) then + v / cp * (beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + // + // Mass balance + // + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dm_dtau = V * (Medium.density_derX(state=state) * der(X_i) + + rho * (kappa *der(p) - beta * der(T))) + "Transient overall mass balance"; + + else + if idealGasMixture then + dm_dtau = V * (rho * (kappa * der(p) - beta / cp * der(h)) + + (Medium.density_derX(state=state) .+ rho .* beta .* + h_i ./ cp) * der(X_i)) + "Transient overall mass balance"; + + else + dm_dtau = V * (rho * ((kappa - beta * my) * der(p) - beta / cp * + der(h)) + (Medium.density_derX(state=state) .+ rho .* beta .* + h_i ./ cp) * der(X_i)) + "Transient overall mass balance"; + + end if; + end if; + end if; + + // + // Energy balance + // + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + if idealGasMixture then + dU_dtau = u * dm_dtau + m * ((cp - p * v * beta) * der(T) + + (h_i .+ p .* v.^2 .* Medium.density_derX(state=state)) * der(X_i)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * (v * (p * kappa - T * beta) * der(p) + + (cp - p * v * beta) * der(T) + (h_i .+ p .* v.^2 .* + Medium.density_derX(state=state)) * der(X_i)) + "Transient energy balance"; + + end if; + + else + if idealGasMixture then + dU_dtau = u * dm_dtau + m * ((1 - p * v * beta / cp) * der(h) + + p .* v.^2 .* (Medium.density_derX(state=state) .+ rho .* + beta .* h_i ./ cp) * der(X_i)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ((1 - p * v * beta / cp) * der(h) + + v * (p * (kappa - beta * my) - 1) * der(p) + p .* v.^2 .* + (Medium.density_derX(state=state) .+ rho .* beta .* h_i ./ cp) * + der(X_i)) + "Transient energy balance"; + + end if; + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a gas mixture T-junction element, applying a lumped modeling +approach. This T-junction is used to connect three gas mixture flows, thereby +calculating mixing properties via (transient) mass and energy balances. +</p> + +<h4>Main equations</h4> +<p> +The main equations are a momentum balance and (transient) mass and energy balances. +Independent states are either the pressure <i>p</i>, temperature <i>T</i>, and mass +fractions </i>X_i</i> or the pressure <i>p</i>, specific enthalpy <i>h</i>, and mass +fractions </i>X_i</i>. The most important equations can be found in the documentation +of the model +<a href=\"Modelica://SorpLib.Basics.Volumes.FluidVolumes.GasMixtureVolume\">SorpLib.Basics.Volumes.FluidVolumes.GasMixtureVolume</a>. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> + <li> + Ideal gas mixture + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to connect three medium flows. In this model, the mixing +properties are calculated via (dynamic) mass and energy balances. Hence, this model acts +like a PT1-element and can be used to break algebraic loops. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <li> + <i>idealGasMixture</i>: + Defines if the medium is an ideal gas mixture and, thus, the governing equations + can be simplified. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_independentMassBalances</i>: + Defines the type of the independent mass balances. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has three dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i> , temperature <i>T</i>, and mass fractions <i>X_i</i> (recommended), or + </li> + <li> + pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions <i>X_i</i>. + </li> +</ul> +<p> +Note that this model does not have the pressure <i>p</i> as dynamic state if the +fluid property model is a single state model. +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end GasMixtureTJunction; diff --git a/SorpLib/Components/Fittings/TJunctions/GasTJunction.mo b/SorpLib/Components/Fittings/TJunctions/GasTJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..77cb9d11c26020557ad671cee3d6aaad6391c4de --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/GasTJunction.mo @@ -0,0 +1,303 @@ +within SorpLib.Components.Fittings.TJunctions; +model GasTJunction "Gas T-junction element" + extends SorpLib.Components.Fittings.BaseClasses.PartialTJunction( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_c, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX, + final pressureNoStateVariable = Medium.singleState, + final neglectTermVp = false, + final X_i_initial=ones(no_components), + final type_independentMassBalances= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + h_initial= + Medium.specificEnthalpy_pTX(p=p_initial, T=T_initial, X=Medium.reference_X), + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = SorpLib.Media.IdealGases.N2 + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium model of the ideal gas" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the calculation setup + // + parameter Boolean idealGas = true + " = true, if medium is an ideal gas and govering equations are explicitly + written for an ideal gas" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity at constant pressure"; + Modelica.Media.Common.IsobaricVolumeExpansionCoefficient beta + "Isobaric expnasion coefficient"; + Modelica.Media.Common.IsothermalCompressibility kappa + "Isothermal compressibility"; + Modelica.Media.Common.JouleThomsonCoefficient my + "Joule-Thomson coefficient"; + +equation + // + // Assertations + // + assert(no_components <= 1, + "The gas volume model can only handel pure fluids (i.e., with one component)!", + level = AssertionLevel.error); + + assert(pressureNoStateVariable or not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + // + // Calculation of properties + // + if independentStateVariables == + SorpLib.Choices.IndependentVariablesVolume.pTX then + state = Medium.setState_pTX(p=p, T=T, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + else + state = Medium.setState_phX(p=p, h=h, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + T = Medium.temperature(state=state) + "Temperature"; + + end if; + + rho = Medium.density(state=state) + "Density"; + h_i = fill(h, no_components) + "Specific enthalpy of individual components: Liquid T-junction can handle + only one component"; + + cp = if ((independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + beta = if (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + kappa = if (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + my = if (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp))) then + v / cp * (beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + // + // Mass balance + // + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dm_dtau = V * rho * (kappa *der(p) - beta * der(T)) + "Transient overall mass balance"; + + else + if idealGas then + dm_dtau = V * rho * (kappa * der(p) - beta / cp * der(h)) + "Transient overall mass balance"; + + else + dm_dtau = V * rho * ((kappa - beta * my) * der(p) - beta / cp * der(h)) + "Transient overall mass balance"; + + end if; + end if; + end if; + + // + // Energy balance + // + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + if idealGas then + dU_dtau = u * dm_dtau + m * ((cp - p * v * beta) * der(T)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + v * (p * kappa - T * beta) * der(p) + (cp - p * v * beta) * der(T)) + "Transient energy balance"; + + end if; + + else + if idealGas then + dU_dtau = u * dm_dtau + m * ((1 - p * v * beta / cp) * der(h)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ( + (1 - p * v * beta / cp) * der(h) + + v * (p * (kappa - beta * my) - 1) * der(p)) + "Transient energy balance"; + + end if; + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a gas T-junction element, applying a lumped modeling +approach. This T-junction is used to connect three gas flows, thereby calculating +mixing properties via (transient) mass and energy balances. +</p> + +<h4>Main equations</h4> +<p> +The main equations are a momentum balance and (transient) mass and energy balances. +Independent states are either the pressure <i>p</i>, temperature <i>T</i>, and mass +fractions </i>X_i</i> or the pressure <i>p</i>, specific enthalpy <i>h</i>, and mass +fractions </i>X_i</i>. The most important equations can be found in the documentation +of the model +<a href=\"Modelica://SorpLib.Basics.Volumes.FluidVolumes.GasVolume\">SorpLib.Basics.Volumes.FluidVolumes.GasVolume</a>. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> + <li> + Ideal gas + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to connect three medium flows. In this model, the mixing +properties are calculated via (dynamic) mass and energy balances. Hence, this model acts +like a PT1-element and can be used to break algebraic loops. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <li> + <i>idealGas</i>: + Defines if the medium is an ideal gas and, thus, the governing equations can + be simplified. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has three dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i> , temperature <i>T</i>, and mass fractions <i>X_i</i> (recommended), or + </li> + <li> + pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions <i>X_i</i>. + </li> +</ul> +<p> +Note that this model does not have the pressure <i>p</i> as dynamic state if the +fluid property model is a single state model. +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end GasTJunction; diff --git a/SorpLib/Components/Fittings/TJunctions/GasVaporMixtureTJunction.mo b/SorpLib/Components/Fittings/TJunctions/GasVaporMixtureTJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..d9ca884a16ecbfaed1018d09de9a5887613c8319 --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/GasVaporMixtureTJunction.mo @@ -0,0 +1,325 @@ +within SorpLib.Components.Fittings.TJunctions; +model GasVaporMixtureTJunction "Gas-vapor mixture T-junction element" + extends SorpLib.Components.Fittings.BaseClasses.PartialTJunction( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_c, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX, + final pressureNoStateVariable = Medium.singleState, + final neglectTermVp = false, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + h_initial= + Medium.specificEnthalpy_pTX(p=p_initial, T=T_initial, X=Medium.reference_X), + X_i_initial=Medium.reference_X, + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_independentMassBalances= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture + "Medium model of the ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the calculation setup + // + parameter Boolean idealGasVaporMixture = true + " = true, if medium is an ideal gas-vapoor mixture and govering equations are + explicitly written for an ideal gas mixture (i.e., unsaturated air)" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity at constant pressure"; + Modelica.Media.Common.IsobaricVolumeExpansionCoefficient beta + "Isobaric expnasion coefficient"; + Modelica.Media.Common.IsothermalCompressibility kappa + "Isothermal compressibility"; + Modelica.Media.Common.JouleThomsonCoefficient my + "Joule-Thomson coefficient"; + +equation + // + // Assertations + // + assert(pressureNoStateVariable or not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + if idealGasVaporMixture then + assert(Medium.relativeHumidity(state=state) < 1.0, + "Govering equations according to ideal gas mixture can only be applied if " + + "dry air is not saturatred! Results may not be reasonable!", + level = AssertionLevel.warning); + + end if; + + // + // Calculation of properties + // + if independentStateVariables == + SorpLib.Choices.IndependentVariablesVolume.pTX then + state = Medium.setState_pTX(p=p, T=T, X=X_i) + "Thermodynamic state required to calculate medium properties"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + else + state = Medium.setState_phX(p=p, h=h, X=X_i) + "Thermodynamic state required to calculate medium properties"; + T = Medium.temperature(state=state) + "Temperature"; + + end if; + + rho = Medium.density(state=state) + "Density"; + + for ind in 1:no_components loop + h_i[ind] = Medium.specificEnthalpy_i(ind_component=ind, state=state) + "Specific enthalpy of individual components"; + end for; + + cp = if ((independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + beta = if (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + kappa = if (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + my = if (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp))) then + v / cp * (beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + // + // Mass balance + // + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dm_dtau = V * (Medium.density_derX(state=state) * der(X_i) + + rho * (kappa *der(p) - beta * der(T))) + "Transient overall mass balance"; + + else + if idealGasVaporMixture then + dm_dtau = V * (rho * (kappa * der(p) - beta / cp * der(h)) + + (Medium.density_derX(state=state) .+ rho .* beta .* + Medium.dh_dX_pT(state=state) ./ cp) * der(X_i)) + "Transient overall mass balance"; + + else + dm_dtau = V * (rho * ((kappa - beta * my) * der(p) - + beta / cp * der(h)) + (Medium.density_derX(state=state) .+ rho .* + beta .* Medium.dh_dX_pT(state=state) ./ cp) * der(X_i)) + "Transient overall mass balance"; + + end if; + end if; + end if; + + // + // Energy balance + // + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + if idealGasVaporMixture then + dU_dtau = u * dm_dtau + m * ((cp - p * v * beta) * der(T) + + (Medium.dh_dX_pT(state=state) .+ p .* v.^2 .* + Medium.density_derX(state=state)) * der(X_i)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * (v * (p * kappa - T * beta) * der(p) + + (cp - p * v * beta) * der(T) + (Medium.dh_dX_pT(state=state) .+ p .* + v.^2 .* Medium.density_derX(state=state)) * der(X_i)) + "Transient energy balance"; + + end if; + + else + if idealGasVaporMixture then + dU_dtau = u * dm_dtau + m * ((1 - p * v * beta / cp) * der(h) + + p .* v.^2 .* (Medium.density_derX(state=state) .+ rho .* + beta .* Medium.dh_dX_pT(state=state) ./ cp) * der(X_i)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ((1 - p * v * beta / cp) * der(h) + + v * (p * (kappa - beta * my) - 1) * der(p) + p .* v.^2 .* + (Medium.density_derX(state=state) .+ rho .* beta .* + Medium.dh_dX_pT(state=state) ./ cp) * der(X_i)) + "Transient energy balance"; + + end if; + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a gas-vapor mixture T-junction element, applying a lumped +modeling approach. This T-junction is used to connect three gas-vapor mixture flows, +thereby calculating mixing properties via (transient) mass and energy balances. +</p> + +<h4>Main equations</h4> +<p> +The main equations are a momentum balance and (transient) mass and energy balances. +Independent states are either the pressure <i>p</i>, temperature <i>T</i>, and mass +fractions </i>X_i</i> or the pressure <i>p</i>, specific enthalpy <i>h</i>, and mass +fractions </i>X_i</i>. The most important equations can be found in the documentation +of the model +<a href=\"Modelica://SorpLib.Basics.Volumes.FluidVolumes.GasVaporMixtureVolume\">SorpLib.Basics.Volumes.FluidVolumes.GasVaporMixtureVolume</a>. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> + <li> + Ideal gas-vapor mixture + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to connect three medium flows. In this model, the mixing +properties are calculated via (dynamic) mass and energy balances. Hence, this model acts +like a PT1-element and can be used to break algebraic loops. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <li> + <i>idealGasVaporMixture</i>: + Defines if the medium is an ideal gas-vapor mixture and, thus, the governing + equations can be simplified. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_independentMassBalances</i>: + Defines the type of the independent mass balances. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has three dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i> , temperature <i>T</i>, and mass fractions <i>X_i</i> (recommended), or + </li> + <li> + pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions <i>X_i</i>. + </li> +</ul> +<p> +Note that this model does not have the pressure <i>p</i> as dynamic state if the +fluid property model is a single state model. +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end GasVaporMixtureTJunction; diff --git a/SorpLib/Components/Fittings/TJunctions/LiquidTJunction.mo b/SorpLib/Components/Fittings/TJunctions/LiquidTJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..b7bfe76e04c6f7c5e74f4888e2e47c603dff3a2e --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/LiquidTJunction.mo @@ -0,0 +1,331 @@ +within SorpLib.Components.Fittings.TJunctions; +model LiquidTJunction "Liquid T-junction element" + extends SorpLib.Components.Fittings.BaseClasses.PartialTJunction( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_c, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + final no_components=Medium.nX, + final pressureNoStateVariable = Medium.singleState, + final X_i_initial=ones(no_components), + final type_independentMassBalances= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + h_initial= + Medium.specificEnthalpy_pTX(p=p_initial, T=T_initial, X=Medium.reference_X), + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the calculation setup + // + parameter Boolean incompressibleLiquid = Medium.singleState + " = true, if medium is incompressible (i.e., partial derivative of specific + volume w.r.t. pressure at constant temperature is constant) and govering + equations are explicitly written for an incompressible fluid" + annotation (Dialog(tab="General", group="Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity at constant pressure"; + Modelica.Media.Common.IsobaricVolumeExpansionCoefficient beta + "Isobaric expnasion coefficient"; + Modelica.Media.Common.IsothermalCompressibility kappa + "Isothermal compressibility"; + Modelica.Media.Common.JouleThomsonCoefficient my + "Joule-Thomson coefficient"; + +equation + // + // Assertations + // + assert(no_components <= 1, + "The liquid volume model can only handel pure fluids (i.e., with one component)!", + level = AssertionLevel.error); + + assert(pressureNoStateVariable or not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + // + // Calculation of properties + // + if independentStateVariables == + SorpLib.Choices.IndependentVariablesVolume.pTX then + state = Medium.setState_pTX(p=p, T=T, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + else + state = Medium.setState_phX(p=p, h=h, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + T = Medium.temperature(state=state) + "Temperature"; + + end if; + + rho = Medium.density(state=state) + "Density"; + h_i = fill(h, no_components) + "Specific enthalpy of individual components: Liquid T-junction can handle + only one component"; + + cp = if ((independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + beta = if (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + kappa = if (not incompressibleLiquid and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp))) then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + my = if (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp))) then + v / cp * (beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + // + // Mass balance + // + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + if incompressibleLiquid then + dm_dtau = -V * rho * beta * der(T) + "Transient overall mass balance"; + + else + dm_dtau = V * rho * (kappa *der(p) - beta * der(T)) + "Transient overall mass balance"; + + end if; + + else + if incompressibleLiquid then + dm_dtau = -V * rho * beta * (my * der(p) + 1 / cp * der(h)) + "Transient overall mass balance"; + + else + dm_dtau = V * rho * ((kappa - beta * my) * der(p) - beta / cp * der(h)) + "Transient overall mass balance"; + + end if; + end if; + end if; + + // + // Energy balance + // + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + if neglectTermVp then + dU_dtau = u * dm_dtau + + m * (v * (1 - T * beta) * der(p) + + cp * der(T)) + "Transient energy balance"; + + else + if incompressibleLiquid then + dU_dtau = u * dm_dtau + + m * (-v * T * beta * der(p) + + (cp - p * v * beta) * der(T)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + + m * (v * (p * kappa - T * beta) * der(p) + + (cp - p * v * beta) * der(T)) + "Transient energy balance"; + + end if; + end if; + + else + if neglectTermVp then + dU_dtau = u * dm_dtau + m * der(h) + "Transient energy balance"; + + else + if incompressibleLiquid then + dU_dtau = u * dm_dtau + + m * ((1 - p * v * beta / cp) * der(h) - + v * (p * beta * my + 1) * der(p)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + + m * ((1 - p * v * beta / cp) * der(h) + + v * (p * (kappa - beta * my) - 1) * der(p)) + "Transient energy balance"; + + end if; + end if; + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a liquid T-junction element, applying a lumped modeling +approach. This T-junction is used to connect three liquid flows, thereby calculating +mixing properties via (transient) mass and energy balances. +</p> + +<h4>Main equations</h4> +<p> +The main equations are a momentum balance and (transient) mass and energy balances. +Independent states are either the pressure <i>p</i>, temperature <i>T</i>, and mass +fractions </i>X_i</i> or the pressure <i>p</i>, specific enthalpy <i>h</i>, and mass +fractions </i>X_i</i>. The most important equations can be found in the documentation +of the model +<a href=\"Modelica://SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume\">SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume</a>. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to connect three medium flows. In this model, the mixing +properties are calculated via (dynamic) mass and energy balances. Hence, this model acts +like a PT1-element and can be used to break algebraic loops. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <li> + <i>incompressibleLiquid</i>: + Defines if the medium is incompressible and the partial derivative of specific + volume w.r.t. pressure at constant temperature is constant, thus leading to + simplified governing equations. + </li> + <li> + <i>neglectTermVp</i>: + Defines if the term 'p*V' is neglected to calculate specific internal energy. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has three dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i> , temperature <i>T</i>, and mass fractions <i>X_i</i> (recommended), or + </li> + <li> + pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions <i>X_i</i>. + </li> +</ul> +<p> +Note that this model does not have the pressure <i>p</i> as dynamic state if the +fluid property model is a single state model. +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end LiquidTJunction; diff --git a/SorpLib/Components/Fittings/TJunctions/Tester/Test_GasMixtureTJunction.mo b/SorpLib/Components/Fittings/TJunctions/Tester/Test_GasMixtureTJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..657e1109706ce25b7a92d4a5f43c345811e001c8 --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/Tester/Test_GasMixtureTJunction.mo @@ -0,0 +1,106 @@ +within SorpLib.Components.Fittings.TJunctions.Tester; +model Test_GasMixtureTJunction + "Tester for the gas mixture T-junction element" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=293.15, + redeclare package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O) + "Fluid source a" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=270, + origin={0,-60}))); + SorpLib.Basics.Sources.Fluids.GasSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 200000, + m_flow_fixed=0, + T_fixed=303.15, + redeclare package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O) + "Fluid source b" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource fs_c( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=313.15, + X_fixed={0.7,0.1,0.1,0.1}, + redeclare package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O) + "Fluid source c" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.TJunctions.GasMixtureTJunction TJunction + "T-junction element" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow_a( + amplitude=1, + f=1/250, + offset=0) + "Input signal for mass flow rate at port a" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=270, + origin={0,-80}))); + Modelica.Blocks.Sources.Sine input_mFlow_c( + amplitude=-1, + f=1/250, + offset=0) "Input signal for mass flow rate at port c" + annotation (Placement(transformation(extent={{90,-10},{70,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, TJunction.port_a) annotation (Line( + points={{0,-60},{0,-7.8}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, TJunction.port_b) annotation (Line( + points={{-60,0},{-8,0}}, + color={244,125,35}, + thickness=1)); + connect(TJunction.port_c, fs_c.port) annotation (Line( + points={{8,0},{60,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_mFlow_a.y, fs_a.m_flow_input) annotation (Line(points={{0,-69},{ + 0,-66},{2,-66},{2,-61.2}}, color={0,0,127})); + connect(input_mFlow_c.y, fs_c.m_flow_input) + annotation (Line(points={{69,0},{66,0},{66,2},{61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the gas mixture T-junction element. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasMixtureTJunction; diff --git a/SorpLib/Components/Fittings/TJunctions/Tester/Test_GasTJunction.mo b/SorpLib/Components/Fittings/TJunctions/Tester/Test_GasTJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..821a1d7b09c1386b7113bf94a8ded30d68d80500 --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/Tester/Test_GasTJunction.mo @@ -0,0 +1,101 @@ +within SorpLib.Components.Fittings.TJunctions.Tester; +model Test_GasTJunction "Tester for the gas T-junction element" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=293.15, + redeclare package Medium = Media.IdealGases.N2) + "Fluid source a" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=270, + origin={0,-60}))); + SorpLib.Basics.Sources.Fluids.GasSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 200000, + m_flow_fixed=0, + T_fixed=303.15, + redeclare package Medium = Media.IdealGases.N2) + "Fluid source b" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.GasSource fs_c( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=313.15, + redeclare package Medium = Media.IdealGases.N2) + "Fluid source c" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.TJunctions.GasTJunction TJunction + "T-junction element" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow_a( + amplitude=1, + f=1/250, + offset=0) + "Input signal for mass flow rate at port a" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=270, + origin={0,-80}))); + Modelica.Blocks.Sources.Sine input_mFlow_c( + amplitude=-1, + f=1/250, + offset=0) "Input signal for mass flow rate at port c" + annotation (Placement(transformation(extent={{90,-10},{70,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, TJunction.port_a) annotation (Line( + points={{0,-60},{0,-7.8}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, TJunction.port_b) annotation (Line( + points={{-60,0},{-8,0}}, + color={244,125,35}, + thickness=1)); + connect(TJunction.port_c, fs_c.port) annotation (Line( + points={{8,0},{60,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_mFlow_a.y, fs_a.m_flow_input) annotation (Line(points={{0,-69},{ + 0,-66},{2,-66},{2,-61.2}}, color={0,0,127})); + connect(input_mFlow_c.y, fs_c.m_flow_input) + annotation (Line(points={{69,0},{66,0},{66,2},{61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the gas T-junction element. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasTJunction; diff --git a/SorpLib/Components/Fittings/TJunctions/Tester/Test_GasVaporMixtureTJunction.mo b/SorpLib/Components/Fittings/TJunctions/Tester/Test_GasVaporMixtureTJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..e21a3c9ba2be606d8f097dce36b5b5bf0e779dd5 --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/Tester/Test_GasVaporMixtureTJunction.mo @@ -0,0 +1,101 @@ +within SorpLib.Components.Fittings.TJunctions.Tester; +model Test_GasVaporMixtureTJunction + "Tester for the gas-vapor mixture T-junction element" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=293.15) + "Fluid source a" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=270, + origin={0,-60}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 200000, + m_flow_fixed=0, + T_fixed=303.15) + "Fluid source b" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_c( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=373.15, + X_fixed={0.25,0.25,0.25,0.25}) + "Fluid source c" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.TJunctions.GasVaporMixtureTJunction TJunction( + idealGasVaporMixture=true) + "T-junction element" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow_a( + amplitude=1, + f=1/250, + offset=0) + "Input signal for mass flow rate at port a" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=270, + origin={0,-80}))); + Modelica.Blocks.Sources.Sine input_mFlow_c( + amplitude=-1, + f=1/250, + offset=0) "Input signal for mass flow rate at port c" + annotation (Placement(transformation(extent={{90,-10},{70,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, TJunction.port_a) annotation (Line( + points={{0,-60},{0,-7.8}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, TJunction.port_b) annotation (Line( + points={{-60,0},{-8,0}}, + color={244,125,35}, + thickness=1)); + connect(TJunction.port_c, fs_c.port) annotation (Line( + points={{8,0},{60,0}}, + color={244,125,35}, + thickness=1)); + + connect(input_mFlow_a.y, fs_a.m_flow_input) annotation (Line(points={{0,-69},{ + 0,-66},{2,-66},{2,-61.2}}, color={0,0,127})); + connect(input_mFlow_c.y, fs_c.m_flow_input) + annotation (Line(points={{69,0},{66,0},{66,2},{61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the gas-vapor mixture T-junction element. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasVaporMixtureTJunction; diff --git a/SorpLib/Components/Fittings/TJunctions/Tester/Test_LiquidTJunction.mo b/SorpLib/Components/Fittings/TJunctions/Tester/Test_LiquidTJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..85e5d4aaeb84eb4436224dcc717640fa90b8da9a --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/Tester/Test_LiquidTJunction.mo @@ -0,0 +1,97 @@ +within SorpLib.Components.Fittings.TJunctions.Tester; +model Test_LiquidTJunction "Tester for the liquid T-junction element" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=293.15) " + Fluid source a" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=270, + origin={0,-60}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 200000, + T_fixed=303.15) + "Fluid source b" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_c( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=313.15) "Fluid source c" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.TJunctions.LiquidTJunction TJunction( + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial) + "T-junction element" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow_a( + amplitude=1, + f=1/250, + offset=0) + "Input signal for mass flow rate at port a" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=270, + origin={0,-80}))); + Modelica.Blocks.Sources.Sine input_mFlow_c( + amplitude=-1, + f=1/250, + offset=0) "Input signal for mass flow rate at port c" + annotation (Placement(transformation(extent={{90,-10},{70,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, TJunction.port_a) annotation (Line( + points={{0,-60},{0,-7.8}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, TJunction.port_b) annotation (Line( + points={{-60,0},{-8,0}}, + color={28,108,200}, + thickness=1)); + connect(TJunction.port_c, fs_c.port) annotation (Line( + points={{8,0},{60,0}}, + color={28,108,200}, + thickness=1)); + + connect(input_mFlow_a.y, fs_a.m_flow_input) annotation (Line(points={{0,-69},{ + 0,-66},{2,-66},{2,-61.2}}, color={0,0,127})); + connect(input_mFlow_c.y, fs_c.m_flow_input) + annotation (Line(points={{69,0},{66,0},{66,2},{61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the liquid T-junction element. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_LiquidTJunction; diff --git a/SorpLib/Components/Fittings/TJunctions/Tester/Test_VLETJunction.mo b/SorpLib/Components/Fittings/TJunctions/Tester/Test_VLETJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..1fcf03e7b0171e8d897b82201fbb5f23511d2c5a --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/Tester/Test_VLETJunction.mo @@ -0,0 +1,97 @@ +within SorpLib.Components.Fittings.TJunctions.Tester; +model Test_VLETJunction "Tester for the VLE T-junction element" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=293.15) " + Fluid source a" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=270, + origin={0,-60}))); + SorpLib.Basics.Sources.Fluids.VLESource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="bar") = 200000, + T_fixed=303.15) + "Fluid source b" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.VLESource fs_c( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=313.15) "Fluid source c" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Fittings.TJunctions.VLETJunction TJunction( + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial) + "T-junction element" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow_a( + amplitude=1, + f=1/250, + offset=0) + "Input signal for mass flow rate at port a" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=270, + origin={0,-80}))); + Modelica.Blocks.Sources.Sine input_mFlow_c( + amplitude=-1, + f=1/250, + offset=0) "Input signal for mass flow rate at port c" + annotation (Placement(transformation(extent={{90,-10},{70,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, TJunction.port_a) annotation (Line( + points={{0,-60},{0,-7.8}}, + color={0,140,72}, + thickness=1)); + connect(fs_b.port, TJunction.port_b) annotation (Line( + points={{-60,0},{-8,0}}, + color={0,140,72}, + thickness=1)); + connect(TJunction.port_c, fs_c.port) annotation (Line( + points={{8,0},{60,0}}, + color={0,140,72}, + thickness=1)); + + connect(input_mFlow_a.y, fs_a.m_flow_input) annotation (Line(points={{0,-69},{ + 0,-66},{2,-66},{2,-61.2}}, color={0,0,127})); + connect(input_mFlow_c.y, fs_c.m_flow_input) + annotation (Line(points={{69,0},{66,0},{66,2},{61.2,2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the VLE T-junction element. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end Test_VLETJunction; diff --git a/SorpLib/Components/Fittings/TJunctions/Tester/package.mo b/SorpLib/Components/Fittings/TJunctions/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..076cbc6c68d7238514992999be41ff61d0103fd8 --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/Tester/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Components.Fittings.TJunctions; +package Tester "Models to test and varify multi port models" + extends Modelica.Icons.ExamplesPackage; + + + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented T-junction +elements. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Fittings/TJunctions/Tester/package.order b/SorpLib/Components/Fittings/TJunctions/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c03fdd5138f52e7372ed874ba2ba037265d0f5cf --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/Tester/package.order @@ -0,0 +1,5 @@ +Test_LiquidTJunction +Test_GasTJunction +Test_GasMixtureTJunction +Test_GasVaporMixtureTJunction +Test_VLETJunction diff --git a/SorpLib/Components/Fittings/TJunctions/VLETJunction.mo b/SorpLib/Components/Fittings/TJunctions/VLETJunction.mo new file mode 100644 index 0000000000000000000000000000000000000000..e8d078c283cce6f464e8c68fbb67aaa004be8a43 --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/VLETJunction.mo @@ -0,0 +1,263 @@ +within SorpLib.Components.Fittings.TJunctions; +model VLETJunction "VLE T-junction element" + extends SorpLib.Components.Fittings.BaseClasses.PartialTJunction( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_c, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + final no_components=Medium.nX, + final pressureNoStateVariable = Medium.singleState, + final neglectTermVp = false, + final X_i_initial=ones(no_components), + final type_independentMassBalances= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + h_initial= + Medium.specificEnthalpy_pTX(p=p_initial, T=T_initial, X=Medium.reference_X), + type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with a two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of protected variables + // +protected + Medium.ThermodynamicState state + "Thermodynamic state required to calculate medium properties"; + + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity at constant pressure"; + Modelica.Media.Common.IsobaricVolumeExpansionCoefficient beta + "Isobaric expnasion coefficient"; + Modelica.Media.Common.IsothermalCompressibility kappa + "Isothermal compressibility"; + Modelica.Media.Common.JouleThomsonCoefficient my + "Joule-Thomson coefficient"; + +equation + // + // Assertations + // + assert(no_components <= 1, + "The VLE volume model can only handel pure fluids (i.e., with one component)!", + level = AssertionLevel.error); + + assert(pressureNoStateVariable or not ( + type_energyBalance<>SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + type_overallMassBalance==SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial), + "Steady-state mass balance combined with transient energy balance is not " + + "sound if the fluid volume is fixed!", + level = AssertionLevel.warning); + + // + // Calculation of properties + // + if independentStateVariables == + SorpLib.Choices.IndependentVariablesVolume.pTX then + state = Medium.setState_pTX(p=p, T=T, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + else + state = Medium.setState_phX(p=p, h=h, X=Medium.reference_X) + "Thermodynamic state required to calculate medium properties"; + T = Medium.temperature(state=state) + "Temperature"; + + end if; + + rho = Medium.density(state=state) + "Density"; + h_i = fill(h, no_components) + "Specific enthalpy of individual components: Liquid T-junction can handle + only one component"; + + cp = if ((independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.specificHeatCapacityCp(state=state) else 0 + "Specific heat capacity"; + beta = if (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial) or + (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isobaricExpansionCoefficient(state=state) else 0 + "Isobaric expnasion coefficient"; + kappa = if (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp)) then + Medium.isothermalCompressibility(state=state) else 0 + "Isothermal compressibility"; + my = if (independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.phX and + (type_overallMassBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial or + (type_energyBalance<> + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial and + not neglectTermVp))) then + v / cp * (beta * T - 1) else 0 + "Joule-Thomson coefficient"; + + // + // Mass balance + // + if type_overallMassBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dm_dtau = 0 + "Steady-state overall mass balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dm_dtau = V * rho * (kappa *der(p) - beta * der(T)) + "Transient overall mass balance"; + + else + dm_dtau = V * rho * ((kappa - beta * my) * der(p) - beta / cp * der(h)) + "Transient overall mass balance"; + + end if; + end if; + + // + // Energy balance + // + if type_energyBalance== + SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial then + dU_dtau = 0 + "Steady-state energy balance"; + + else + if independentStateVariables== + SorpLib.Choices.IndependentVariablesVolume.pTX then + dU_dtau = u * dm_dtau + m * (v * (p * kappa - T * beta) * der(p) + + (cp - p * v * beta) * der(T)) + "Transient energy balance"; + + else + dU_dtau = u * dm_dtau + m * ((1 - p * v * beta / cp) * der(h) + + v * (p * (kappa - beta * my) - 1) * der(p)) + "Transient energy balance"; + + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model represents a VLE T-junction element, applying a lumped modeling approach. +This T-junction is used to connect three VLE flows, thereby calculating mixing properties +via (transient) mass and energy balances. +</p> + +<h4>Main equations</h4> +<p> +The main equations are a momentum balance and (transient) mass and energy balances. +Independent states are either the pressure <i>p</i>, temperature <i>T</i>, and mass +fractions </i>X_i</i> or the pressure <i>p</i>, specific enthalpy <i>h</i>, and mass +fractions </i>X_i</i>. The most important equations can be found in the documentation +of the model +<a href=\"Modelica://SorpLib.Basics.Volumes.FluidVolumes.VLEVolume\">SorpLib.Basics.Volumes.FluidVolumes.VLEVolume</a>. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volume <i>V</i> + </li> + <li> + Homogenoues properties within the volume + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is typically used to connect three medium flows. In this model, the mixing +properties are calculated via (dynamic) mass and energy balances. Hence, this model acts +like a PT1-element and can be used to break algebraic loops. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>independentStateVariables</i>: + Defines independent state variables. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +<p> +Note that not all combinations of govering equation types are reasonable. Typically, +a transient mass balance is combined with a transient energy balance. +</p> + +<h4>Dynamics</h4> +<p> +This model has three dynamic state that can be selected (see options): +</p> +<ul> + <li> + Pressure <i>p</i> , temperature <i>T</i>, and mass fractions <i>X_i</i> (recommended), or + </li> + <li> + pressure <i>p</i>, specific enthalpy <i>h</i>, and mass fractions <i>X_i</i>. + </li> +</ul> +<p> +Note that this model does not have the pressure <i>p</i> as dynamic state if the +fluid property model is a single state model. +</p> +</html>", revisions="<html> +<ul> + <li> + December 21, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end VLETJunction; diff --git a/SorpLib/Components/Fittings/TJunctions/package.mo b/SorpLib/Components/Fittings/TJunctions/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..ccb863f2df73c474b1d6534dd6e148264290779a --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Fittings; +package TJunctions "Package containing T-junction elements" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains T-junction elements based on the Modelica Standard library +(MSL). These models may be used to connect three fluid flows. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end TJunctions; diff --git a/SorpLib/Components/Fittings/TJunctions/package.order b/SorpLib/Components/Fittings/TJunctions/package.order new file mode 100644 index 0000000000000000000000000000000000000000..8ae9319ba14570da6ac5b3065e0784b9224224cb --- /dev/null +++ b/SorpLib/Components/Fittings/TJunctions/package.order @@ -0,0 +1,6 @@ +LiquidTJunction +GasTJunction +GasMixtureTJunction +GasVaporMixtureTJunction +VLETJunction +Tester diff --git a/SorpLib/Components/Fittings/package.mo b/SorpLib/Components/Fittings/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a16b2e807fb247c9c3c416ed1118e99b43117c60 --- /dev/null +++ b/SorpLib/Components/Fittings/package.mo @@ -0,0 +1,39 @@ +within SorpLib.Components; +package Fittings "Adaptors for connections of fluid components and the regulation of fluid flow" + extends SorpLib.Icons.FittingsPackage; + + annotation (Documentation(info="<html> +<p> +This package includes various models for fittings that can handle (ideal) liquids, +ideal gases, ideal gas mixtures, ideal gas-vapor mixtures, and real substances (i.e., +with a two-phase region). The following fittings are implemented: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.InertiaInducers\">InertiaInducers</a>: + Inertia inducers may be used to describe the acceleration of a fluid caused by a + sudden pressure change, thus also allowing to break algebraic loops. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.MultiPorts\">MultiPorts</a>: + Multi port models may be used if several connections shall be made to one port. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.Resistors\">Resistors</a>: + Hydraulic resistors can be used to calculate pressure losses as a function of mass + flow rate and vice versa. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.Fittings.TJunctions\">TJunctions</a>: + T-junction models may be used to connect three fluid flows. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Fittings; diff --git a/SorpLib/Components/Fittings/package.order b/SorpLib/Components/Fittings/package.order new file mode 100644 index 0000000000000000000000000000000000000000..81198f009ec88646a0e03712f84459b5b9871f1e --- /dev/null +++ b/SorpLib/Components/Fittings/package.order @@ -0,0 +1,7 @@ +BaseClasses +Records +PressureLossCorrelations +InertiaInducers +MultiPorts +Resistors +TJunctions diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/AdsorberDP.mo b/SorpLib/Components/HeatExchanger/Adsorbers/AdsorberDP.mo new file mode 100644 index 0000000000000000000000000000000000000000..15a578f14e6b9924e9f452b4ab9268a492ac6bcf --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/AdsorberDP.mo @@ -0,0 +1,310 @@ +within SorpLib.Components.HeatExchanger.Adsorbers; +model AdsorberDP + "Closed adsorber with pressure-driven mass trasnfer and vapor volume" + extends SorpLib.Components.HeatExchanger.BaseClasses.PartialPureComponentAdsorber( + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + final no_components=MediumHX.nX, + final no_adsorptiveComponents=MediumAdsorptive.nX, + redeclare SorpLib.Components.Tubes.LiquidTube heatExchangerTubes( + redeclare package Medium = MediumHX, + redeclare model WallMaterial = WallMaterialHX), + redeclare SorpLib.Basics.Volumes.FluidVolumes.VLEVolume vaporVolume( + redeclare final package Medium = MediumAdsorptive, + final ms_flow_initial=m_flow_adsorptive_start, + final h_initial, + nPorts_cfp_xMinus=no_sorbentVolumes), + redeclare SorpLib.Basics.Volumes.SolidVolumes.SolidVolume casing( + redeclare final WallMaterialCS solidMedium, + redeclare final SorpLib.Basics.Volumes.Records.VolumeGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_wall_cas*geometry.no_hydraulicParallelTubes), + final T_initial=T_casingInitial, + final p=vaporVolume.fluidProperties.p, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX), + thermalConduction_casing1(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda)), + thermalConduction_casing2(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda))); + + // + // Definition of parameters regarding the media + // + replaceable model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = MediumAdsorptive) + "Working pair model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable package MediumHX = + Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid in the heat exchanger" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable package MediumAdsorptive = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of adsorptive" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model WallMaterialHX = + SorpLib.Media.Solids.MetalsAndMetalAlloys.Copper + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Heat exchanger wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable model WallMaterialCS = + Media.Solids.MetalsAndMetalAlloys.StainlessSteel_X5CrNi18_10 + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Casing wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding transport phenomena + // + replaceable model MassTransferCoefficient = + MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow + constrainedby + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + geometry=geometry) + "Model calculating the mass transfer coefficient" + annotation (Dialog(tab="Transport Phenomena", group="Mass Transfer"), + choicesAllMatching=true, + HideResult=true, + Evaluate=true); + + // + // Definition and instantiation of models + // + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureVLEVolume[no_sorbentVolumes] + sorbentVolumes( + redeclare each final package Medium = MediumAdsorptive, + redeclare each final model PureWorkingPairModel = WorkingPair, + redeclare each final SorpLib.Basics.Volumes.Records.VolumeGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_particles*geometry.no_hydraulicParallelTubes), + each final m_sor_initial=m_sorInitial/geometry.no_sorbentVolumes, + each final T_initial=T_sorInitial, + each final x_initial=x_sorInitial, + each final msor_flow_initialX, + each final md_flow_initialX, + each final useAdsorbatePorts=false, + each final useDiffusivePorts=false, + each final useHeatPorts=false, + each final useHeatPortsX=false, + each final useHeatPortsY=false, + each final useHeatPortsZ=false, + each final ms_flow_initial=m_flow_adsorptive_start, + each final type_adsorbentMassBalance=type_overallMassBalance, + each final type_adsorptMassBalance=type_overallMassBalance, + each final type_energyBalance=type_energyBalance, + each final avoid_events=avoid_events, + each calcUptakeAveragedProperties=false, + each independentStateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT, + each nSorptionPorts=1) + "Sorbent volumes" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={50,-30}))); + + SorpLib.Components.HeatTransfer.ClosedAdsorberHeatTransfer[min(no_sorbentVolumes,no_wallVolumes)] + heatTransfer_HeatExchangerToSorbentVolumes( + each final n_a=if no_wallVolumes > no_sorbentVolumes then factorDiscretization + else 1, + each final n_b=if no_wallVolumes < no_sorbentVolumes then factorDiscretization + else 1, + each final calculateFluidProperties=calcFluidTransportProperties, + redeclare each final model HeatTransferCoefficient = + VV_HeatExchanger, + final fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=sorbentVolumes.adsorbateProperties.p, + T=sorbentVolumes.adsorbateProperties.T, + rho=1 ./ sorbentVolumes.workingPair.medium_sorbent.state_variables.v, + cp=sorbentVolumes.workingPair.medium_sorbent.additional_variables.c, + eta=0, + lambda=sorbentVolumes.workingPair.medium_sorbent.additional_variables.lambda), + each final geometry=geometry) + "Heat transfer from heat exchanger to sorbent volumes" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={50,-54}))); + + SorpLib.Components.MassTransfer.VLEMassTransfers.ClosedAdsorberMassTransferDP[no_sorbentVolumes] massTransfer( + redeclare each final package Medium =MediumAdsorptive, + redeclare each final model MassTransferCoefficient =MassTransferCoefficient, + each final canBeActivated=false, + each final isFlapValve=false, + each final isFlowAB, + each final offset_dp, + each final calculateFluidProperties=calcFluidTransportProperties, + each final m_flow_start=m_flow_adsorptive_start, + each final avoid_events=avoid_events, + each final m_flow_small=m_flow_small, + each final noDiff=noDiff) + "Mass transfer between sorbent volumes and gas volume" + annotation (Placement(transformation(extent={{40,-20},{60,0}}))); + + // + // Definition of variables + // + SorpLib.Components.HeatExchanger.Records.SummaryClosedAdsorber summary( + final p_vapor=vaporVolume.fluidProperties.p, + final T_vapor=vaporVolume.fluidProperties.T, + final rho_vapor=1/vaporVolume.fluidProperties.v, + final mass_vapor=vaporVolume.m, + final p_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.p)/ + no_sorbentVolumes, + final T_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.T)/ + no_sorbentVolumes, + final x_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.x_i[1])/ + no_sorbentVolumes, + final mass_adsorpt=summary.x_adsorbate_avg*m_sorInitial, + final p_liq_inlet=heatExchangerTubes.state_a.p, + final p_liq_outlet=heatExchangerTubes.state_b.p, + final p_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.p)/ + no_fluidVolumes, + final T_liq_inlet=heatExchangerTubes.state_a.T, + final T_liq_outlet=heatExchangerTubes.state_b.T, + final T_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.T)/ + no_fluidVolumes, + final T_wall_avg=sum(heatExchangerTubes.wallVolumes.T)/ + no_wallVolumes, + final m_flow_liq_inlet=port_a.m_flow, + final m_flow_liq_outlet=port_b.m_flow, + final m_flow_evaporator=evaporatorPort.m_flow, + final m_flow_condenser=condenserPort.m_flow, + final m_flow_massRecovery=sum(massRecoveryPorts.m_flow), + final Q_flow_wallToSorbent=heatExchangerTubes.Q_flow_wallHP, + final Q_flow_fluidWall=heatExchangerTubes.Q_flow_fluidWall, + final DH_liquid=heatExchangerTubes.DH_flow) + "Summary record"; + +equation + // + // Connections of fluid ports + // + connect(massTransfer.port_b, sorbentVolumes.fp_sorption[1]) annotation (Line( + points={{58,-10},{70,-10},{70,-44},{51.6,-44},{51.6,-34.4}}, + color={0,0,0})); + connect(massTransfer.port_a, vaporVolume.cfp_xMinus) annotation (Line(points={{42.2, + -10},{20,-10},{20,-20},{-1.8,-20},{-1.8,-4.2}}, color={0,0,0})); + + // + // Connection of heat ports + // + if no_sorbentVolumes == no_wallVolumes then + // + // Identical discretization number + // + connect(heatExchangerTubes.hp_wall, + heatTransfer_HeatExchangerToSorbentVolumes.hp_a[1]) annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_HeatExchangerToSorbentVolumes.hp_b[1], + sorbentVolumes.hp_sorption) annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + + elseif no_wallVolumes > no_sorbentVolumes then + // + // More wall volumes than sorbent volumes + // + for i in 1:no_sorbentVolumes loop + connect(heatExchangerTubes.hp_wall[1+(i-1)*factorDiscretization:i*factorDiscretization], + heatTransfer_HeatExchangerToSorbentVolumes[i].hp_a[1:factorDiscretization]) + annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + end for; + + connect(heatTransfer_HeatExchangerToSorbentVolumes.hp_b[1], + sorbentVolumes.hp_sorption) annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + + else + // + // More sorbent volumes than wall volumes + // + connect(heatExchangerTubes.hp_wall, + heatTransfer_HeatExchangerToSorbentVolumes.hp_a[1]) annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + + for i in 1:no_wallVolumes loop + connect(heatTransfer_HeatExchangerToSorbentVolumes[i].hp_b[1:factorDiscretization], + sorbentVolumes[1+(i-1)*factorDiscretization:i*factorDiscretization].hp_sorption) + annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + end for; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +TO BE ADDED! +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + Major adaptations due to restructering of the library. + </li> + <li> + January 19, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorberDP; diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/AdsorberDX.mo b/SorpLib/Components/HeatExchanger/Adsorbers/AdsorberDX.mo new file mode 100644 index 0000000000000000000000000000000000000000..0bbcc30d906ea7280fea9944224139473e45067a --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/AdsorberDX.mo @@ -0,0 +1,312 @@ +within SorpLib.Components.HeatExchanger.Adsorbers; +model AdsorberDX + "Closed adsorber with loading-driven mass trasnfer and vapor volume" + extends SorpLib.Components.HeatExchanger.BaseClasses.PartialPureComponentAdsorber( + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + final no_components=MediumHX.nX, + final no_adsorptiveComponents=MediumAdsorptive.nX, + redeclare SorpLib.Components.Tubes.LiquidTube heatExchangerTubes( + redeclare package Medium = MediumHX, + redeclare model WallMaterial = WallMaterialHX), + redeclare SorpLib.Basics.Volumes.FluidVolumes.VLEVolume vaporVolume( + redeclare final package Medium = MediumAdsorptive, + final ms_flow_initial=m_flow_adsorptive_start, + final h_initial, + nPorts_cfp_xMinus=no_sorbentVolumes), + redeclare SorpLib.Basics.Volumes.SolidVolumes.SolidVolume casing( + redeclare final WallMaterialCS solidMedium, + redeclare final SorpLib.Basics.Volumes.Records.VolumeGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_wall_cas*geometry.no_hydraulicParallelTubes), + final T_initial=T_casingInitial, + final p=vaporVolume.fluidProperties.p, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX), + thermalConduction_casing1(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda)), + thermalConduction_casing2(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda))); + + // + // Definition of parameters regarding the media + // + replaceable model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = MediumAdsorptive) + "Working pair model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable package MediumHX = + Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid in the heat exchanger" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable package MediumAdsorptive = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of adsorptive" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model WallMaterialHX = + SorpLib.Media.Solids.MetalsAndMetalAlloys.Copper + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Heat exchanger wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable model WallMaterialCS = + Media.Solids.MetalsAndMetalAlloys.StainlessSteel_X5CrNi18_10 + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Casing wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding transport phenomena + // + replaceable model MassTransferCoefficient = + SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven.GlueckaufArrhenius + constrainedby + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDX( + geometry=geometry) + "Model calculating the mass transfer coefficient" + annotation (Dialog(tab="Transport Phenomena", group="Mass Transfer"), + choicesAllMatching=true, + HideResult=true, + Evaluate=true); + + // + // Definition and instantiation of models + // + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureVLEVolume[no_sorbentVolumes] + sorbentVolumes( + redeclare each final package Medium = MediumAdsorptive, + redeclare each final model PureWorkingPairModel = WorkingPair, + redeclare each final SorpLib.Basics.Volumes.Records.VolumeGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_particles*geometry.no_hydraulicParallelTubes), + each final m_sor_initial=m_sorInitial/geometry.no_sorbentVolumes, + each final T_initial=T_sorInitial, + each final x_initial=x_sorInitial, + each final msor_flow_initialX, + each final md_flow_initialX, + each final useAdsorbatePorts=false, + each final useDiffusivePorts=false, + each final useHeatPorts=false, + each final useHeatPortsX=false, + each final useHeatPortsY=false, + each final useHeatPortsZ=false, + each final ms_flow_initial=m_flow_adsorptive_start, + each final type_adsorbentMassBalance=type_overallMassBalance, + each final type_adsorptMassBalance=type_overallMassBalance, + each final type_energyBalance=type_energyBalance, + each final avoid_events=avoid_events, + each calcUptakeAveragedProperties=false, + each independentStateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT, + each nSorptionPorts=1) + "Sorbent volumes" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={50,-30}))); + + SorpLib.Components.HeatTransfer.ClosedAdsorberHeatTransfer[min(no_sorbentVolumes,no_wallVolumes)] + heatTransfer_HeatExchangerToSorbentVolumes( + each final n_a=if no_wallVolumes > no_sorbentVolumes then factorDiscretization + else 1, + each final n_b=if no_wallVolumes < no_sorbentVolumes then factorDiscretization + else 1, + each final calculateFluidProperties=calcFluidTransportProperties, + redeclare each final model HeatTransferCoefficient = + VV_HeatExchanger, + final fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=sorbentVolumes.adsorbateProperties.p, + T=sorbentVolumes.adsorbateProperties.T, + rho=1 ./ sorbentVolumes.workingPair.medium_sorbent.state_variables.v, + cp=sorbentVolumes.workingPair.medium_sorbent.additional_variables.c, + eta=0, + lambda=sorbentVolumes.workingPair.medium_sorbent.additional_variables.lambda), + each final geometry=geometry) + "Heat transfer from heat exchanger to sorbent volumes" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={50,-54}))); + + SorpLib.Components.MassTransfer.VLEMassTransfers.ClosedAdsorberMassTransferDX[no_sorbentVolumes] massTransfer( + redeclare each final package Medium =MediumAdsorptive, + redeclare each final model MassTransferCoefficient =MassTransferCoefficient, + final x_adsorpt_input=sorbentVolumes.x, + final T_adsorpt_input=sorbentVolumes.T, + each final canBeActivated=false, + each final isFlapValve=false, + each final isFlowAB, + each final offset_dp, + each final calculateFluidProperties=calcFluidTransportProperties, + each final m_flow_start=m_flow_adsorptive_start, + each final avoid_events=avoid_events, + each final m_flow_small=m_flow_small, + each final noDiff=noDiff) + "Mass transfer between sorbent volumes and gas volume" + annotation (Placement(transformation(extent={{40,-20},{60,0}}))); + + // + // Definition of variables + // + SorpLib.Components.HeatExchanger.Records.SummaryClosedAdsorber summary( + final p_vapor=vaporVolume.fluidProperties.p, + final T_vapor=vaporVolume.fluidProperties.T, + final rho_vapor=1/vaporVolume.fluidProperties.v, + final mass_vapor=vaporVolume.m, + final p_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.p)/ + no_sorbentVolumes, + final T_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.T)/ + no_sorbentVolumes, + final x_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.x_i[1])/ + no_sorbentVolumes, + final mass_adsorpt=summary.x_adsorbate_avg*m_sorInitial, + final p_liq_inlet=heatExchangerTubes.state_a.p, + final p_liq_outlet=heatExchangerTubes.state_b.p, + final p_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.p)/ + no_fluidVolumes, + final T_liq_inlet=heatExchangerTubes.state_a.T, + final T_liq_outlet=heatExchangerTubes.state_b.T, + final T_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.T)/ + no_fluidVolumes, + final T_wall_avg=sum(heatExchangerTubes.wallVolumes.T)/ + no_wallVolumes, + final m_flow_liq_inlet=port_a.m_flow, + final m_flow_liq_outlet=port_b.m_flow, + final m_flow_evaporator=evaporatorPort.m_flow, + final m_flow_condenser=condenserPort.m_flow, + final m_flow_massRecovery=sum(massRecoveryPorts.m_flow), + final Q_flow_wallToSorbent=heatExchangerTubes.Q_flow_wallHP, + final Q_flow_fluidWall=heatExchangerTubes.Q_flow_fluidWall, + final DH_liquid=heatExchangerTubes.DH_flow) + "Summary record"; + +equation + // + // Connections of fluid ports + // + connect(massTransfer.port_b, sorbentVolumes.fp_sorption[1]) annotation (Line( + points={{58,-10},{70,-10},{70,-44},{51.6,-44},{51.6,-34.4}}, + color={0,0,0})); + connect(massTransfer.port_a, vaporVolume.cfp_xMinus) annotation (Line(points={{42.2, + -10},{20,-10},{20,-20},{-1.8,-20},{-1.8,-4.2}}, color={0,0,0})); + + // + // Connection of heat ports + // + if no_sorbentVolumes == no_wallVolumes then + // + // Identical discretization number + // + connect(heatExchangerTubes.hp_wall, + heatTransfer_HeatExchangerToSorbentVolumes.hp_a[1]) annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_HeatExchangerToSorbentVolumes.hp_b[1], + sorbentVolumes.hp_sorption) annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + + elseif no_wallVolumes > no_sorbentVolumes then + // + // More wall volumes than sorbent volumes + // + for i in 1:no_sorbentVolumes loop + connect(heatExchangerTubes.hp_wall[1+(i-1)*factorDiscretization:i*factorDiscretization], + heatTransfer_HeatExchangerToSorbentVolumes[i].hp_a[1:factorDiscretization]) + annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + end for; + + connect(heatTransfer_HeatExchangerToSorbentVolumes.hp_b[1], + sorbentVolumes.hp_sorption) annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + + else + // + // More sorbent volumes than wall volumes + // + connect(heatExchangerTubes.hp_wall, + heatTransfer_HeatExchangerToSorbentVolumes.hp_a[1]) annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + + for i in 1:no_wallVolumes loop + connect(heatTransfer_HeatExchangerToSorbentVolumes[i].hp_b[1:factorDiscretization], + sorbentVolumes[1+(i-1)*factorDiscretization:i*factorDiscretization].hp_sorption) + annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + end for; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +TO BE ADDED! +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + Major adaptations due to restructering of the library. + </li> + <li> + January 19, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorberDX; diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/SimpleAdsorberDP.mo b/SorpLib/Components/HeatExchanger/Adsorbers/SimpleAdsorberDP.mo new file mode 100644 index 0000000000000000000000000000000000000000..2effdcc66ba6ca91e49cd5f5dd36b3d121187548 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/SimpleAdsorberDP.mo @@ -0,0 +1,375 @@ +within SorpLib.Components.HeatExchanger.Adsorbers; +model SimpleAdsorberDP + "Closed adsorber with pressure-driven mass transfer and without a vapor volume" + extends + SorpLib.Components.HeatExchanger.BaseClasses.PartialPureSimpleComponentAdsorber( + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + final no_components=MediumHX.nX, + final no_adsorptiveComponents=MediumAdsorptive.nX, + redeclare SorpLib.Components.Fittings.MultiPorts.VLEMultiPort evaporatorSplitter(redeclare + final package Medium = MediumAdsorptive, no_ports_b=no_sorbentVolumes), + redeclare SorpLib.Components.Fittings.MultiPorts.VLEMultiPort condenserSplitter(redeclare + final package Medium = MediumAdsorptive, no_ports_b=no_sorbentVolumes), + redeclare SorpLib.Components.Fittings.MultiPorts.VLEMultiPort massRecoverySplitter(redeclare + final package Medium = MediumAdsorptive, no_ports_b=no_sorbentVolumes), + redeclare SorpLib.Components.Tubes.LiquidTube heatExchangerTubes( + redeclare package Medium = MediumHX, + redeclare model WallMaterial = WallMaterialHX), + redeclare SorpLib.Basics.Volumes.SolidVolumes.SolidVolume casing( + redeclare final WallMaterialCS solidMedium, + redeclare final SorpLib.Basics.Volumes.Records.VolumeGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_wall_cas*geometry.no_hydraulicParallelTubes), + final T_initial=T_casingInitial, + final p=summary.p_adsorbate_avg, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX), + thermalConduction_casing1(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda)), + thermalConduction_casing2(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda))); + + // + // Definition of parameters regarding the media + // + replaceable model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = MediumAdsorptive) + "Working pair model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable package MediumHX = + Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid in the heat exchanger" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable package MediumAdsorptive = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of adsorptive" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model WallMaterialHX = + SorpLib.Media.Solids.MetalsAndMetalAlloys.Copper + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Heat exchanger wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable model WallMaterialCS = + Media.Solids.MetalsAndMetalAlloys.StainlessSteel_X5CrNi18_10 + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Casing wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding transport phenomena + // + replaceable model MassTransferCoefficientCondenser = + MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow + constrainedby + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + geometry=geometry) + "Model calculating the mass transfer coefficient at the condenser port" + annotation (Dialog(tab="Transport Phenomena", group="Mass Transfer"), + choicesAllMatching=true, + HideResult=true, + Evaluate=true); + replaceable model MassTransferCoefficientEvaporator = + MassTransferCoefficientCondenser + constrainedby + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + geometry=geometry) + "Model calculating the mass transfer coefficient at the evaporator port" + annotation (Dialog(tab="Transport Phenomena", group="Mass Transfer"), + choicesAllMatching=true, + HideResult=true, + Evaluate=true); + + // + // Definition and instantiation of models + // + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureVLEVolume[no_sorbentVolumes] + sorbentVolumes( + redeclare each final package Medium = MediumAdsorptive, + redeclare each final model PureWorkingPairModel = WorkingPair, + redeclare each final SorpLib.Basics.Volumes.Records.VolumeGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_particles*geometry.no_hydraulicParallelTubes), + each final m_sor_initial=m_sorInitial/geometry.no_sorbentVolumes, + each final T_initial=T_sorInitial, + each final x_initial=x_sorInitial, + each final msor_flow_initialX, + each final md_flow_initialX, + each final useAdsorbatePorts=false, + each final useDiffusivePorts=false, + each final useHeatPorts=false, + each final useHeatPortsX=false, + each final useHeatPortsY=false, + each final useHeatPortsZ=false, + each final ms_flow_initial=m_flow_adsorptive_start, + each final type_adsorbentMassBalance=type_overallMassBalance, + each final type_adsorptMassBalance=type_overallMassBalance, + each final type_energyBalance=type_energyBalance, + each final avoid_events=avoid_events, + each calcUptakeAveragedProperties=false, + each independentStateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT, + each nSorptionPorts=if useMassRecoveryPorts then 3 else 2) + "Sorbent volumes" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={50,-30}))); + + SorpLib.Components.HeatTransfer.ClosedAdsorberHeatTransfer[min(no_sorbentVolumes,no_wallVolumes)] + heatTransfer_HeatExchangerToSorbentVolumes( + each final n_a=if no_wallVolumes > no_sorbentVolumes then factorDiscretization + else 1, + each final n_b=if no_wallVolumes < no_sorbentVolumes then factorDiscretization + else 1, + each final calculateFluidProperties=calcFluidTransportProperties, + redeclare each final model HeatTransferCoefficient = + VV_HeatExchanger, + final fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=sorbentVolumes.adsorbateProperties.p, + T=sorbentVolumes.adsorbateProperties.T, + rho=1 ./ sorbentVolumes.workingPair.medium_sorbent.state_variables.v, + cp=sorbentVolumes.workingPair.medium_sorbent.additional_variables.c, + eta=0, + lambda=sorbentVolumes.workingPair.medium_sorbent.additional_variables.lambda), + each final geometry=geometry) + "Heat transfer from heat exchanger to sorbent volumes" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={50,-54}))); + + SorpLib.Components.MassTransfer.VLEMassTransfers.ClosedAdsorberMassTransferDP[ + no_sorbentVolumes] massTransferCondenser( + redeclare each final package Medium = MediumAdsorptive, + redeclare each final model MassTransferCoefficient = + MassTransferCoefficientCondenser, + each isFlapValve=true, + each isFlowAB=false, + each final calculateFluidProperties=calcFluidTransportProperties, + each final m_flow_start=m_flow_adsorptive_start, + each final avoid_events=avoid_events, + each final m_flow_small=m_flow_small, + each final noDiff=noDiff) + "Mass transfer between sorbent volumes and condenser port" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={60,0}))); + SorpLib.Components.MassTransfer.VLEMassTransfers.ClosedAdsorberMassTransferDP[ + no_sorbentVolumes] massTransferEvaporator( + redeclare each final package Medium = MediumAdsorptive, + redeclare each final model MassTransferCoefficient = + MassTransferCoefficientEvaporator, + each isFlapValve=true, + each isFlowAB=true, + each final calculateFluidProperties=calcFluidTransportProperties, + each final m_flow_start=m_flow_adsorptive_start, + each final avoid_events=avoid_events, + each final m_flow_small=m_flow_small, + each final noDiff=noDiff) + "Mass transfer between sorbent volumes and evaporator port" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,0}))); + + // + // Definition of variables + // + SorpLib.Components.HeatExchanger.Records.SummarySimpleClosedAdsorber summary( + final p_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.p)/ + no_sorbentVolumes, + final T_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.T)/ + no_sorbentVolumes, + final x_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.x_i[1])/ + no_sorbentVolumes, + final mass_adsorpt=summary.x_adsorbate_avg*m_sorInitial, + final p_liq_inlet=heatExchangerTubes.state_a.p, + final p_liq_outlet=heatExchangerTubes.state_b.p, + final p_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.p)/ + no_fluidVolumes, + final T_liq_inlet=heatExchangerTubes.state_a.T, + final T_liq_outlet=heatExchangerTubes.state_b.T, + final T_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.T)/ + no_fluidVolumes, + final T_wall_avg=sum(heatExchangerTubes.wallVolumes.T)/ + no_wallVolumes, + final m_flow_liq_inlet=port_a.m_flow, + final m_flow_liq_outlet=port_b.m_flow, + final m_flow_evaporator=evaporatorPort.m_flow, + final m_flow_condenser=condenserPort.m_flow, + final m_flow_massRecovery=sum({sum(sorbentVolumes[i].fp_sorption.m_flow) + for i in 1:no_sorbentVolumes}) + evaporatorPort.m_flow+condenserPort.m_flow, + final Q_flow_wallToSorbent=heatExchangerTubes.Q_flow_wallHP, + final Q_flow_fluidWall=heatExchangerTubes.Q_flow_fluidWall, + final DH_liquid=heatExchangerTubes.DH_flow) + "Summary record"; + +equation + // + // Connections of fluid portsuseMassRecoveryPorts + // + connect(massTransferCondenser.port_b, sorbentVolumes.fp_sorption[1]) + annotation (Line(points={{60,-8},{60,-16},{70,-16},{70,-44},{51.6,-44},{51.6, + -34.4}}, color={0,0,0})); + connect(massTransferEvaporator.port_b, sorbentVolumes.fp_sorption[2]) + annotation (Line(points={{0,-8},{0,-16},{70,-16},{70,-44},{51.6,-44},{51.6,-34.4}}, + color={0,0,0})); + + if useMassRecoveryPorts then + connect(massRecoverySplitter.port_b, sorbentVolumes.fp_sorption[3]) + annotation (Line(points={{0,-8},{0,-16},{70,-16},{70,-44},{51.6,-44},{51.6,-34.4}}, + color={0,0,0})); + end if; + + connect(evaporatorPort, evaporatorSplitter.port_a) annotation (Line( + points={{-100,40},{0,40},{0,36}}, + color={0,140,72}, + thickness=1)); + connect(condenserPort, condenserSplitter.port_a) annotation (Line( + points={{100,40},{60,40},{60,36}}, + color={0,140,72}, + thickness=1)); + connect(massTransferEvaporator.port_a, evaporatorSplitter.ports_b) + annotation (Line( + points={{0,7.8},{0,24}}, + color={0,140,72}, + thickness=1)); + connect(massTransferCondenser.port_a, condenserSplitter.ports_b) annotation ( + Line( + points={{60,7.8},{60,24}}, + color={0,140,72}, + thickness=1)); + + // + // Connection of heat ports + // + if no_sorbentVolumes == no_wallVolumes then + // + // Identical discretization number + // + connect(heatExchangerTubes.hp_wall, + heatTransfer_HeatExchangerToSorbentVolumes.hp_a[1]) annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_HeatExchangerToSorbentVolumes.hp_b[1], + sorbentVolumes.hp_sorption) annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + + elseif no_wallVolumes > no_sorbentVolumes then + // + // More wall volumes than sorbent volumes + // + for i in 1:no_sorbentVolumes loop + connect(heatExchangerTubes.hp_wall[1+(i-1)*factorDiscretization:i*factorDiscretization], + heatTransfer_HeatExchangerToSorbentVolumes[i].hp_a[1:factorDiscretization]) + annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + end for; + + connect(heatTransfer_HeatExchangerToSorbentVolumes.hp_b[1], + sorbentVolumes.hp_sorption) annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + + else + // + // More sorbent volumes than wall volumes + // + connect(heatExchangerTubes.hp_wall, + heatTransfer_HeatExchangerToSorbentVolumes.hp_a[1]) annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + + for i in 1:no_wallVolumes loop + connect(heatTransfer_HeatExchangerToSorbentVolumes[i].hp_b[1:factorDiscretization], + sorbentVolumes[1+(i-1)*factorDiscretization:i*factorDiscretization].hp_sorption) + annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + end for; + end if; + + connect(heatTransfer_sorbentVolumesToCasing.hp_a, sorbentVolumes.hp_sorption) + annotation (Line( + points={{-24,0},{-20,0},{-20,-20},{20,-20},{20,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + + // + // Annotations + // + connect(massRecoveryPorts, massRecoverySplitter.port_a) annotation (Line( + points={{0,60},{30,60},{30,36}}, + color={0,140,72}, + thickness=1)); + annotation (Documentation(info="<html> +<p> +TO BE ADDED! +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + Major adaptations due to restructering of the library. + </li> + <li> + January 19, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SimpleAdsorberDP; diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/SimpleAdsorberDX.mo b/SorpLib/Components/HeatExchanger/Adsorbers/SimpleAdsorberDX.mo new file mode 100644 index 0000000000000000000000000000000000000000..288624c15447f29552fd7c5d8415093ac4935cb3 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/SimpleAdsorberDX.mo @@ -0,0 +1,374 @@ +within SorpLib.Components.HeatExchanger.Adsorbers; +model SimpleAdsorberDX + "Closed adsorber with loading-driven mass transfer and without a vapor volume" + extends + SorpLib.Components.HeatExchanger.BaseClasses.PartialPureSimpleComponentAdsorber( + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + final no_components=MediumHX.nX, + final no_adsorptiveComponents=MediumAdsorptive.nX, + redeclare SorpLib.Components.Fittings.MultiPorts.VLEMultiPort evaporatorSplitter(redeclare + final package Medium = MediumAdsorptive, no_ports_b=no_sorbentVolumes), + redeclare SorpLib.Components.Fittings.MultiPorts.VLEMultiPort condenserSplitter(redeclare + final package Medium = MediumAdsorptive, no_ports_b=no_sorbentVolumes), + redeclare SorpLib.Components.Fittings.MultiPorts.VLEMultiPort massRecoverySplitter(redeclare + final package Medium = MediumAdsorptive, no_ports_b=no_sorbentVolumes), + redeclare SorpLib.Components.Tubes.LiquidTube heatExchangerTubes( + redeclare package Medium = MediumHX, + redeclare model WallMaterial = WallMaterialHX), + redeclare SorpLib.Basics.Volumes.SolidVolumes.SolidVolume casing( + redeclare final WallMaterialCS solidMedium, + redeclare final SorpLib.Basics.Volumes.Records.VolumeGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_wall_cas*geometry.no_hydraulicParallelTubes), + final T_initial=T_casingInitial, + final p=summary.p_adsorbate_avg, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX), + thermalConduction_casing1(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda)), + thermalConduction_casing2(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda))); + + // + // Definition of parameters regarding the media + // + replaceable model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = MediumAdsorptive) + "Working pair model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable package MediumHX = + Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid in the heat exchanger" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable package MediumAdsorptive = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of adsorptive" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model WallMaterialHX = + SorpLib.Media.Solids.MetalsAndMetalAlloys.Copper + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Heat exchanger wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable model WallMaterialCS = + Media.Solids.MetalsAndMetalAlloys.StainlessSteel_X5CrNi18_10 + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Casing wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding transport phenomena + // + replaceable model MassTransferCoefficientCondenser = + SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven.GlueckaufArrhenius + constrainedby + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDX( + geometry=geometry) + "Model calculating the mass transfer coefficient at the condenser port" + annotation (Dialog(tab="Transport Phenomena", group="Mass Transfer"), + choicesAllMatching=true, + HideResult=true, + Evaluate=true); + replaceable model MassTransferCoefficientEvaporator = + MassTransferCoefficientCondenser + constrainedby + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDX( + geometry=geometry) + "Model calculating the mass transfer coefficient at the evaporator port" + annotation (Dialog(tab="Transport Phenomena", group="Mass Transfer"), + choicesAllMatching=true, + HideResult=true, + Evaluate=true); + + // + // Definition and instantiation of models + // + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureVLEVolume[no_sorbentVolumes] + sorbentVolumes( + redeclare each final package Medium = MediumAdsorptive, + redeclare each final model PureWorkingPairModel = WorkingPair, + redeclare each final SorpLib.Basics.Volumes.Records.VolumeGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_particles*geometry.no_hydraulicParallelTubes), + each final m_sor_initial=m_sorInitial/geometry.no_sorbentVolumes, + each final T_initial=T_sorInitial, + each final x_initial=x_sorInitial, + each final msor_flow_initialX, + each final md_flow_initialX, + each final useAdsorbatePorts=false, + each final useDiffusivePorts=false, + each final useHeatPorts=false, + each final useHeatPortsX=false, + each final useHeatPortsY=false, + each final useHeatPortsZ=false, + each final ms_flow_initial=m_flow_adsorptive_start, + each final type_adsorbentMassBalance=type_overallMassBalance, + each final type_adsorptMassBalance=type_overallMassBalance, + each final type_energyBalance=type_energyBalance, + each final avoid_events=avoid_events, + each calcUptakeAveragedProperties=false, + each independentStateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT, + each nSorptionPorts=if useMassRecoveryPorts then 3 else 2) + "Sorbent volumes" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={50,-30}))); + + SorpLib.Components.HeatTransfer.ClosedAdsorberHeatTransfer[min(no_sorbentVolumes,no_wallVolumes)] + heatTransfer_HeatExchangerToSorbentVolumes( + each final n_a=if no_wallVolumes > no_sorbentVolumes then factorDiscretization + else 1, + each final n_b=if no_wallVolumes < no_sorbentVolumes then factorDiscretization + else 1, + each final calculateFluidProperties=calcFluidTransportProperties, + redeclare each final model HeatTransferCoefficient = + VV_HeatExchanger, + final fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=sorbentVolumes.adsorbateProperties.p, + T=sorbentVolumes.adsorbateProperties.T, + rho=1 ./ sorbentVolumes.workingPair.medium_sorbent.state_variables.v, + cp=sorbentVolumes.workingPair.medium_sorbent.additional_variables.c, + eta=0, + lambda=sorbentVolumes.workingPair.medium_sorbent.additional_variables.lambda), + each final geometry=geometry) + "Heat transfer from heat exchanger to sorbent volumes" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={50,-54}))); + + SorpLib.Components.MassTransfer.VLEMassTransfers.ClosedAdsorberMassTransferDX[ + no_sorbentVolumes] massTransferCondenser( + redeclare each final package Medium =MediumAdsorptive, + final x_adsorpt_input=sorbentVolumes.x, + final T_adsorpt_input=sorbentVolumes.T, + redeclare each final model MassTransferCoefficient = + MassTransferCoefficientCondenser, + each isFlapValve=true, + each isFlowAB=false, + each final calculateFluidProperties=calcFluidTransportProperties, + each final m_flow_start=m_flow_adsorptive_start, + each final avoid_events=avoid_events, + each final m_flow_small=m_flow_small, + each final noDiff=noDiff) + "Mass transfer between sorbent volumes and condenser port" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={60,0}))); + SorpLib.Components.MassTransfer.VLEMassTransfers.ClosedAdsorberMassTransferDX[ + no_sorbentVolumes] massTransferEvaporator( + redeclare each final package Medium =MediumAdsorptive, + final x_adsorpt_input=sorbentVolumes.x, + final T_adsorpt_input=sorbentVolumes.T, + redeclare each final model MassTransferCoefficient = + MassTransferCoefficientEvaporator, + each isFlapValve=true, + each isFlowAB=true, + each final calculateFluidProperties=calcFluidTransportProperties, + each final m_flow_start=m_flow_adsorptive_start, + each final avoid_events=avoid_events, + each final m_flow_small=m_flow_small, + each final noDiff=noDiff) + "Mass transfer between sorbent volumes and evaporator port" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,0}))); + + // + // Definition of variables + // + SorpLib.Components.HeatExchanger.Records.SummarySimpleClosedAdsorber summary( + final p_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.p)/ + no_sorbentVolumes, + final T_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.T)/ + no_sorbentVolumes, + final x_adsorbate_avg=sum(sorbentVolumes.adsorbateProperties.x_i[1])/ + no_sorbentVolumes, + final mass_adsorpt=summary.x_adsorbate_avg*m_sorInitial, + final p_liq_inlet=heatExchangerTubes.state_a.p, + final p_liq_outlet=heatExchangerTubes.state_b.p, + final p_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.p)/ + no_fluidVolumes, + final T_liq_inlet=heatExchangerTubes.state_a.T, + final T_liq_outlet=heatExchangerTubes.state_b.T, + final T_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.T)/ + no_fluidVolumes, + final T_wall_avg=sum(heatExchangerTubes.wallVolumes.T)/ + no_wallVolumes, + final m_flow_liq_inlet=port_a.m_flow, + final m_flow_liq_outlet=port_b.m_flow, + final m_flow_evaporator=evaporatorPort.m_flow, + final m_flow_condenser=condenserPort.m_flow, + final m_flow_massRecovery=sum({sum(sorbentVolumes[i].fp_sorption.m_flow) + for i in 1:no_sorbentVolumes}) + evaporatorPort.m_flow+condenserPort.m_flow, + final Q_flow_wallToSorbent=heatExchangerTubes.Q_flow_wallHP, + final Q_flow_fluidWall=heatExchangerTubes.Q_flow_fluidWall, + final DH_liquid=heatExchangerTubes.DH_flow) + "Summary record"; + +equation + // + // Connections of fluid portsuseMassRecoveryPorts + // + connect(massTransferCondenser.port_b, sorbentVolumes.fp_sorption[1]) + annotation (Line(points={{60,-8},{60,-16},{70,-16},{70,-44},{51.6,-44},{51.6, + -34.4}}, color={0,0,0})); + connect(massTransferEvaporator.port_b, sorbentVolumes.fp_sorption[2]) + annotation (Line(points={{0,-8},{0,-16},{70,-16},{70,-44},{51.6,-44},{51.6,-34.4}}, + color={0,0,0})); + + + connect(evaporatorPort, evaporatorSplitter.port_a) annotation (Line( + points={{-100,40},{0,40},{0,36}}, + color={0,140,72}, + thickness=1)); + connect(condenserPort, condenserSplitter.port_a) annotation (Line( + points={{100,40},{60,40},{60,36}}, + color={0,140,72}, + thickness=1)); + connect(massTransferEvaporator.port_a, evaporatorSplitter.ports_b) + annotation (Line( + points={{0,7.8},{0,24}}, + color={0,140,72}, + thickness=1)); + connect(massTransferCondenser.port_a, condenserSplitter.ports_b) annotation ( + Line( + points={{60,7.8},{60,24}}, + color={0,140,72}, + thickness=1)); + + // + // Connection of heat ports + // + if no_sorbentVolumes == no_wallVolumes then + // + // Identical discretization number + // + connect(heatExchangerTubes.hp_wall, + heatTransfer_HeatExchangerToSorbentVolumes.hp_a[1]) annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_HeatExchangerToSorbentVolumes.hp_b[1], + sorbentVolumes.hp_sorption) annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + + elseif no_wallVolumes > no_sorbentVolumes then + // + // More wall volumes than sorbent volumes + // + for i in 1:no_sorbentVolumes loop + connect(heatExchangerTubes.hp_wall[1+(i-1)*factorDiscretization:i*factorDiscretization], + heatTransfer_HeatExchangerToSorbentVolumes[i].hp_a[1:factorDiscretization]) + annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + end for; + + connect(heatTransfer_HeatExchangerToSorbentVolumes.hp_b[1], + sorbentVolumes.hp_sorption) annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + + else + // + // More sorbent volumes than wall volumes + // + connect(heatExchangerTubes.hp_wall, + heatTransfer_HeatExchangerToSorbentVolumes.hp_a[1]) annotation (Line( + points={{50,-76},{50,-62}}, + color={238,46,47}, + thickness=1)); + + for i in 1:no_wallVolumes loop + connect(heatTransfer_HeatExchangerToSorbentVolumes[i].hp_b[1:factorDiscretization], + sorbentVolumes[1+(i-1)*factorDiscretization:i*factorDiscretization].hp_sorption) + annotation (Line( + points={{50,-46},{50,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + end for; + end if; + + connect(heatTransfer_sorbentVolumesToCasing.hp_a, sorbentVolumes.hp_sorption) + annotation (Line( + points={{-24,0},{-20,0},{-20,-20},{20,-20},{20,-44},{48.4,-44},{48.4,-37.6}}, + color={238,46,47}, + thickness=1)); + + // + // Annotations + // + connect(massRecoveryPorts, massRecoverySplitter.port_a) annotation (Line( + points={{0,60},{30,60},{30,36}}, + color={0,140,72}, + thickness=1)); + annotation (Documentation(info="<html> +<p> +TO BE ADDED! +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + Major adaptations due to restructering of the library. + </li> + <li> + January 19, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SimpleAdsorberDX; diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_AdsorberDP.mo b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_AdsorberDP.mo new file mode 100644 index 0000000000000000000000000000000000000000..6073db1a03da33004b7ca9d3f41d591a9d9b886e --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_AdsorberDP.mo @@ -0,0 +1,110 @@ +within SorpLib.Components.HeatExchanger.Adsorbers.Tester; +model Test_AdsorberDP + "Tester for the closed adsorber with pressure-driven mass transfer" + extends Modelica.Icons.Example; + + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=false, + use_VFlowInput=false, + V_flow_fixed=-10/60/1000, + use_TInput=true, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=false, + redeclare final package Medium = + Modelica.Media.Water.ConstantPropertyLiquidWater) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of models + // + SorpLib.Components.HeatExchanger.Adsorbers.AdsorberDP closedAdsorber( + no_fluidVolumes=10, + geometry(V_vapor_cas=10, no_hydraulicParallelTubes=1), + useCasing=false, + redeclare model VV_HeatExchanger = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.ConstantAlphaA + (constantAlphaA=300), + redeclare model VV_Casing = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlphaA + (constantAlphaA=5), redeclare + model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT, + calcEntropicProperties=false, + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Dubinin, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.BoilingCurve, + approachSpecificVolume=SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve, + limitLowerPressureAdsorptive=true), + redeclare model WallMaterialCS = + Media.Solids.MetalsAndMetalAlloys.Aluminium, + redeclare model MassTransferCoefficient = + MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.KnudsenDiffusionPoiseuilleFlow) + "Closed adsorber model" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={0,0}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Pulse input_T( + amplitude=60, + width=50, + period=1000, + offset=273.15 + 25) "Input signal for temperature" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, closedAdsorber.port_a) annotation (Line( + points={{-60,0},{-10,0}}, + color={28,108,200}, + thickness=1)); + connect(closedAdsorber.port_b, fs_b.port) annotation (Line( + points={{10,0},{60,0}}, + color={28,108,200}, + thickness=1)); + + connect(input_T.y, fs_a.T_input) annotation (Line(points={{-79,0},{-70,0},{-70, + -2},{-61.2,-2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=5000, + Tolerance=1e-04), + Documentation(info="<html> +<p> +This model checks the closed adsorber heat exchanger with pressure-driven +mass transfer. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 5000 s). +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_AdsorberDP; diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_AdsorberDX.mo b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_AdsorberDX.mo new file mode 100644 index 0000000000000000000000000000000000000000..5afe0ff6aaec77793426030cab2d9aceec47b725 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_AdsorberDX.mo @@ -0,0 +1,110 @@ +within SorpLib.Components.HeatExchanger.Adsorbers.Tester; +model Test_AdsorberDX + "Tester for the closed adsorber with loading-driven mass transfer" + extends Modelica.Icons.Example; + + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=false, + use_VFlowInput=false, + V_flow_fixed=-10/60/1000, + use_TInput=true, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=false, + redeclare final package Medium = + Modelica.Media.Water.ConstantPropertyLiquidWater) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of models + // + SorpLib.Components.HeatExchanger.Adsorbers.AdsorberDX closedAdsorber( + no_fluidVolumes=10, + geometry(V_vapor_cas=10, no_hydraulicParallelTubes=1), + useCasing=false, + redeclare model VV_HeatExchanger = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.ConstantAlphaA + (constantAlphaA=300), + redeclare model VV_Casing = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlphaA + (constantAlphaA=5), redeclare + model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT, + calcEntropicProperties=false, + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Dubinin, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.BoilingCurve, + approachSpecificVolume=SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve, + limitLowerPressureAdsorptive=true), + redeclare model WallMaterialCS = + Media.Solids.MetalsAndMetalAlloys.Aluminium, + redeclare model MassTransferCoefficient = + MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven.Glueckauf) + "Closed adsorber model" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={0,0}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Pulse input_T( + amplitude=60, + width=50, + period=1000, + offset=273.15 + 25) "Input signal for temperature" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, closedAdsorber.port_a) annotation (Line( + points={{-60,0},{-10,0}}, + color={28,108,200}, + thickness=1)); + connect(closedAdsorber.port_b, fs_b.port) annotation (Line( + points={{10,0},{60,0}}, + color={28,108,200}, + thickness=1)); + + connect(input_T.y, fs_a.T_input) annotation (Line(points={{-79,0},{-70,0},{-70, + -2},{-61.2,-2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=5000, + Tolerance=1e-04), + Documentation(info="<html> +<p> +This model checks the closed adsorber heat exchanger with loading-driven +mass transfer. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 5000 s). +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_AdsorberDX; diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_SimpleAdsorberDP.mo b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_SimpleAdsorberDP.mo new file mode 100644 index 0000000000000000000000000000000000000000..7d4d42312a0dca627eecc55d5a0676ba22326589 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_SimpleAdsorberDP.mo @@ -0,0 +1,132 @@ +within SorpLib.Components.HeatExchanger.Adsorbers.Tester; +model Test_SimpleAdsorberDP + "Tester for the simple closed adsorber with pressure-driven mass transfer" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=false, + use_VFlowInput=false, + V_flow_fixed=-10*10/60/1000, + use_TInput=true, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=false, + redeclare final package Medium = + Modelica.Media.Water.ConstantPropertyLiquidWater) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + Basics.Sources.Fluids.VLESource evaporatorSource( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="kPa") = 1700, + T_fixed=288.15) "Evaporator source" + annotation (Placement(transformation(extent={{-70,10},{-50,30}}))); + + Basics.Sources.Fluids.VLESource condenserSource( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="kPa") = 5628, + T_fixed=308.15) "Condenser source" + annotation (Placement(transformation(extent={{50,10},{70,30}}))); + + // + // Definition of models + // + SorpLib.Components.HeatExchanger.Adsorbers.SimpleAdsorberDP closedAdsorber( + no_fluidVolumes=10, + geometry(no_hydraulicParallelTubes=10), + useCasing=false, + redeclare model VV_HeatExchanger = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.ConstantAlphaA + (constantAlphaA=300), + redeclare model VV_Casing = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlphaA + (constantAlphaA=5), + x_sorInitial=0.15, redeclare + model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT, + calcEntropicProperties=false, + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Dubinin, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.BoilingCurve, + approachSpecificVolume=SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve, + limitLowerPressureAdsorptive=true), + redeclare model WallMaterialCS = + Media.Solids.MetalsAndMetalAlloys.Aluminium, + redeclare model MassTransferCoefficientCondenser = + MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.KnudsenDiffusionPoiseuilleFlow) + "Closed adsorber model" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={0,0}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Pulse input_T( + amplitude=60, + width=50, + period=1000, + offset=273.15 + 25) "Input signal for temperature" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + +equation + // + // Connections + // + connect(evaporatorSource.port, closedAdsorber.evaporatorPort) annotation ( + Line( + points={{-60,20},{-10,20},{-10,4}}, + color={0,140,72}, + thickness=1)); + connect(condenserSource.port, closedAdsorber.condenserPort) annotation (Line( + points={{60,20},{10,20},{10,4}}, + color={0,140,72}, + thickness=1)); + connect(fs_a.port, closedAdsorber.port_a) annotation (Line( + points={{-60,0},{-10,0}}, + color={28,108,200}, + thickness=1)); + connect(closedAdsorber.port_b, fs_b.port) annotation (Line( + points={{10,0},{60,0}}, + color={28,108,200}, + thickness=1)); + + connect(input_T.y, fs_a.T_input) annotation (Line(points={{-79,0},{-70,0},{-70, + -2},{-61.2,-2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=5000, + __Dymola_NumberOfIntervals=2500, + __Dymola_Algorithm="Dassl"), + Documentation(info="<html> +<p> +This model checks the simple closed adsorber heat exchanger with pressure-driven +mass transfer. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 5000 s). +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_SimpleAdsorberDP; diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_SimpleAdsorberDX.mo b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_SimpleAdsorberDX.mo new file mode 100644 index 0000000000000000000000000000000000000000..4a6a578c28a5194c6e566263d2067f77e20f0987 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/Test_SimpleAdsorberDX.mo @@ -0,0 +1,132 @@ +within SorpLib.Components.HeatExchanger.Adsorbers.Tester; +model Test_SimpleAdsorberDX + "Tester for the simple closed adsorber with loading-driven mass transfer" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=false, + use_VFlowInput=false, + V_flow_fixed=-10*10/60/1000, + use_TInput=true, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=false, + redeclare final package Medium = + Modelica.Media.Water.ConstantPropertyLiquidWater) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + Basics.Sources.Fluids.VLESource evaporatorSource( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="kPa") = 1700, + T_fixed=288.15) "Evaporator source" + annotation (Placement(transformation(extent={{-70,10},{-50,30}}))); + + Basics.Sources.Fluids.VLESource condenserSource( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed(displayUnit="kPa") = 5628, + T_fixed=308.15) "Condenser source" + annotation (Placement(transformation(extent={{50,10},{70,30}}))); + + // + // Definition of models + // + SorpLib.Components.HeatExchanger.Adsorbers.SimpleAdsorberDX closedAdsorber( + no_fluidVolumes=10, + geometry(no_hydraulicParallelTubes=10), + useCasing=false, + redeclare model VV_HeatExchanger = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.ConstantAlphaA + (constantAlphaA=300), + redeclare model VV_Casing = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlphaA + (constantAlphaA=5), + x_sorInitial=0.15, redeclare + model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT, + calcEntropicProperties=false, + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Dubinin, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.BoilingCurve, + approachSpecificVolume=SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve, + limitLowerPressureAdsorptive=true), + redeclare model WallMaterialCS = + Media.Solids.MetalsAndMetalAlloys.Aluminium, + redeclare model MassTransferCoefficientCondenser = + MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven.GlueckaufArrhenius) + "Closed adsorber model" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={0,0}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Pulse input_T( + amplitude=60, + width=50, + period=1000, + offset=273.15 + 25) "Input signal for temperature" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + +equation + // + // Connections + // + connect(evaporatorSource.port, closedAdsorber.evaporatorPort) annotation ( + Line( + points={{-60,20},{-10,20},{-10,4}}, + color={0,140,72}, + thickness=1)); + connect(condenserSource.port, closedAdsorber.condenserPort) annotation (Line( + points={{60,20},{10,20},{10,4}}, + color={0,140,72}, + thickness=1)); + connect(fs_a.port, closedAdsorber.port_a) annotation (Line( + points={{-60,0},{-10,0}}, + color={28,108,200}, + thickness=1)); + connect(closedAdsorber.port_b, fs_b.port) annotation (Line( + points={{10,0},{60,0}}, + color={28,108,200}, + thickness=1)); + + connect(input_T.y, fs_a.T_input) annotation (Line(points={{-79,0},{-70,0},{-70, + -2},{-61.2,-2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=5000, + __Dymola_NumberOfIntervals=2500, + __Dymola_Algorithm="Dassl"), + Documentation(info="<html> +<p> +This model checks the simple closed adsorber heat exchanger with loading-driven +mass transfer. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 5000 s). +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_SimpleAdsorberDX; diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/Tester/package.mo b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..65ee86c91c619b5d58809725e01a004926bf29b1 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.HeatExchanger.Adsorbers; +package Tester "Models to test and varify closed adsorbers" + extends Modelica.Icons.ExamplesPackage; + + + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all closed adsorber heat exchangers. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/Tester/package.order b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e162433df51e3ada78a8db17a24f2159231d6904 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/Tester/package.order @@ -0,0 +1,4 @@ +Test_AdsorberDP +Test_AdsorberDX +Test_SimpleAdsorberDP +Test_SimpleAdsorberDX diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/package.mo b/SorpLib/Components/HeatExchanger/Adsorbers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d179375f18e137baf6806143ae551a5c6c413d9b --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.HeatExchanger; +package Adsorbers "Adsorbers used in closed sorption systems" + extends SorpLib.Icons.AdsorbersPackage; + + annotation (Documentation(info="<html> +<p> +This package contains closed adsorber heat exchanger that are based on the Modelica +Standard Library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Adsorbers; diff --git a/SorpLib/Components/HeatExchanger/Adsorbers/package.order b/SorpLib/Components/HeatExchanger/Adsorbers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..4cffa738ea192ee0d95c94979495f720c9803428 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Adsorbers/package.order @@ -0,0 +1,5 @@ +AdsorberDP +AdsorberDX +SimpleAdsorberDP +SimpleAdsorberDX +Tester diff --git a/SorpLib/Components/HeatExchanger/BaseClasses/PartialHeatExchanger.mo b/SorpLib/Components/HeatExchanger/BaseClasses/PartialHeatExchanger.mo new file mode 100644 index 0000000000000000000000000000000000000000..fd2e200584f38d6fa87dde3e0fd135a4dc0becec --- /dev/null +++ b/SorpLib/Components/HeatExchanger/BaseClasses/PartialHeatExchanger.mo @@ -0,0 +1,132 @@ +within SorpLib.Components.HeatExchanger.BaseClasses; +partial model PartialHeatExchanger + "Base model for all heat exchanger" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.Pressure p_initial = 1e5 + "Initial value of pressure" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + parameter Modelica.Units.SI.MassFraction[no_components] X_i_initial= + fill(1/no_components, no_components) + "Initial values of mass fractions" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + + parameter Modelica.Units.SI.MassFlowRate m_flow_start = 1e-4 + "Start value for mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter SorpLib.Choices.BalanceEquations type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial + "Handling of the overall mass balance and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Choices.BalanceEquations type_independentMassBalances= + type_overallMassBalance + "Handling of independent mass balances and corresponding initialisations" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Choices.BalanceEquations type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial + "Handling of the energy balance and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult = true); + + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Modelica.Units.SI.MassFlowRate m_flow_small = 1e-4 + "Regularization mass flow rate" + annotation (Dialog(tab="Advanced", group="Numerics")); + parameter Integer noDiff = 2 + "Specification how often transition functions can be differentiated" + annotation(Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult=true); + + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=m_flow_start)) + "Fluid port a" + annotation (Placement(transformation(extent={{-110,-10},{-90,10}}), + iconTransformation(extent={{-110,-10},{-90,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-m_flow_start)) + "Fluid port b" + annotation (Placement(transformation(extent={{90,-10},{110,10}}), + iconTransformation(extent={{90,-10},{110,10}})), + choicesAllMatching=true); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all heat exchangers. It defines some +fundamental parameters required by all heat exchangers. Models that inherit properties +from this partial model have to redeclare the fluid ports. Moreover, the mass +and energy balances must be completed using the ports. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Pressure <i>port_a.p</i> at port a. + </li> + <li> + Pressure <i>port_a.p</i> at port b. + </li> + <br/> + <li> + Mass flow rate <i>port_a.m_flow</i> at port a. + </li> + <li> + Mass flow rate <i>port_a.m_flow</i> at port b. + </li> + <br/> + <li> + Outflowing specific enthalpy <i>port_a.h_outflow</i> at port a. + </li> + <li> + Outflowing specific enthalpy <i>port_b.h_outflow</i> at port b. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 26, 2024, by Mirko Engelpracht:<br/> + Minor adaptations and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialHeatExchanger; diff --git a/SorpLib/Components/HeatExchanger/BaseClasses/PartialPureComponentAdsorber.mo b/SorpLib/Components/HeatExchanger/BaseClasses/PartialPureComponentAdsorber.mo new file mode 100644 index 0000000000000000000000000000000000000000..06b72f1809fbadd74b1a850d08792dc3a0747aca --- /dev/null +++ b/SorpLib/Components/HeatExchanger/BaseClasses/PartialPureComponentAdsorber.mo @@ -0,0 +1,1161 @@ +within SorpLib.Components.HeatExchanger.BaseClasses; +partial model PartialPureComponentAdsorber + "Base model for all adsorber heat exchangers for pure component adsorption" + extends SorpLib.Components.HeatExchanger.BaseClasses.PartialHeatExchanger( + final p_initial, + final X_i_initial); + + // + // Definition of general parameters + // + parameter Integer nPortsMassTransfer = 0 + "Number of mass transfer ports" + annotation (Dialog(connectorSizing=true), + HideResult = true); + + parameter Integer no_fluidVolumes(min=2)=2 + "Discretization number of fluid volumes" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + parameter Integer no_wallVolumes(min=2)=no_fluidVolumes + "Discretization number of wall volumes (must be a factor of no_fluidVolumes)" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + parameter Integer no_sorbentVolumes(min=1)=no_wallVolumes + "Discretization number of sorbent volumes (must be a factor of no_wallVolumes)" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding the geometry + // + replaceable parameter SorpLib.Components.HeatExchanger.Records.GeometryClosedAdsorber geometry + constrainedby + SorpLib.Components.HeatExchanger.Records.GeometryClosedAdsorber( + no_fluidVolumes=no_fluidVolumes, + no_wallVolumes=no_wallVolumes, + no_sorbentVolumes=no_sorbentVolumes) + "Geometry of the closed adsorber" + annotation (Dialog(tab = "General", group = "Geometry"), + choicesAllMatching = true); + + // + // Definition of parameters regarding the medium + // + parameter Integer no_adsorptiveComponents = 1 + "Number of adsorptive components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of models describing transport phenomena + // + parameter Boolean useCasing = false + " = true, if casing is modeled" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useConductionCasing = true + " = true, if thermal conduction in the casing is modeled" + annotation (Dialog(tab="Transport Phenomena", group="General", + enable=useCasing), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useConductionPerpendicularFlowDirection = true + " = true, if thermal conduction perpendicular to the flow direction is + considered within the heat exchanger wall" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useConductionFlowDirection = false + " = true, if thermal conduction in the flow direction is considered within + the heat exchanger wall" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcFluidTransportProperties = true + " = true, if any transport model needs fluid or transport properties" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + replaceable model HX_InnerWallThermalConductionPerpendicularFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_hx/geometry.no_wallVolumes, + d_inner=geometry.d_hydInner_hx, + d_outer=(geometry.d_hydInner_hx + geometry.d_hydOuter_hx)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction perpendicular to the + flow direction within the heat exchanger wall near the fluid" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionPerpendicularFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model HX_OuterWallThermalConductionPerpendicularFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_hx/geometry.no_wallVolumes, + d_inner=(geometry.d_hydInner_hx + geometry.d_hydOuter_hx)/2, + d_outer=geometry.d_hydOuter_hx) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction perpendicular to the + flow direction within the heat exchanger wall near the heat port" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionPerpendicularFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model HX_WallThermalConductionFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.PlainWall + ( + A_cross=geometry.A_crossWall_hx, + delta_wall=(geometry.l_hx/geometry.no_wallVolumes)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction in the flow direction + within the heat exchanger wall" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model CS_InnerWallThermalConduction = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_cas, + d_inner=geometry.d_hydInner_cas, + d_outer=(geometry.d_hydInner_cas + geometry.d_hydOuter_cas)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction within the casing + near the phase separator" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useCasing and useConductionCasing), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model CS_OuterWallThermalConduction = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_cas, + d_inner=(geometry.d_hydInner_cas + geometry.d_hydOuter_cas)/2, + d_outer=geometry.d_hydOuter_cas) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction within the casing + near the heat port" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useCasing and useConductionCasing), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model HX_FluidThermalConvectionTubeInside = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.GnielinskiDittusBoelter + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialTubeInsideHeatTransferCoefficient + "Heat transfer correlation describing thermal convection at the tube inside + within the heat exchanger (i.e., form the fluid to the wall)" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Convection"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model VV_HeatExchanger = + HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.ConstantAlphaA + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialClosedAdsorberHeatTransferCoefficient + "Heat transfer correlation describing the heat transfer from the sorbent volumes + to heat exchanger tubes" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Convection"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model VV_Casing = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlphaA + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialGenericHeatTransferCoefficient + "Heat transfer correlation describing the heat transfer between the vapor + volume and casing" + annotation (Dialog(tab="Transport Phenomena", group="Generic", + enable = useCasing), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model HX_PressureDrop = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Konakov + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss + "Pressure drop correlation describing the pressure drop of the fluid within + the heat exchanger" + annotation (Dialog(tab="Transport Phenomena", group="Pressure Drop"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding initial values + // + parameter Modelica.Units.SI.Pressure p_fluidAInitial = 1.25e5 + "Initial value of fluid pressure at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + parameter Modelica.Units.SI.Pressure p_fluidBInitial = 1e5 + "Initial value of fluid pressure at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + parameter Modelica.Units.SI.Temperature T_fluidAInitial = 283.15 + "Initial value of fluid temperature at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + parameter Modelica.Units.SI.Temperature T_fluidBInitial = 303.15 + "Initial value of fluid temperature at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + + parameter Modelica.Units.SI.Temperature T_wallAInitial = T_fluidAInitial + "Initial value of wall temperature at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Wall")); + parameter Modelica.Units.SI.Temperature T_wallBInitial = T_fluidBInitial + "Initial value of wall temperature at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Wall")); + + parameter Modelica.Units.SI.Pressure p_vaporVolumeInitial = 1e3 + "Initial value of the vapor pressure" + annotation (Dialog(tab="Initialisation", group="Initial Values - Vapor")); + parameter Modelica.Units.SI.Temperature T_vaporVolumeInitial = 303.15 + "Initial value of vapor temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values - Vapor")); + + parameter Modelica.Units.SI.Mass m_sorInitial = 725 * geometry.V_sorbent_hx / + geometry.no_sorbentVolumes + "Initial value of the sorbent mass" + annotation (Dialog(tab="Initialisation", group="Initial Values - Sorbent")); + parameter SorpLib.Units.Uptake x_sorInitial = 0.15 + "Initial loading of the sorbent" + annotation (Dialog(tab="Initialisation", group="Initial Values - Sorbent")); + parameter Modelica.Units.SI.Temperature T_sorInitial = 303.15 + "Initial value of sorbent temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values - Sorbent")); + + + parameter Modelica.Units.SI.Temperature T_casingInitial = 298.15 + "Initial value of casing temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values - Casing", + enable=useCasing)); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.MassFlowRate m_flow_adsorptive_start = 1e-4 + "Start value for adsorptive mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of ports + // + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_in evaporatorPort(final + no_components=no_adsorptiveComponents, m_flow(start= + m_flow_adsorptive_start)) "Evaporator port" annotation (Placement( + transformation(extent={{-110,30},{-90,50}}), iconTransformation(extent={ + {-110,30},{-90,50}}))); + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_out condenserPort(final + no_components=no_adsorptiveComponents, m_flow(start=- + m_flow_adsorptive_start)) "Condenser port" annotation (Placement( + transformation(extent={{90,30},{110,50}}), iconTransformation(extent={{90, + 30},{110,50}}))); + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_out[nPortsMassTransfer] massRecoveryPorts( + each final no_components=no_adsorptiveComponents, + each final m_flow(start=m_flow_adsorptive_start)) "Mass recovery ports" + annotation (Placement(transformation(extent={{-10,50},{10,70}}), + iconTransformation(extent={{-10,50},{10,70}}))); + + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_casing if + useCasing + "Heat ports at casing" + annotation (Placement(transformation(extent={{-10,-50},{10,-70}}), + iconTransformation(extent={{-10,-70},{10,-50}}))); + + // + // Definition and instanziation of models + // + replaceable Basics.Volumes.BaseClasses.PartialFluidVolume vaporVolume( + final calculateAdditionalProperties=calcFluidTransportProperties, + redeclare final SorpLib.Basics.Volumes.Records.VolumeGeometry + geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_vapor_cas), + final useHeatPorts=true, + final useHeatPortsX=false, + final useHeatPortsY=true, + final useHeatPortsZ=false, + final p_initial=p_vaporVolumeInitial, + final T_initial=T_vaporVolumeInitial, + final mc_flow_initialX=m_flow_adsorptive_start, + final type_energyBalance=type_energyBalance, + final type_overallMassBalance=type_overallMassBalance, + final avoid_events=avoid_events, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.phX, + nPorts_cfp_xPlus=2+nPortsMassTransfer) + "Vapor volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,0}))); + + replaceable SorpLib.Components.Tubes.BaseClasses.PartialTube heatExchangerTubes( + final no_fluidVolumes=no_fluidVolumes, + final no_wallVolumes=no_wallVolumes, + redeclare final SorpLib.Components.Tubes.Records.GeometryTube geometry( + no_hydraulicParallelTubes=geometry.no_hydraulicParallelTubes, + l=geometry.l_hx, + roughness=geometry.roughness_hx, + d_inner=geometry.d_inner_hx, + d_outer=geometry.d_outer_hx, + d_hydInner=geometry.d_hydInner_hx, + d_hydOuter=geometry.d_hydOuter_hx, + t_wall=geometry.t_wall_hx, + A_crossInner=geometry.A_crossInner_hx, + A_crossOuter=geometry.A_crossOuter_hx, + A_crossWall=geometry.A_crossWall_hx, + A_hydCrossInner=geometry.A_hydCrossInner_hx, + A_hydCrossOuter=geometry.A_hydCrossOuter_hx, + A_hydCrossWall=geometry.A_hydCrossWall_hx, + A_heatTransferInner=geometry.A_heatTransferInner_hx, + A_heatTransferOuter=geometry.A_heatTransferOuter_hx, + f_finAreaRatioInner=geometry.f_finAreaRatioInner_hx, + f_finAreaRatioOuter=geometry.f_finAreaRatioOuter_hx, + V_inner=geometry.V_inner_hx, + V_outer=geometry.V_outer_hx, + V_wall=geometry.V_wall_hx, + f_finVolumeRatioInner=geometry.f_finVolumeRatioInner_hx, + f_finVolumeRatioOuter=geometry.f_finVolumeRatioOuter_hx), + final useConductionPerpendicularFlowDirection= + useConductionPerpendicularFlowDirection, + final useConductionFlowDirection=useConductionFlowDirection, + final calcFluidTransportProperties=calcFluidTransportProperties, + redeclare final model InnerWallThermalConductionPerpendicularFlowDirection = + HX_InnerWallThermalConductionPerpendicularFlowDirection, + redeclare final model OuterWallThermalConductionPerpendicularFlowDirection = + HX_OuterWallThermalConductionPerpendicularFlowDirection, + redeclare final model WallThermalConductionFlowDirection = + HX_WallThermalConductionFlowDirection, + redeclare final model FluidThermalConvectionTubeInside = + HX_FluidThermalConvectionTubeInside, + redeclare final model PressureDrop = HX_PressureDrop, + final p_fluidAInitial=p_fluidAInitial, + final p_fluidBInitial=p_fluidBInitial, + final T_fluidAInitial=T_fluidAInitial, + final T_fluidBInitial=T_fluidBInitial, + final T_wallAInitial=T_wallAInitial, + final T_wallBInitial=T_wallBInitial, + final m_flow_start=m_flow_start, + final type_overallMassBalance=type_overallMassBalance, + final type_independentMassBalances=type_independentMassBalances, + final avoid_events=avoid_events, + final m_flow_small=m_flow_small, + final noDiff=noDiff) + "Heat exchanger tubes" + annotation (Placement(transformation(extent={{40,-90},{60,-70}}))); + + replaceable SorpLib.Basics.Volumes.BaseClasses.PartialVolume casing( + final useHeatPortsX=false, + final useHeatPortsY=true, + final useHeatPortsZ=false, + final type_energyBalance=type_energyBalance, + final avoid_events=avoid_events) if useCasing + "Casing" + annotation (Placement(transformation(extent={{-68,10},{-48,-10}}))); + + SorpLib.Components.HeatTransfer.GenericHeatTransfer heatTransfer_vaporVolumeToCasing( + final n_a=1, + final n_b=1, + final calculateFluidProperties=calcFluidTransportProperties, + redeclare final model HeatTransferCoefficient = VV_Casing) if + useCasing "Heat transfer from vapor volume to casing" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={-32,0}))); + + HeatTransfer.ConductionHeatTransfer thermalConduction_casing1( + final n_a=1, + final n_b=1, + final calculateFluidProperties=calcFluidTransportProperties, + redeclare final model HeatTransferCoefficient = + CS_InnerWallThermalConduction, + final no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes) if + (useCasing and useConductionCasing) + "Thermal conduction of the first casing half" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={-58,22}))); + + HeatTransfer.ConductionHeatTransfer thermalConduction_casing2( + final n_a=1, + final n_b=1, + final calculateFluidProperties=calcFluidTransportProperties, + redeclare final model HeatTransferCoefficient = + CS_OuterWallThermalConduction, + final no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes) if + (useCasing and useConductionCasing) + "Thermal conduction of the second casing half" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={-58,-22}))); + + // + // Definition of protected parameters + // +protected + final parameter Integer factorDiscretization= + integer(max(no_sorbentVolumes,no_wallVolumes)/ + min(no_sorbentVolumes,no_wallVolumes)) + "Discretization factor" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + +equation + // + // Assertations + // + if no_wallVolumes < no_fluidVolumes then + assert(rem(no_fluidVolumes, no_wallVolumes) == 0, + "Number of wall volumes must be a factor of the number of fluid volumes!"); + + elseif no_wallVolumes > no_fluidVolumes then + assert(rem(no_wallVolumes, no_fluidVolumes) == 0, + "Number of wall volumes must be a factor of the number of fluid volumes!"); + + end if; + + if no_wallVolumes < no_sorbentVolumes then + assert(rem(no_sorbentVolumes, no_wallVolumes) == 0, + "Number of wall volumes must be a factor of the number of sorbent volumes!"); + + elseif no_wallVolumes > no_sorbentVolumes then + assert(rem(no_wallVolumes, no_sorbentVolumes) == 0, + "Number of wall volumes must be a factor of the number of sorbent volumes!"); + + end if; + + // + // Connection of fluid ports + // + connect(port_a, heatExchangerTubes.fp_a) annotation (Line(points={{-100,0},{-80, + 0},{-80,-80},{40,-80}}, color={0,0,0})); + connect(heatExchangerTubes.fp_b, port_b) annotation (Line(points={{60,-80},{80, + -80},{80,0},{100,0}}, color={0,0,0})); + + connect(evaporatorPort, vaporVolume.cfp_xPlus[1]) annotation (Line( + points={{-100,40},{-1.8,40},{-1.8,7.8}}, + color={0,140,72}, + thickness=1)); + connect(condenserPort, vaporVolume.cfp_xPlus[2]) annotation (Line( + points={{100,40},{-1.8,40},{-1.8,7.8}}, + color={0,140,72}, + thickness=1)); + + if nPortsMassTransfer > 0 then + connect(massRecoveryPorts, vaporVolume.cfp_xPlus[3:2+nPortsMassTransfer]) annotation (Line( + points={{0,60},{0,40},{-2,40},{-2,8},{-1.8,8},{-1.8,7.8}}, + color={0,140,72}, + thickness=1)); + end if; + + // + // Connection of heat ports + // + connect(vaporVolume.hp_yPlus, heatTransfer_vaporVolumeToCasing.hp_a[1]) + annotation (Line( + points={{-6,0},{-24,0}}, + color={238,46,47}, + thickness=1)); + + if useCasing then + if useConductionCasing then + connect(heatTransfer_vaporVolumeToCasing.hp_b[1], + thermalConduction_casing1.hp_a[1]) annotation (Line( + points={{-40,4.44089e-16},{-42,4.44089e-16},{-42,32},{-58,32},{-58,30}}, + color={238,46,47}, + thickness=1)); + + connect(thermalConduction_casing1.hp_b[1], casing.hp_yMinus) annotation (Line( + points={{-58,14},{-58,6}}, + color={238,46,47}, + thickness=1)); + connect(casing.hp_yPlus, thermalConduction_casing2.hp_a[1]) annotation (Line( + points={{-58,-6},{-58,-14}}, + color={238,46,47}, + thickness=1)); + connect(thermalConduction_casing2.hp_b[1], hp_casing) annotation (Line( + points={{-58,-30},{-58,-32},{0,-32},{0,-60}}, + color={238,46,47}, + thickness=1)); + + else + connect(heatTransfer_vaporVolumeToCasing.hp_b[1], hp_casing); + + end if; + end if; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle( + extent={{-100,60},{100,-60}}, + lineColor={0,0,0}, + lineThickness=1), + Line( + points={{100,40},{-80,40},{80,0},{-80,-40},{100,-40}}, + color={0,0,0}, + thickness=1), + Ellipse( + extent={{-74,42},{-80,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,42},{-20,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,42},{-32,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-38,42},{-44,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,42},{-56,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,42},{-68,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,42},{52,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,42},{40,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,42},{28,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,42},{16,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,42},{4,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-2,42},{-8,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,42},{64,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{82,42},{76,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{82,-48},{76,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,-48},{64,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,-48},{52,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,-48},{40,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,-48},{28,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,-48},{16,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,-48},{4,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-2,-48},{-8,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,-48},{-20,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,-48},{-32,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-38,-48},{-44,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,-48},{-56,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,-48},{-68,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-74,-48},{-80,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{88,-38},{82,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{76,-38},{70,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{64,-38},{58,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,-38},{46,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{40,-38},{34,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{28,-38},{22,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{16,-38},{10,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{4,-38},{-2,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,-38},{-14,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-20,-38},{-26,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-32,-38},{-38,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-44,-40},{-50,-34}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-44,34},{-50,40}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-32,32},{-38,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-20,32},{-26,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,32},{-14,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{4,32},{-2,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{16,32},{10,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{28,32},{22,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{40,32},{34,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,32},{46,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{64,32},{58,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{76,32},{70,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{88,32},{82,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,30},{-72,36}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-52,26},{-58,32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-36,22},{-42,28}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,18},{-24,24}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-4,14},{-10,20}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{12,10},{6,16}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,6},{24,12}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{44,2},{38,8}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{60,-2},{54,4}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,24},{-14,30}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{6,20},{0,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,16},{16,22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{38,12},{32,18}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,8},{46,14}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{68,4},{62,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,-36},{-72,-30}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-52,-32},{-58,-26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-36,-28},{-42,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,-24},{-24,-18}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-4,-20},{-10,-14}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{12,-16},{6,-10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,-12},{24,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{44,-8},{38,-2}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{68,-10},{62,-4}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,-14},{46,-8}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{38,-18},{32,-12}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{24,-22},{18,-16}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{6,-26},{0,-20}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,-30},{-14,-24}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-44,24},{-50,30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-54,34},{-60,40}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-76,34},{-82,40}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,42},{-14,48}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,26},{-20,32}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{4,12},{-2,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,14},{24,20}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,0},{46,6}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,32},{28,38}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{76,42},{70,48}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{82,32},{76,38}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{20,-14},{14,-8}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-28,-26},{-34,-20}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-52,-40},{-58,-34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-78,-42},{-84,-36}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-32,-48},{-38,-42}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,-38},{4,-32}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{40,-48},{34,-42}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,-38},{64,-32}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,-16},{40,-10}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid)}), + Diagram(coordinateSystem(extent={{-100,-100},{100,100}})), + Documentation(info="<html> +<p> +This partial model is the base model for all closed adsorber heat exchanger. It defines +fundamental parameters, models, and variables required by all closed adsorbers. Models +that inherit properties from this partial model have to redeclare all partial models +(i.e., fluid ports, tube, vapor volume, and casing). Moreover, sorbent volumes must be +added as well as a mass transfer model describing the mass transfer between the sorbent +and vapor and a heat transfer model describing the heat transfer between the sorbent and +heat exchanger. These models are not inserted in the partial model to allow for designing +different heat exchanger cofigurations with various level of detal. Furthermore, +the geometry of the redeclared heat trasnfer must be correctly set using the geometry +record. In addition, the inputs 'fluidProperties' of the conductive heat transfer models +must be correctly set using properties of the casing. +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + Major adaptations due to restructering of the library and documentation. + </li> + <li> + January 19, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureComponentAdsorber; diff --git a/SorpLib/Components/HeatExchanger/BaseClasses/PartialPureSimpleComponentAdsorber.mo b/SorpLib/Components/HeatExchanger/BaseClasses/PartialPureSimpleComponentAdsorber.mo new file mode 100644 index 0000000000000000000000000000000000000000..0a13a3df8981955289a4ee1308573e91c13d7d20 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/BaseClasses/PartialPureSimpleComponentAdsorber.mo @@ -0,0 +1,1130 @@ +within SorpLib.Components.HeatExchanger.BaseClasses; +partial model PartialPureSimpleComponentAdsorber + "Base model for all adsorber heat exchangers without a vapor volume for pure component adsorption" + extends SorpLib.Components.HeatExchanger.BaseClasses.PartialHeatExchanger( + final p_initial, + final X_i_initial); + + // + // Definition of general parameters + // + parameter Integer no_fluidVolumes(min=2)=2 + "Discretization number of fluid volumes" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + parameter Integer no_wallVolumes(min=2)=no_fluidVolumes + "Discretization number of wall volumes (must be a factor of no_fluidVolumes)" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + parameter Integer no_sorbentVolumes(min=1)=no_wallVolumes + "Discretization number of sorbent volumes (must be a factor of no_wallVolumes)" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding the geometry + // + replaceable parameter SorpLib.Components.HeatExchanger.Records.GeometryClosedAdsorber geometry + constrainedby + SorpLib.Components.HeatExchanger.Records.GeometryClosedAdsorber( + no_fluidVolumes=no_fluidVolumes, + no_wallVolumes=no_wallVolumes, + no_sorbentVolumes=no_sorbentVolumes) + "Geometry of the closed adsorber" + annotation (Dialog(tab = "General", group = "Geometry"), + choicesAllMatching = true); + + // + // Definition of parameters regarding the medium + // + parameter Integer no_adsorptiveComponents = 1 + "Number of adsorptive components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of models describing transport phenomena + // + parameter Boolean useCasing = false + " = true, if casing is modeled" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useConductionCasing = true + " = true, if thermal conduction in the casing is modeled" + annotation (Dialog(tab="Transport Phenomena", group="General", + enable=useCasing), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useConductionPerpendicularFlowDirection = true + " = true, if thermal conduction perpendicular to the flow direction is + considered within the heat exchanger wall" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useConductionFlowDirection = false + " = true, if thermal conduction in the flow direction is considered within + the heat exchanger wall" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcFluidTransportProperties = true + " = true, if any transport model needs fluid or transport properties" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useMassRecoveryPorts = false + " = true, if mass recovery ports are used" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + replaceable model HX_InnerWallThermalConductionPerpendicularFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_hx/geometry.no_wallVolumes, + d_inner=geometry.d_hydInner_hx, + d_outer=(geometry.d_hydInner_hx + geometry.d_hydOuter_hx)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction perpendicular to the + flow direction within the heat exchanger wall near the fluid" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionPerpendicularFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model HX_OuterWallThermalConductionPerpendicularFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_hx/geometry.no_wallVolumes, + d_inner=(geometry.d_hydInner_hx + geometry.d_hydOuter_hx)/2, + d_outer=geometry.d_hydOuter_hx) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction perpendicular to the + flow direction within the heat exchanger wall near the heat port" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionPerpendicularFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model HX_WallThermalConductionFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.PlainWall + ( + A_cross=geometry.A_crossWall_hx, + delta_wall=(geometry.l_hx/geometry.no_wallVolumes)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction in the flow direction + within the heat exchanger wall" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model CS_InnerWallThermalConduction = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_cas, + d_inner=geometry.d_hydInner_cas, + d_outer=(geometry.d_hydInner_cas + geometry.d_hydOuter_cas)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction within the casing + near the phase separator" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useCasing and useConductionCasing), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model CS_OuterWallThermalConduction = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_cas, + d_inner=(geometry.d_hydInner_cas + geometry.d_hydOuter_cas)/2, + d_outer=geometry.d_hydOuter_cas) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction within the casing + near the heat port" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useCasing and useConductionCasing), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model HX_FluidThermalConvectionTubeInside = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.GnielinskiDittusBoelter + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialTubeInsideHeatTransferCoefficient + "Heat transfer correlation describing thermal convection at the tube inside + within the heat exchanger (i.e., form the fluid to the wall)" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Convection"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model VV_HeatExchanger = + HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.ConstantAlphaA + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialClosedAdsorberHeatTransferCoefficient + "Heat transfer correlation describing the heat transfer from the sorbent volumes + to heat exchanger tubes" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Convection"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model VV_Casing = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlphaA + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialGenericHeatTransferCoefficient + "Heat transfer correlation describing the heat transfer between the vapor + volume and casing" + annotation (Dialog(tab="Transport Phenomena", group="Generic", + enable = useCasing), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model HX_PressureDrop = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Konakov + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss + "Pressure drop correlation describing the pressure drop of the fluid within + the heat exchanger" + annotation (Dialog(tab="Transport Phenomena", group="Pressure Drop"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding initial values + // + parameter Modelica.Units.SI.Pressure p_fluidAInitial = 1.25e5 + "Initial value of fluid pressure at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + parameter Modelica.Units.SI.Pressure p_fluidBInitial = 1e5 + "Initial value of fluid pressure at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + parameter Modelica.Units.SI.Temperature T_fluidAInitial = 283.15 + "Initial value of fluid temperature at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + parameter Modelica.Units.SI.Temperature T_fluidBInitial = 303.15 + "Initial value of fluid temperature at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + + parameter Modelica.Units.SI.Temperature T_wallAInitial = T_fluidAInitial + "Initial value of wall temperature at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Wall")); + parameter Modelica.Units.SI.Temperature T_wallBInitial = T_fluidBInitial + "Initial value of wall temperature at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Wall")); + + parameter Modelica.Units.SI.Pressure p_vaporVolumeInitial = 1e3 + "Initial value of the vapor pressure" + annotation (Dialog(tab="Initialisation", group="Initial Values - Vapor")); + parameter Modelica.Units.SI.Temperature T_vaporVolumeInitial = 303.15 + "Initial value of vapor temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values - Vapor")); + + parameter Modelica.Units.SI.Mass m_sorInitial = 725 * geometry.V_sorbent_hx / + geometry.no_sorbentVolumes + "Initial value of the sorbent mass" + annotation (Dialog(tab="Initialisation", group="Initial Values - Sorbent")); + parameter SorpLib.Units.Uptake x_sorInitial = 0.15 + "Initial loading of the sorbent" + annotation (Dialog(tab="Initialisation", group="Initial Values - Sorbent")); + parameter Modelica.Units.SI.Temperature T_sorInitial = 303.15 + "Initial value of sorbent temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values - Sorbent")); + + parameter Modelica.Units.SI.Temperature T_casingInitial = 298.15 + "Initial value of casing temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values - Casing", + enable=useCasing)); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.MassFlowRate m_flow_adsorptive_start = 1e-4 + "Start value for adsorptive mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of ports + // + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_in evaporatorPort(final + no_components=no_adsorptiveComponents, m_flow(start= + m_flow_adsorptive_start)) "Evaporator port" annotation (Placement( + transformation(extent={{-110,30},{-90,50}}), iconTransformation(extent={ + {-110,30},{-90,50}}))); + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_out condenserPort(final + no_components=no_adsorptiveComponents, m_flow(start=- + m_flow_adsorptive_start)) "Condenser port" annotation (Placement( + transformation(extent={{90,30},{110,50}}), iconTransformation(extent={{90, + 30},{110,50}}))); + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_out massRecoveryPorts( + no_components=no_adsorptiveComponents, + m_flow(start=m_flow_adsorptive_start)) if useMassRecoveryPorts + "Mass recovery ports" + annotation (Placement(transformation(extent={{-10,50},{10,70}}), + iconTransformation(extent={{-10,50},{10,70}}))); + + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_casing if + useCasing + "Heat ports at casing" + annotation (Placement(transformation(extent={{-10,-50},{10,-70}}), + iconTransformation(extent={{-10,-70},{10,-50}}))); + + // + // Definition and instanziation of models + // + replaceable SorpLib.Components.Fittings.BaseClasses.PartialMultiPort condenserSplitter + "Splitter for condenser port" annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={60,30}))); + replaceable SorpLib.Components.Fittings.BaseClasses.PartialMultiPort evaporatorSplitter + "Splitter for evaporator port" annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,30}))); + replaceable SorpLib.Components.Fittings.BaseClasses.PartialMultiPort massRecoverySplitter if + useMassRecoveryPorts + "Splitter for mass recovery port" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={30,30}))); + + replaceable SorpLib.Components.Tubes.BaseClasses.PartialTube heatExchangerTubes( + final no_fluidVolumes=no_fluidVolumes, + final no_wallVolumes=no_wallVolumes, + redeclare final SorpLib.Components.Tubes.Records.GeometryTube geometry( + no_hydraulicParallelTubes=geometry.no_hydraulicParallelTubes, + l=geometry.l_hx, + roughness=geometry.roughness_hx, + d_inner=geometry.d_inner_hx, + d_outer=geometry.d_outer_hx, + d_hydInner=geometry.d_hydInner_hx, + d_hydOuter=geometry.d_hydOuter_hx, + t_wall=geometry.t_wall_hx, + A_crossInner=geometry.A_crossInner_hx, + A_crossOuter=geometry.A_crossOuter_hx, + A_crossWall=geometry.A_crossWall_hx, + A_hydCrossInner=geometry.A_hydCrossInner_hx, + A_hydCrossOuter=geometry.A_hydCrossOuter_hx, + A_hydCrossWall=geometry.A_hydCrossWall_hx, + A_heatTransferInner=geometry.A_heatTransferInner_hx, + A_heatTransferOuter=geometry.A_heatTransferOuter_hx, + f_finAreaRatioInner=geometry.f_finAreaRatioInner_hx, + f_finAreaRatioOuter=geometry.f_finAreaRatioOuter_hx, + V_inner=geometry.V_inner_hx, + V_outer=geometry.V_outer_hx, + V_wall=geometry.V_wall_hx, + f_finVolumeRatioInner=geometry.f_finVolumeRatioInner_hx, + f_finVolumeRatioOuter=geometry.f_finVolumeRatioOuter_hx), + final useConductionPerpendicularFlowDirection= + useConductionPerpendicularFlowDirection, + final useConductionFlowDirection=useConductionFlowDirection, + final calcFluidTransportProperties=calcFluidTransportProperties, + redeclare final model InnerWallThermalConductionPerpendicularFlowDirection = + HX_InnerWallThermalConductionPerpendicularFlowDirection, + redeclare final model OuterWallThermalConductionPerpendicularFlowDirection = + HX_OuterWallThermalConductionPerpendicularFlowDirection, + redeclare final model WallThermalConductionFlowDirection = + HX_WallThermalConductionFlowDirection, + redeclare final model FluidThermalConvectionTubeInside = + HX_FluidThermalConvectionTubeInside, + redeclare final model PressureDrop = HX_PressureDrop, + final p_fluidAInitial=p_fluidAInitial, + final p_fluidBInitial=p_fluidBInitial, + final T_fluidAInitial=T_fluidAInitial, + final T_fluidBInitial=T_fluidBInitial, + final T_wallAInitial=T_wallAInitial, + final T_wallBInitial=T_wallBInitial, + final m_flow_start=m_flow_start, + final type_overallMassBalance=type_overallMassBalance, + final type_independentMassBalances=type_independentMassBalances, + final avoid_events=avoid_events, + final m_flow_small=m_flow_small, + final noDiff=noDiff) + "Heat exchanger tubes" + annotation (Placement(transformation(extent={{40,-90},{60,-70}}))); + + replaceable SorpLib.Basics.Volumes.BaseClasses.PartialVolume casing( + final useHeatPortsX=false, + final useHeatPortsY=true, + final useHeatPortsZ=false, + final type_energyBalance=type_energyBalance, + final avoid_events=avoid_events) if useCasing + "Casing" + annotation (Placement(transformation(extent={{-68,10},{-48,-10}}))); + + SorpLib.Components.HeatTransfer.GenericHeatTransfer heatTransfer_sorbentVolumesToCasing( + final n_a=no_sorbentVolumes, + final n_b=1, + final calculateFluidProperties=calcFluidTransportProperties, + redeclare final model HeatTransferCoefficient = VV_Casing) if + useCasing "Heat transfer from sorbent volumes to casing" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={-32,0}))); + + HeatTransfer.ConductionHeatTransfer thermalConduction_casing1( + final n_a=1, + final n_b=1, + final calculateFluidProperties=calcFluidTransportProperties, + redeclare final model HeatTransferCoefficient = + CS_InnerWallThermalConduction, + final no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes) if + (useCasing and useConductionCasing) + "Thermal conduction of the first casing half" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={-58,22}))); + + HeatTransfer.ConductionHeatTransfer thermalConduction_casing2( + final n_a=1, + final n_b=1, + final calculateFluidProperties=calcFluidTransportProperties, + redeclare final model HeatTransferCoefficient = + CS_OuterWallThermalConduction, + final no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes) if + (useCasing and useConductionCasing) + "Thermal conduction of the second casing half" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={-58,-22}))); + + // + // Definition of protected parameters + // +protected + final parameter Integer factorDiscretization= + integer(max(no_sorbentVolumes,no_wallVolumes)/ + min(no_sorbentVolumes,no_wallVolumes)) + "Discretization factor" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + +equation + // + // Assertations + // + if no_wallVolumes < no_fluidVolumes then + assert(rem(no_fluidVolumes, no_wallVolumes) == 0, + "Number of wall volumes must be a factor of the number of fluid volumes!"); + + elseif no_wallVolumes > no_fluidVolumes then + assert(rem(no_wallVolumes, no_fluidVolumes) == 0, + "Number of wall volumes must be a factor of the number of fluid volumes!"); + + end if; + + if no_wallVolumes < no_sorbentVolumes then + assert(rem(no_sorbentVolumes, no_wallVolumes) == 0, + "Number of wall volumes must be a factor of the number of sorbent volumes!"); + + elseif no_wallVolumes > no_sorbentVolumes then + assert(rem(no_wallVolumes, no_sorbentVolumes) == 0, + "Number of wall volumes must be a factor of the number of sorbent volumes!"); + + end if; + + // + // Connection of fluid ports + // + connect(port_a, heatExchangerTubes.fp_a) annotation (Line(points={{-100,0},{-80, + 0},{-80,-80},{40,-80}}, color={0,0,0})); + connect(heatExchangerTubes.fp_b, port_b) annotation (Line(points={{60,-80},{80, + -80},{80,0},{100,0}}, color={0,0,0})); + + // + // Connection of heat ports + // + + if useCasing then + if useConductionCasing then + connect(heatTransfer_sorbentVolumesToCasing.hp_b[1], + thermalConduction_casing1.hp_a[1]) annotation (Line( + points={{-40,4.44089e-16},{-42,4.44089e-16},{-42,32},{-58,32},{-58,30}}, + color={238,46,47}, + thickness=1)); + + connect(thermalConduction_casing1.hp_b[1], casing.hp_yMinus) annotation (Line( + points={{-58,14},{-58,6}}, + color={238,46,47}, + thickness=1)); + connect(casing.hp_yPlus, thermalConduction_casing2.hp_a[1]) annotation (Line( + points={{-58,-6},{-58,-14}}, + color={238,46,47}, + thickness=1)); + connect(thermalConduction_casing2.hp_b[1], hp_casing) annotation (Line( + points={{-58,-30},{-58,-32},{0,-32},{0,-60}}, + color={238,46,47}, + thickness=1)); + + else + connect(heatTransfer_sorbentVolumesToCasing.hp_b[1], hp_casing); + + end if; + end if; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle( + extent={{-100,60},{100,-60}}, + lineColor={0,0,0}, + lineThickness=1), + Line( + points={{100,40},{-80,40},{80,0},{-80,-40},{100,-40}}, + color={0,0,0}, + thickness=1), + Ellipse( + extent={{-74,42},{-80,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,42},{-20,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,42},{-32,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-38,42},{-44,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,42},{-56,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,42},{-68,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,42},{52,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,42},{40,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,42},{28,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,42},{16,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,42},{4,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-2,42},{-8,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,42},{64,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{82,42},{76,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{82,-48},{76,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,-48},{64,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,-48},{52,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,-48},{40,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,-48},{28,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,-48},{16,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,-48},{4,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-2,-48},{-8,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,-48},{-20,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,-48},{-32,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-38,-48},{-44,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,-48},{-56,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,-48},{-68,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-74,-48},{-80,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{88,-38},{82,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{76,-38},{70,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{64,-38},{58,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,-38},{46,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{40,-38},{34,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{28,-38},{22,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{16,-38},{10,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{4,-38},{-2,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,-38},{-14,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-20,-38},{-26,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-32,-38},{-38,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-44,-40},{-50,-34}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-44,34},{-50,40}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-32,32},{-38,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-20,32},{-26,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,32},{-14,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{4,32},{-2,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{16,32},{10,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{28,32},{22,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{40,32},{34,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,32},{46,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{64,32},{58,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{76,32},{70,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{88,32},{82,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,30},{-72,36}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-52,26},{-58,32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-36,22},{-42,28}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,18},{-24,24}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-4,14},{-10,20}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{12,10},{6,16}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,6},{24,12}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{44,2},{38,8}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{60,-2},{54,4}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,24},{-14,30}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{6,20},{0,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,16},{16,22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{38,12},{32,18}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,8},{46,14}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{68,4},{62,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,-36},{-72,-30}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-52,-32},{-58,-26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-36,-28},{-42,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,-24},{-24,-18}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-4,-20},{-10,-14}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{12,-16},{6,-10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,-12},{24,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{44,-8},{38,-2}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{68,-10},{62,-4}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,-14},{46,-8}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{38,-18},{32,-12}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{24,-22},{18,-16}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{6,-26},{0,-20}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,-30},{-14,-24}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-44,24},{-50,30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-54,34},{-60,40}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-76,34},{-82,40}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,42},{-14,48}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,26},{-20,32}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{4,12},{-2,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,14},{24,20}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,0},{46,6}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,32},{28,38}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{76,42},{70,48}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{82,32},{76,38}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{20,-14},{14,-8}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-28,-26},{-34,-20}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-52,-40},{-58,-34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-78,-42},{-84,-36}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-32,-48},{-38,-42}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,-38},{4,-32}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{40,-48},{34,-42}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,-38},{64,-32}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,-16},{40,-10}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid)}), + Diagram(coordinateSystem(extent={{-100,-100},{100,100}})), + Documentation(info="<html> +<p> +This partial model is the base model for all closed adsorber heat exchanger without vapor +volumes. It defines fundamental parameters, models, and variables required by all adsorbers. +Models that inherit properties from this partial model have to redeclare all partial models +(i.e., fluid ports, tube, vapor volume, and casing). Moreover, sorbent volumes must be +added as well as a mass transfer model describing the mass transfer between the sorbent +and vapor and a heat transfer model describing the heat transfer between the sorbent and +heat exchanger. These models are not inserted in the partial model to allow for designing +different heat exchanger cofigurations with various level of detal. Furthermore, +the geometry of the redeclared heat trasnfer must be correctly set using the geometry +record. In addition, the inputs 'fluidProperties' of the conductive heat transfer models +must be correctly set using properties of the casing. +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + Major adaptations due to restructering of the library and documentation. + </li> + <li> + January 19, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureSimpleComponentAdsorber; diff --git a/SorpLib/Components/HeatExchanger/BaseClasses/PartialSimpleCondenserEvaporator.mo b/SorpLib/Components/HeatExchanger/BaseClasses/PartialSimpleCondenserEvaporator.mo new file mode 100644 index 0000000000000000000000000000000000000000..b713eadb58ee32d55ef40a6b539d78850c9f1a38 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/BaseClasses/PartialSimpleCondenserEvaporator.mo @@ -0,0 +1,629 @@ +within SorpLib.Components.HeatExchanger.BaseClasses; +partial model PartialSimpleCondenserEvaporator + "Base model for all simple condensers and evaporators" + extends SorpLib.Components.HeatExchanger.BaseClasses.PartialHeatExchanger( + final p_initial, + final X_i_initial); + + // + // Definition of general parameters + // + parameter Integer nPortsLiquid = 0 + "Number of liquid VLE ports" + annotation (Dialog(connectorSizing=true), + HideResult = true); + parameter Integer nPortsVapor = 0 + "Number of vapor VLE ports" + annotation (Dialog(connectorSizing=true), + HideResult = true); + + parameter Integer no_fluidVolumes(min=2)=10 + "Discretization number of fluid volumes" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + parameter Integer no_wallVolumes(min=2)=no_fluidVolumes + "Discretization number of wall volumes (must be a factor of no_fluidVolumes)" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding the geometry + // + replaceable parameter SorpLib.Components.HeatExchanger.Records.GeometryCondenserEvaporator geometry + constrainedby + SorpLib.Components.HeatExchanger.Records.GeometryCondenserEvaporator( + no_fluidVolumes=no_fluidVolumes, + no_wallVolumes=no_wallVolumes) + "Geometry of the condenser or evaporator" + annotation (Dialog(tab = "General", group = "Geometry"), + choicesAllMatching = true); + + // + // Definition of parameters regarding the medium + // + parameter Integer no_VLEcomponents = 1 + "Number of components within the VLE" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of models describing transport phenomena + // + parameter Boolean useCasing = false + " = true, if casing is modeled" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useConductionCasing = true + " = true, if thermal conduction in the casing is modeled" + annotation (Dialog(tab="Transport Phenomena", group="General", + enable=useCasing), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useConductionPerpendicularFlowDirection = true + " = true, if thermal conduction perpendicular to the flow direction is + considered within the heat exchanger wall" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useConductionFlowDirection = false + " = true, if thermal conduction in the flow direction is considered within + the heat exchanger wall" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcFluidTransportProperties = true + " = true, if any transport model needs fluid or transport properties" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Integer fluidPropertyPosition = 1 + "Defines the position for fluid porperty calculation is discretization number + is different" + annotation (Dialog(tab="Transport Phenomena", group="General", + enable=no_fluidVolumes<>no_wallVolumes), + choices(choice=1 "First volume near port a", + choice=2 "First volume near port b", + choice=3 "Properties averaged over volumes"), + Evaluate=true, + HideResult=true); + + replaceable model HX_InnerWallThermalConductionPerpendicularFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_hx/geometry.no_wallVolumes, + d_inner=geometry.d_hydInner_hx, + d_outer=(geometry.d_hydInner_hx + geometry.d_hydOuter_hx)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction perpendicular to the + flow direction within the heat exchanger wall near the fluid" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionPerpendicularFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model HX_OuterWallThermalConductionPerpendicularFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_hx/geometry.no_wallVolumes, + d_inner=(geometry.d_hydInner_hx + geometry.d_hydOuter_hx)/2, + d_outer=geometry.d_hydOuter_hx) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction perpendicular to the + flow direction within the heat exchanger wall near the heat port" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionPerpendicularFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model HX_WallThermalConductionFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.PlainWall + ( + A_cross=geometry.A_crossWall_hx, + delta_wall=(geometry.l_hx/geometry.no_wallVolumes)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction in the flow direction + within the heat exchanger wall" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model CS_InnerWallThermalConduction = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_cas, + d_inner=geometry.d_hydInner_cas, + d_outer=(geometry.d_hydInner_cas + geometry.d_hydOuter_cas)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction within the casing + near the phase separator" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useCasing and useConductionCasing), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model CS_OuterWallThermalConduction = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l_cas, + d_inner=(geometry.d_hydInner_cas + geometry.d_hydOuter_cas)/2, + d_outer=geometry.d_hydOuter_cas) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction within the casing + near the heat port" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useCasing and useConductionCasing), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model HX_FluidThermalConvectionTubeInside = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.GnielinskiDittusBoelter + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialTubeInsideHeatTransferCoefficient + "Heat transfer correlation describing thermal convection at the tube inside + within the heat exchanger (i.e., form the fluid to the wall)" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Convection"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model PS_Casing = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlphaA + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialGenericHeatTransferCoefficient + "Heat transfer correlation describing the heat transfer between the phase + separator and casing" + annotation (Dialog(tab="Transport Phenomena", group="Generic", + enable = useCasing), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model HX_PressureDrop = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Konakov + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss + "Pressure drop correlation describing the pressure drop of the fluid within + the heat exchanger" + annotation (Dialog(tab="Transport Phenomena", group="Pressure Drop"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding initial values + // + parameter Modelica.Units.SI.Pressure p_fluidAInitial = 1.25e5 + "Initial value of fluid pressure at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + parameter Modelica.Units.SI.Pressure p_fluidBInitial = 1e5 + "Initial value of fluid pressure at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + parameter Modelica.Units.SI.Temperature T_fluidAInitial = 283.15 + "Initial value of fluid temperature at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + parameter Modelica.Units.SI.Temperature T_fluidBInitial = 303.15 + "Initial value of fluid temperature at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Fluid")); + + parameter Modelica.Units.SI.Temperature T_wallAInitial = T_fluidAInitial + "Initial value of wall temperature at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Wall")); + parameter Modelica.Units.SI.Temperature T_wallBInitial = T_fluidBInitial + "Initial value of wall temperature at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values - HX Wall")); + + parameter Modelica.Units.SI.Density d_phaseSeparatorInitial = 300 + "Initial value of phase separator density" + annotation (Dialog(tab="Initialisation", group="Initial Values - Phase Separator")); + parameter Modelica.Units.SI.Temperature T_phaseSeparatorInitial = 288.15 + "Initial value of phase separator temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values - Phase Separator")); + + parameter Modelica.Units.SI.Temperature T_casingInitial = 298.15 + "Initial value of casing temperature" + annotation (Dialog(tab="Initialisation", group="Initial Values - Casing", + enable=useCasing)); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.MassFlowRate m_flow_VLE_start = 1e-4 + "Start value for mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of ports + // + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_in[nPortsLiquid] liquidPort( + each final no_components=no_VLEcomponents, + each m_flow(start=m_flow_VLE_start)) + "Liquid port" + annotation (Placement(transformation(extent={{-10,-28},{10,-48}}), + iconTransformation(extent={{-10,-48},{10,-28}}))); + SorpLib.Basics.Interfaces.FluidPorts.VLEPort_out[nPortsVapor] vaporPort( + each final no_components=no_VLEcomponents, + each m_flow(start=-m_flow_VLE_start)) + "Vapor port" + annotation (Placement(transformation(extent={{-10,32},{10,52}}), + iconTransformation(extent={{-10,32},{10,52}}))); + + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in hp_casing if + useCasing + "Heat ports at casing" + annotation (Placement(transformation(extent={{-60,30},{-40,50}}), + iconTransformation(extent={{-60,30},{-40,50}}))); + + // + // Definition and instanziation of models + // + replaceable SorpLib.Basics.Volumes.BaseClasses.PartialPhaseSeparatorVolume + phaseSeparatorVolume( + final calculateAdditionalProperties=calcFluidTransportProperties, + final T_initial=T_phaseSeparatorInitial, + final rho_initial=d_phaseSeparatorInitial, + final mc_flow_initialX=m_flow_VLE_start, + redeclare final SorpLib.Basics.Volumes.Records.PhaseSeparatorGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_refrigerant, + A_base=geometry.A_refrigerant), + final useHeatPorts=true, + final useHeatPortsX=false, + final useHeatPortsY=true, + final useHeatPortsZ=false, + final type_energyBalance=type_energyBalance, + final type_overallMassBalance=type_overallMassBalance, + final avoid_events=avoid_events, + nPorts_cfp_xMinus=nPortsLiquid, + nPorts_cfp_xPlus=nPortsVapor) + "Phase separator" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,0}))); + + replaceable SorpLib.Components.Tubes.BaseClasses.PartialTube heatExchangerTubes( + final no_fluidVolumes=no_fluidVolumes, + final no_wallVolumes=no_wallVolumes, + redeclare final SorpLib.Components.Tubes.Records.GeometryTube geometry( + no_hydraulicParallelTubes=geometry.no_hydraulicParallelTubes, + l=geometry.l_hx, + roughness=geometry.roughness_hx, + d_inner=geometry.d_inner_hx, + d_outer=geometry.d_outer_hx, + d_hydInner=geometry.d_hydInner_hx, + d_hydOuter=geometry.d_hydOuter_hx, + t_wall=geometry.t_wall_hx, + A_crossInner=geometry.A_crossInner_hx, + A_crossOuter=geometry.A_crossOuter_hx, + A_crossWall=geometry.A_crossWall_hx, + A_hydCrossInner=geometry.A_hydCrossInner_hx, + A_hydCrossOuter=geometry.A_hydCrossOuter_hx, + A_hydCrossWall=geometry.A_hydCrossWall_hx, + A_heatTransferInner=geometry.A_heatTransferInner_hx, + A_heatTransferOuter=geometry.A_heatTransferOuter_hx, + f_finAreaRatioInner=geometry.f_finAreaRatioInner_hx, + f_finAreaRatioOuter=geometry.f_finAreaRatioOuter_hx, + V_inner=geometry.V_inner_hx, + V_outer=geometry.V_outer_hx, + V_wall=geometry.V_wall_hx, + f_finVolumeRatioInner=geometry.f_finVolumeRatioInner_hx, + f_finVolumeRatioOuter=geometry.f_finVolumeRatioOuter_hx), + final useConductionPerpendicularFlowDirection= + useConductionPerpendicularFlowDirection, + final useConductionFlowDirection=useConductionFlowDirection, + final calcFluidTransportProperties=calcFluidTransportProperties, + final fluidPropertyPosition=fluidPropertyPosition, + redeclare final model InnerWallThermalConductionPerpendicularFlowDirection = + HX_InnerWallThermalConductionPerpendicularFlowDirection, + redeclare final model OuterWallThermalConductionPerpendicularFlowDirection = + HX_OuterWallThermalConductionPerpendicularFlowDirection, + redeclare final model WallThermalConductionFlowDirection = + HX_WallThermalConductionFlowDirection, + redeclare final model FluidThermalConvectionTubeInside = + HX_FluidThermalConvectionTubeInside, + redeclare final model PressureDrop = HX_PressureDrop, + final p_fluidAInitial=p_fluidAInitial, + final p_fluidBInitial=p_fluidBInitial, + final T_fluidAInitial=T_fluidAInitial, + final T_fluidBInitial=T_fluidBInitial, + final T_wallAInitial=T_wallAInitial, + final T_wallBInitial=T_wallBInitial, + final m_flow_start=m_flow_start, + final type_overallMassBalance=type_overallMassBalance, + final type_independentMassBalances=type_independentMassBalances, + final avoid_events=avoid_events, + final m_flow_small=m_flow_small, + final noDiff=noDiff) + "Heat exchanger tubes" + annotation (Placement(transformation(extent={{40,-60},{60,-40}}))); + + replaceable SorpLib.Basics.Volumes.BaseClasses.PartialVolume casing( + final useHeatPortsX=false, + final useHeatPortsY=true, + final useHeatPortsZ=false, + final type_energyBalance=type_energyBalance, + final avoid_events=avoid_events) if useCasing + "Casing" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + + replaceable SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransfer + heatTransfer_HeatExchangerToPhaseSeparator( + final n_a=no_wallVolumes, + final n_b=1, + final calculateFluidProperties=calcFluidTransportProperties) + "Heat transfer from heat exchanger to phase separator" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={50,-20}))); + + SorpLib.Components.HeatTransfer.GenericHeatTransfer heatTransfer_phaseSeparatorToCasing( + final n_a=1, + final n_b=1, + final calculateFluidProperties=calcFluidTransportProperties, + redeclare final model HeatTransferCoefficient = + PS_Casing) if useCasing + "Heat transfer from phase seprator to casing" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={-24,0}))); + + HeatTransfer.ConductionHeatTransfer thermalConduction_casing1( + final n_a=1, + final n_b=1, + final calculateFluidProperties=calcFluidTransportProperties, + redeclare final model HeatTransferCoefficient = + CS_InnerWallThermalConduction, + final no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes) if + (useCasing and useConductionCasing) + "Thermal conduction of the first casing half" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-50,-24}))); + + HeatTransfer.ConductionHeatTransfer thermalConduction_casing2( + final n_a=1, + final n_b=1, + final calculateFluidProperties=calcFluidTransportProperties, + redeclare final model HeatTransferCoefficient = + CS_OuterWallThermalConduction, + final no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes) if + (useCasing and useConductionCasing) + "Thermal conduction of the second casing half" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-50,24}))); + +equation + // + // Assertations + // + if no_wallVolumes < no_fluidVolumes then + assert(rem(no_fluidVolumes, no_wallVolumes) == 0, + "Number of wall volumes must be a factor of the number of fluid volumes!"); + + elseif no_wallVolumes > no_fluidVolumes then + assert(rem(no_wallVolumes, no_fluidVolumes) == 0, + "Number of wall volumes must be a factor of the number of fluid volumes!"); + + end if; + + // + // Connection of fluid ports + // + connect(port_a, heatExchangerTubes.fp_a) annotation (Line(points={{-100,0},{-80, + 0},{-80,-50},{40,-50}}, color={0,0,0})); + connect(heatExchangerTubes.fp_b, port_b) annotation (Line(points={{60,-50},{80, + -50},{80,0},{100,0}}, color={0,0,0})); + connect(liquidPort, phaseSeparatorVolume.cfp_xMinus) annotation (Line( + points={{0,-38},{0,-20},{-1.8,-20},{-1.8,-4.2}}, + color={0,140,72}, + thickness=1)); + connect(vaporPort, phaseSeparatorVolume.cfp_xPlus) annotation (Line( + points={{0,42},{0,20},{-1.8,20},{-1.8,7.8}}, + color={0,140,72}, + thickness=1)); + + // + // Connection of heat ports + // + connect(heatExchangerTubes.hp_wall, + heatTransfer_HeatExchangerToPhaseSeparator.hp_a) annotation (Line( + points={{50,-46},{50,-28}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_HeatExchangerToPhaseSeparator.hp_b[1], + phaseSeparatorVolume.hp_yMinus) annotation (Line( + points={{50,-12},{50,0},{6,0}}, + color={238,46,47}, + thickness=1)); + + if useCasing then + connect(phaseSeparatorVolume.hp_yPlus, heatTransfer_phaseSeparatorToCasing.hp_a[ + 1]) annotation (Line( + points={{-6,0},{-16,0}}, + color={238,46,47}, + thickness=1)); + + if useConductionCasing then + connect(heatTransfer_phaseSeparatorToCasing.hp_b[1], + thermalConduction_casing1.hp_a[1]) annotation (Line( + points={{-32,0},{-36,0},{-36,-40},{-50,-40},{-50,-32}}, + color={238,46,47}, + thickness=1)); + connect(thermalConduction_casing1.hp_b[1], casing.hp_yMinus) annotation (Line( + points={{-50,-16},{-50,-6}}, + color={238,46,47}, + thickness=1)); + connect(casing.hp_yPlus, thermalConduction_casing2.hp_a[1]) annotation (Line( + points={{-50,6},{-50,16}}, + color={238,46,47}, + thickness=1)); + connect(thermalConduction_casing2.hp_b[1], hp_casing) annotation (Line( + points={{-50,32},{-50,40}}, + color={238,46,47}, + thickness=1)); + + else + connect(heatTransfer_phaseSeparatorToCasing.hp_b[1], hp_casing); + + end if; + end if; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100}, + {100,100}}), graphics={ + Text( + extent={{-60,30},{-40,10}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.None, + fontSize=20, + textString="1"), + Text( + extent={{40,30},{60,10}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.None, + fontSize=20, + textString="n"), + Line( + points={{0,40},{0,22},{-2,14},{2,0},{-2,-14},{2,-24},{0,-40}}, + color={0,0,0}, + smooth=Smooth.Bezier), + Rectangle( + extent={{-100,-2},{100,-40}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Polygon( + points={{-100,-10},{-80,8},{-54,-2},{-36,0},{-6,6},{14,-2},{42,4},{74, + 4},{94,-6},{-100,-10}}, + lineColor={28,108,200}, + lineThickness=0.5, + smooth=Smooth.Bezier, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{-100,40},{100,-40}}, + lineColor={0,0,0}, + lineThickness=1), + Polygon( + points={{-20,4},{-20,4},{-32,18},{-8,18},{-20,4}}, + lineColor={0,0,0}, + lineThickness=0.5), + Ellipse( + extent={{-66,38},{-78,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-28,38},{-40,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-12,38},{-24,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{16,22},{4,10}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{28,38},{16,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{36,22},{24,10}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,24},{-70,12}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{74,38},{62,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{48,38},{36,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{86,24},{74,12}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-84,34},{-96,22}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid)}), + Diagram(coordinateSystem(extent={{-100,-100},{100,100}})), + Documentation(info="<html> +<p> +This partial model is the base model for all condensers and evaporators. It defines +fundamental parameters, models, and variables required by all condensers and evaporators. +Models that inherit properties from this partial model have to redeclare all partial +models (i.e., fluid ports, tube, phase separator, casing, and heat transfer). Morover, +the geometry of the redeclared heat trasnfer must be correctly set using the geometry +record. In addition, the inputs 'fluidProperties' of the conductive heat transfer models +must be correctly set using properties of the casing. +</p> +</html>", revisions="<html> +<ul> + <li> + March 4, 2024, by Mirko Engelpracht:<br/> + Major adaptations due to restructering of the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation, including major revisions, after restructuring of the library. + </li> +</ul> +</html>")); +end PartialSimpleCondenserEvaporator; diff --git a/SorpLib/Components/HeatExchanger/BaseClasses/PartialSimpleDryCooler.mo b/SorpLib/Components/HeatExchanger/BaseClasses/PartialSimpleDryCooler.mo new file mode 100644 index 0000000000000000000000000000000000000000..b1342390c5d8f9fb34e4af20ced712dfb055f5f3 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/BaseClasses/PartialSimpleDryCooler.mo @@ -0,0 +1,392 @@ +within SorpLib.Components.HeatExchanger.BaseClasses; +partial model PartialSimpleDryCooler + "Base model for all simple dry coolers" + extends SorpLib.Components.HeatExchanger.BaseClasses.PartialHeatExchanger( + final type_energyBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + final type_independentMassBalances=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + final type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial); + + // + // Definition of general parameters + // + parameter Modelica.Units.SI.Pressure p_air = 1.01325e5 + "Ambient pressure (i.e., used to calculate air properties)" + annotation (Dialog(tab="General", group="Ambient Conditions")); + parameter Modelica.Units.SI.Temperature T_air_in = 273.15 + 25 + "Ambient temperature (i.e., used to calculate air properties)" + annotation (Dialog(tab="General", group="Ambient Conditions")); + + parameter Integer flowDirection = 1 + "Definition of flow direction of liquid stream: Relevant for energy balance" + annotation (Dialog(tab="General", group="Recooler Specifications"), + choices(choice=1 "A_to_B", + choice=2 "B_to_A", + choice=3 "Actual flow direction"), + Evaluate=true, + HideResult=true); + replaceable parameter SorpLib.Components.HeatExchanger.Records.ParametrizationDryCooler + typeDryRecooler + constrainedby + SorpLib.Components.HeatExchanger.Records.ParametrizationDryCooler + "Paremetrization record of recooler" + annotation (Dialog(tab="General", group="Recooler Specifications"), + Evaluate=true, + choicesAllMatching=true); + parameter Real scaleFactor = 1 + "Scaling factor for recooler: In reality, only integers are sound since + they correspond to the number of fans" + annotation (Dialog(tab="General", group="Recooler Specifications")); + + // + // Definition of scaled specification parameters + // + final parameter Modelica.Units.SI.MassFlowRate m_flow_liq_nom= + typeDryRecooler.m_flow_liq_nom * scaleFactor + "Scaled nominal mass flow rate of liquid" + annotation (HideResult=true); + final parameter Modelica.Units.SI.VolumeFlowRate V_flow_air_max= + typeDryRecooler.V_flow_air_max * scaleFactor + "Scaled maximal volume flow rate of air" + annotation (HideResult=true); + final parameter Modelica.Units.SI.Power P_el_fan_max= + typeDryRecooler.P_el_fan_max * scaleFactor + "Scaled maximal electrical power consumption of fan unit" + annotation (HideResult=true); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput relativeFanSpeed + "Input defining relative volume flow rate of air" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-60}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-60}))); + + // + // Definition of variables + // + Modelica.Units.SI.ThermalConductance UA_internal + "Internal effective heat trasfer coefficient (i.e., liquid side)"; + Modelica.Units.SI.ThermalConductance UA_external + "External effective heat trasfer coefficient (i.e., air side)"; + + Real C_air(unit="W/K") + "Heat capacity rate of air"; + Real C_liquid(unit="W/K") + "Heat capacity rate of liquid"; + Real C_min(unit="W/K") = min(C_air, C_liquid) + "Minimum heat capacity rate"; + Real C_max(unit="W/K") = max(C_air, C_liquid) + "Maximum heat capacity rate"; + Real C_ratio(unit="1") = C_min/C_max + "Ratio between minimum and maximum heat capacity rates"; + + Real NTU(unit="1") + "Number of transfer units"; + Real efficiency(unit="1") + "Efficiency of dry cooler"; + + Modelica.Units.SI.HeatFlowRate Q_flow_max + "Maximum heat flow rate that could be transferred"; + Modelica.Units.SI.HeatFlowRate Q_flow + "Actual heat flow rate that is transferred from liquid to air"; + + Modelica.Units.SI.MassFlowRate m_flow_air + "Mass flow rate of air"; + Modelica.Units.SI.VolumeFlowRate V_flow_air + "Volume flow rate of air"; + + Modelica.Units.SI.PressureDifference dp_liq + "Pressure drop at liquid side"; + + Modelica.Units.SI.Power P_el_fans + "Total electrical power consumption of fan unit"; + + // + // Definition of protected variables + // +protected + Modelica.Units.SI.Temperature T_liq_in + "Inlet temperature of liquid"; + Modelica.Units.SI.SpecificHeatCapacity cp_liq_in + "Specific heat capacity of liquid at inlet"; + Modelica.Units.SI.DynamicViscosity eta_liq_in + "Dynamic viscosity of liquid at inlet"; + + Modelica.Units.SI.Temperature T_air_out + "Outlet temperature of air"; + Modelica.Units.SI.Density d_air_in + "Density of air at inlet"; + Modelica.Units.SI.SpecificHeatCapacity cp_air_in + "Specific heat capacity of air at inlet"; + +equation + // + // Momentum balance + // + dp_liq = port_a.p - port_b.p + "Pressure drop of liquid"; + + // + // Mass balance + // + 0 = port_a.m_flow + port_b.m_flow + "Steady-state mass balance of liquid"; + + port_a.Xi_outflow = inStream(port_b.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + port_b.Xi_outflow = inStream(port_a.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + + // + // Energy balance + // + port_a.h_outflow = inStream(port_b.h_outflow) - Q_flow / port_b.m_flow + "Steady-state energy balance depends on the flow direction"; + port_b.h_outflow = inStream(port_a.h_outflow) - Q_flow / port_a.m_flow + "Steady-state energy balance depends on the flow direction"; + + T_air_out = T_air_in + Q_flow/scaleFactor / C_air + "Outlet temperature of air: Rescaling (see calculation of C_air)"; + + // + // NTU-method for heat exchangers + // + V_flow_air = V_flow_air_max * relativeFanSpeed + "Calculate actual volume flow rate of air (i.e., corresponds to load of dry + cooler)"; + m_flow_air = V_flow_air * d_air_in + "Mass flow rate of air"; + + UA_internal = 2 * typeDryRecooler.delta * + (((abs(port_a.m_flow) / scaleFactor)^0.8) / (eta_liq_in^0.5)) + "Internal effective heat transfer coefficient: Division by scaling factor + since mass flow rate is devided equally between fan units"; + UA_external = 0.35 * typeDryRecooler.gamma * cp_air_in * + ((m_flow_air / scaleFactor)^0.8) + "External effective heat transfer coefficient: Division by scaling factor + since mass flow rate is devided equally between fan units"; + + C_air = m_flow_air/scaleFactor * cp_air_in + "Heat capacity rate of air: Division by scaling factor + since mass flow rate is devided equally between fan units"; + C_liquid = abs(port_a.m_flow)/scaleFactor * cp_liq_in + "Heat capacity rate of liquid: Division by scaling factor + since mass flow rate is devided equally between fan units"; + + NTU = (UA_external * UA_internal / (UA_external + UA_internal)) / C_min + "Number of transfer units"; + efficiency = (1 - exp(-NTU * (1 -C_ratio))) / + (1 - C_ratio * exp(-NTU * (1 - C_ratio))) + "Efficiency of dry cooler: Counter-flow arrangement"; + + Q_flow_max = C_min * (T_liq_in-T_air_in) * scaleFactor + "Maximum heat flow rate that could be transferred theoretically: + Rescaling (see calculation of C_i)"; + Q_flow = Q_flow_max * efficiency + "Actual heat flow rate that is transferred"; + + // + // Apply affinity laws for pressure drop and power consumption calculations + // + if avoid_events then + dp_liq = typeDryRecooler.dp_liq_nom * SorpLib.Numerics.regSquare_noEvent( + x=port_a.m_flow, + delta_x=max(m_flow_small, 0.005 * m_flow_liq_nom)) / + m_flow_liq_nom^2 + "Pressure drop of liquid"; + + else + dp_liq = typeDryRecooler.dp_liq_nom * SorpLib.Numerics.regSquare( + x=port_a.m_flow, + delta_x=max(m_flow_small, 0.005 * m_flow_liq_nom)) / + m_flow_liq_nom^2 + "Pressure drop of liquid"; + + end if; + + P_el_fans = ((V_flow_air / V_flow_air_max)^3) * P_el_fan_max + "Total electrical power consumption of fan unit"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all simple dry coolers. It defines the +required parameters and variables and adds all relevant equations. Models that +inherit properties from this partial model have to redeclare the fluid ports. Moreover, +fluid properties at inlets must be added. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Liquid inlet temperature <i>T_liq_in</i>. + </li> + <li> + Specific heat capacity of the liquid at the inlet <i>cp_liq_in</i>. + </li> + <li> + Dynamic viscosity of the liquid at the inlet <i>eta_liq_in</i>. + </li> + <br/> + <li> + Specific heat capacity of the air at the inlet <i>cp_air_in</i>. + </li> + <li> + Density of the air at the inlet <i>d_air_in</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 26, 2024, by Mirko Engelpracht:<br/> + Minor adaptations and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Polygon( + points={{-100,40},{-100,-40},{-60,-60},{60,-60},{100,-40},{100,40},{60, + 60},{-60,60},{-100,40}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Line( + points={{-100,0},{-80,60},{-60,-60},{-40,60},{-20,-60},{0,60},{20,-60}, + {40,60},{60,-60},{80,60},{98,0}}, + color={28,108,200}, + thickness=1, + smooth=Smooth.Bezier), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-60,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-40,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-20,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={0,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={20,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={40,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={60,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-60,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-40,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-20,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={0,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={20,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={40,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={60,46}, + rotation=180), + Ellipse( + extent={{-60,64},{0,58}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{0,64},{60,58}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid)})); +end PartialSimpleDryCooler; diff --git a/SorpLib/Components/HeatExchanger/BaseClasses/package.mo b/SorpLib/Components/HeatExchanger/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..449bcda2f5b5810474e24fc0ab5ba09fcd751e7c --- /dev/null +++ b/SorpLib/Components/HeatExchanger/BaseClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.HeatExchanger; +package BaseClasses "Base models and functions for all heat exchangers" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial heat exchanger models, containing fundamental +definitions for heat exchangers. The content of this package is only of interest +when adding new heat exchangers to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Components/HeatExchanger/BaseClasses/package.order b/SorpLib/Components/HeatExchanger/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..d77267ef67a2b04031bd404584cb634d0416a87d --- /dev/null +++ b/SorpLib/Components/HeatExchanger/BaseClasses/package.order @@ -0,0 +1,5 @@ +PartialHeatExchanger +PartialSimpleCondenserEvaporator +PartialSimpleDryCooler +PartialPureComponentAdsorber +PartialPureSimpleComponentAdsorber diff --git a/SorpLib/Components/HeatExchanger/CondensersEvaporators/SimpleCondenser.mo b/SorpLib/Components/HeatExchanger/CondensersEvaporators/SimpleCondenser.mo new file mode 100644 index 0000000000000000000000000000000000000000..53088a82f20c1ad2948d0838489ec65a8952de10 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/CondensersEvaporators/SimpleCondenser.mo @@ -0,0 +1,155 @@ +within SorpLib.Components.HeatExchanger.CondensersEvaporators; +model SimpleCondenser "Simple condenser for a pure component" + extends SorpLib.Components.HeatExchanger.BaseClasses.PartialSimpleCondenserEvaporator( + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + final no_components=MediumHX.nX, + final no_VLEcomponents=MediumPS.nX, + redeclare SorpLib.Components.Tubes.LiquidTube heatExchangerTubes( + redeclare final package Medium = MediumHX, + redeclare model WallMaterial = WallMaterialHX), + redeclare SorpLib.Basics.Volumes.PhaseSeparatorVolumes.PhaseSeparatorVolume + phaseSeparatorVolume( + redeclare final package Medium = MediumPS), + redeclare SorpLib.Basics.Volumes.SolidVolumes.SolidVolume casing( + redeclare final WallMaterialCS solidMedium, + redeclare final SorpLib.Basics.Volumes.Records.VolumeGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_wall_cas), + final T_initial=T_casingInitial, + final p=phaseSeparatorVolume.p, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX), + redeclare SorpLib.Components.HeatTransfer.PoolCondensationHeatTransfer + heatTransfer_HeatExchangerToPhaseSeparator( + redeclare final model HeatTransferCoefficient = PS_HeatExchanger, + final fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=phaseSeparatorVolume.p, + T=phaseSeparatorVolume.T, + rho=phaseSeparatorVolume.rho, + cp=phaseSeparatorVolume.phaseSepratorProperties.cp, + eta=phaseSeparatorVolume.phaseSepratorProperties.eta, + lambda=phaseSeparatorVolume.phaseSepratorProperties.lambda), + final f_relativeFillingLevel=phaseSeparatorVolume.l_liq_rel), + thermalConduction_casing1(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda)), + thermalConduction_casing2(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda))); + + // + // Definition of parameters + // + replaceable package MediumHX = + Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid in the heat exchanger" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable package MediumPS = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the real fluid in the phase separator" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model WallMaterialHX = + SorpLib.Media.Solids.MetalsAndMetalAlloys.Copper + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Heat exchanger wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable model WallMaterialCS = + Media.Solids.MetalsAndMetalAlloys.StainlessSteel_X5CrNi18_10 + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Casing wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of tranport phenomena + // + replaceable model PS_HeatExchanger = + HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation.LinearAlphaA_fRel + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolCondensationHeatTransferCoefficient + "Heat transfer correlation describing the condensation at the outside of the + heat exchanger tubes" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Convection"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + SorpLib.Components.HeatExchanger.Records.SummaryCondenserEvaporator summary( + final p_VLE=phaseSeparatorVolume.p, + final rho_VLE=phaseSeparatorVolume.rho, + final T_VLE=phaseSeparatorVolume.T, + final mass=phaseSeparatorVolume.m, + final p_liq_inlet=heatExchangerTubes.state_a.p, + final p_liq_outlet=heatExchangerTubes.state_b.p, + final p_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.p)/ + heatExchangerTubes.no_fluidVolumes, + final T_liq_inlet=heatExchangerTubes.state_a.T, + final T_liq_outlet=heatExchangerTubes.state_b.T, + final T_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.T)/ + heatExchangerTubes.no_fluidVolumes, + final T_wall_avg=sum(heatExchangerTubes.wallVolumes.T)/ + heatExchangerTubes.no_wallVolumes, + final m_flow_liq_inlet=port_a.m_flow, + final m_flow_liq_outlet=port_b.m_flow, + final m_flow_vapor=sum(vaporPort.m_flow), + final m_flow_liquid=sum(liquidPort.m_flow), + final Q_flow_wallToPhaseSeparator=heatExchangerTubes.Q_flow_wallHP, + final Q_flow_fluidWall=heatExchangerTubes.Q_flow_fluidWall, + final DH_liquid=heatExchangerTubes.DH_flow) + "Summary record"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +TO BE ADDED +</p> +</html>", revisions="<html> +<ul> + <li> + March 4, 2024, by Mirko Engelpracht:<br/> + Minor adaptations due to restructering of the library. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SimpleCondenser; diff --git a/SorpLib/Components/HeatExchanger/CondensersEvaporators/SimpleEvaporator.mo b/SorpLib/Components/HeatExchanger/CondensersEvaporators/SimpleEvaporator.mo new file mode 100644 index 0000000000000000000000000000000000000000..8c82c57595d35866737ad83ee87cb297f3179e22 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/CondensersEvaporators/SimpleEvaporator.mo @@ -0,0 +1,156 @@ +within SorpLib.Components.HeatExchanger.CondensersEvaporators; +model SimpleEvaporator "Simple evaporator for a pure component" + extends + SorpLib.Components.HeatExchanger.BaseClasses.PartialSimpleCondenserEvaporator( + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + final no_components=MediumHX.nX, + final no_VLEcomponents=MediumPS.nX, + redeclare SorpLib.Components.Tubes.LiquidTube heatExchangerTubes( + redeclare final package Medium = MediumHX, + redeclare model WallMaterial = WallMaterialHX), + redeclare SorpLib.Basics.Volumes.PhaseSeparatorVolumes.PhaseSeparatorVolume + phaseSeparatorVolume( + redeclare final package Medium = MediumPS), + redeclare SorpLib.Basics.Volumes.SolidVolumes.SolidVolume casing( + redeclare final WallMaterialCS solidMedium, + redeclare final SorpLib.Basics.Volumes.Records.VolumeGeometry geometry( + dx=0, + dy=0, + dz=0, + A_xy=0, + A_xz=0, + A_yz=0, + V=geometry.V_wall_cas), + final T_initial=T_casingInitial, + final p=phaseSeparatorVolume.p, + independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX), + redeclare SorpLib.Components.HeatTransfer.PoolBoilingHeatTransfer + heatTransfer_HeatExchangerToPhaseSeparator( + redeclare final model HeatTransferCoefficient = PS_HeatExchanger, + final fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=phaseSeparatorVolume.p, + T=phaseSeparatorVolume.T, + rho=phaseSeparatorVolume.rho, + cp=phaseSeparatorVolume.phaseSepratorProperties.cp, + eta=phaseSeparatorVolume.phaseSepratorProperties.eta, + lambda=phaseSeparatorVolume.phaseSepratorProperties.lambda), + final f_relativeFillingLevel=phaseSeparatorVolume.l_liq_rel), + thermalConduction_casing1(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda)), + thermalConduction_casing2(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=casing.solidProperties.p, + T=casing.solidProperties.T, + rho=1/casing.solidProperties.v, + cp=casing.solidProperties.c, + eta=0, + lambda=casing.solidProperties.lambda))); + + // + // Definition of parameters + // + replaceable package MediumHX = + Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid in the heat exchanger" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable package MediumPS = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the real fluid in the phase separator" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model WallMaterialHX = + SorpLib.Media.Solids.MetalsAndMetalAlloys.Copper + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Heat exchanger wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + replaceable model WallMaterialCS = + Media.Solids.MetalsAndMetalAlloys.StainlessSteel_X5CrNi18_10 + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Casing wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of tranport phenomena + // + replaceable model PS_HeatExchanger = + HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling.LinearAlphaA_fRel + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolBoilingHeatTransferCoefficient + "Heat transfer correlation describing the boiling at the outside of the + heat exchanger tubes" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Convection"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + SorpLib.Components.HeatExchanger.Records.SummaryCondenserEvaporator summary( + final p_VLE=phaseSeparatorVolume.p, + final rho_VLE=phaseSeparatorVolume.rho, + final T_VLE=phaseSeparatorVolume.T, + final mass=phaseSeparatorVolume.m, + final p_liq_inlet=heatExchangerTubes.state_a.p, + final p_liq_outlet=heatExchangerTubes.state_b.p, + final p_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.p)/ + heatExchangerTubes.no_fluidVolumes, + final T_liq_inlet=heatExchangerTubes.state_a.T, + final T_liq_outlet=heatExchangerTubes.state_b.T, + final T_liq_avg=sum(heatExchangerTubes.fluidVolumes.fluidProperties.T)/ + heatExchangerTubes.no_fluidVolumes, + final T_wall_avg=sum(heatExchangerTubes.wallVolumes.T)/ + heatExchangerTubes.no_wallVolumes, + final m_flow_liq_inlet=port_a.m_flow, + final m_flow_liq_outlet=port_b.m_flow, + final m_flow_vapor=sum(vaporPort.m_flow), + final m_flow_liquid=sum(liquidPort.m_flow), + final Q_flow_wallToPhaseSeparator=heatExchangerTubes.Q_flow_wallHP, + final Q_flow_fluidWall=heatExchangerTubes.Q_flow_fluidWall, + final DH_liquid=heatExchangerTubes.DH_flow) + "Summary record"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +TO BE ADDED +</p> +</html>", revisions="<html> +<ul> + <li> + March 4, 2024, by Mirko Engelpracht:<br/> + Minor adaptations due to restructering of the library. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SimpleEvaporator; diff --git a/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/Test_SimpleCondenser.mo b/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/Test_SimpleCondenser.mo new file mode 100644 index 0000000000000000000000000000000000000000..a6d024eb4ef38aa42cabb0f155e7db788e9dbdcb --- /dev/null +++ b/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/Test_SimpleCondenser.mo @@ -0,0 +1,130 @@ +within SorpLib.Components.HeatExchanger.CondensersEvaporators.Tester; +model Test_SimpleCondenser "Tester for the simple condenser" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=false, + use_VFlowInput=true, + V_flow_fixed=-10/60/1000, + T_fixed=298.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=358.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource vaporSource( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=353.15) "Vapor Source" annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={0,30}))); + + // + // Definition of models + // + SorpLib.Components.HeatExchanger.CondensersEvaporators.SimpleCondenser condenser( + geometry(d_inner_cas=0.05, d_outer_cas=0.055), + useCasing=true, + redeclare model HX_FluidThermalConvectionTubeInside = + HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.Schmidt, + redeclare model HX_PressureDrop = + Fittings.PressureLossCorrelations.TubeInside.MishraGupaSchmidt, + redeclare package MediumHX = Medium, + redeclare model PS_HeatExchanger = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation.LinearAlphaA_fRel, + nPortsVapor=1) "Condenser model" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_V_flow( + amplitude=5/1000/60, + f=1/500, + offset=-10/1000/60) "Input signal for volume flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=1e5, + duration=2500, + offset=2e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + Modelica.Blocks.Sources.Ramp input_TWall( + height=-0.001, + duration=2000, + offset=0, + startTime=500) "Input signal for wall temperature boundary" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,60}))); + +equation + // + // Connections + // + connect(fs_a.port, condenser.port_a) annotation (Line( + points={{-60,0},{-10,0}}, + color={28,108,200}, + thickness=1)); + connect(condenser.port_b, fs_b.port) annotation (Line( + points={{10,0},{60,0}}, + color={28,108,200}, + thickness=1)); + connect(vaporSource.port, condenser.vaporPort[1]) annotation (Line( + points={{0,30},{0,4.2}}, + color={0,140,72}, + thickness=1)); + + connect(input_V_flow.y, fs_a.V_flow_input) annotation (Line(points={{-79,0},{-70, + 0},{-70,2},{-61.2,2}}, color={0,0,127})); + connect(input_p.y, fs_b.p_input) + annotation (Line(points={{79,0},{70,0},{70,5},{61.2,5}}, color={0,0,127})); + connect(input_TWall.y, vaporSource.m_flow_input) annotation (Line(points={{0,49}, + {0,40},{-2,40},{-2,31.2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=2500), Documentation(info="<html> +<p> +This model checks the simple condenser. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + March 4, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_SimpleCondenser; diff --git a/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/Test_SimpleEvaporator.mo b/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/Test_SimpleEvaporator.mo new file mode 100644 index 0000000000000000000000000000000000000000..c97a8d07966ef835c8ee2642209f76646d51e83d --- /dev/null +++ b/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/Test_SimpleEvaporator.mo @@ -0,0 +1,130 @@ +within SorpLib.Components.HeatExchanger.CondensersEvaporators.Tester; +model Test_SimpleEvaporator "Tester for the simple evaporator" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=false, + use_VFlowInput=true, + V_flow_fixed=-10/60/1000, + T_fixed=298.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=358.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource vaporSource( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=288.15) "Vapor Source" annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={0,30}))); + + // + // Definition of models + // + SorpLib.Components.HeatExchanger.CondensersEvaporators.SimpleEvaporator evaporator( + geometry(d_inner_cas=0.05, d_outer_cas=0.055), + redeclare model HX_FluidThermalConvectionTubeInside = + HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.GnielinskiDittusBoelter, + + redeclare model HX_PressureDrop = + Fittings.PressureLossCorrelations.TubeInside.PrandtlKarman, + redeclare package MediumHX = Medium, + redeclare model PS_HeatExchanger = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling.LinearAlphaA_fRel, + nPortsVapor=1) "Evaporator model" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_V_flow( + amplitude=5/1000/60, + f=1/500, + offset=-10/1000/60) "Input signal for volume flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=1e5, + duration=2500, + offset=2e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + Modelica.Blocks.Sources.Ramp input_TWall( + height=0.001, + duration=2000, + offset=0, + startTime=500) "Input signal for wall temperature boundary" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,60}))); + +equation + // + // Connections + // + connect(fs_a.port, evaporator.port_a) annotation (Line( + points={{-60,0},{-10,0}}, + color={28,108,200}, + thickness=1)); + connect(evaporator.port_b, fs_b.port) annotation (Line( + points={{10,0},{60,0}}, + color={28,108,200}, + thickness=1)); + connect(vaporSource.port, evaporator.vaporPort[1]) annotation (Line( + points={{0,30},{0,4.2}}, + color={0,140,72}, + thickness=1)); + + connect(input_V_flow.y, fs_a.V_flow_input) annotation (Line(points={{-79,0},{-70, + 0},{-70,2},{-61.2,2}}, color={0,0,127})); + connect(input_p.y, fs_b.p_input) + annotation (Line(points={{79,0},{70,0},{70,5},{61.2,5}}, color={0,0,127})); + connect(input_TWall.y, vaporSource.m_flow_input) annotation (Line(points={{0,49}, + {0,40},{-2,40},{-2,31.2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=2500), Documentation(info="<html> +<p> +This model checks the simple evaporator. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + March 4, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_SimpleEvaporator; diff --git a/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/package.mo b/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..db79882d47ee5cbe50a77932a0de80a9c7743f28 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.HeatExchanger.CondensersEvaporators; +package Tester "Models to test and varify condensers and evaporators" + extends Modelica.Icons.ExamplesPackage; + + + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all condensres and evaporators. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/package.order b/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..9e25a94c524f008f67dac1b351f78ddf922cab2a --- /dev/null +++ b/SorpLib/Components/HeatExchanger/CondensersEvaporators/Tester/package.order @@ -0,0 +1,2 @@ +Test_SimpleCondenser +Test_SimpleEvaporator diff --git a/SorpLib/Components/HeatExchanger/CondensersEvaporators/package.mo b/SorpLib/Components/HeatExchanger/CondensersEvaporators/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..46a0a6e0719ee7225102939ec5c70dc10c105080 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/CondensersEvaporators/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.HeatExchanger; +package CondensersEvaporators "Condensers and evaporators used in closed sorption systems" + extends SorpLib.Icons.CondensersEvaporatorsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains condensers and evaporators that are based on the Modelica +Standard Library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end CondensersEvaporators; diff --git a/SorpLib/Components/HeatExchanger/CondensersEvaporators/package.order b/SorpLib/Components/HeatExchanger/CondensersEvaporators/package.order new file mode 100644 index 0000000000000000000000000000000000000000..78303dfa5bfe3709686184162f1bd2cc45222c73 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/CondensersEvaporators/package.order @@ -0,0 +1,3 @@ +SimpleCondenser +SimpleEvaporator +Tester diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Geometry/HXGeometry.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Geometry/HXGeometry.mo deleted file mode 100644 index 05cfdd8685299f127deb155280cac56ceb326d7f..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Geometry/HXGeometry.mo +++ /dev/null @@ -1,60 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow.Geometry; -record HXGeometry - "Geometry record for air air counterflow heat exchanger" - extends SorpLib.Internals.ClassTypes.Record; - - parameter Modelica.SIunits.Length length(start = 1) "total length of heat exchanger"; - - parameter Modelica.SIunits.Length width(start = 1) "total width of heat exchanger"; - - parameter Modelica.SIunits.Length heightDuct1(start=0.0035) - "height of one duct (fluid 1)"; - - parameter Modelica.SIunits.Length heightDuct2(start=0.0035) - "height of one duct (fluid 2)"; - - parameter Modelica.SIunits.Length tSheet(start=0.0003) - "thickness of thermal sheet layer between fluid ducts"; - - parameter Modelica.SIunits.Length tCasing(start=0.003) - "thickness of casing wall"; - - parameter Integer numDucts(min=1,start=10) - "Number of alternating duct layers"; - - final parameter Modelica.SIunits.Length totalheight=numDucts*(heightDuct1 + - heightDuct2) + (2*numDucts - 1)*tSheet + 2*tCasing - "total height of heat exchanger"; - - final parameter Real ratioDuctheight=heightDuct1/heightDuct2 - "ratio of duct height 1 to duct height 2"; - - final parameter Modelica.SIunits.Diameter hydraulicDiameter1=numDucts*2*heightDuct1*width/(numDucts*heightDuct1+width) - "hydraulic diameter of sum of all ducts 1"; - - final parameter Modelica.SIunits.Diameter hydraulicDiameter2=numDucts*2*heightDuct2*width/(numDucts*heightDuct2+width) - "hydraulic diameter of sum of all ducts 2"; - - final parameter Modelica.SIunits.Area flowCrossSection1=numDucts*heightDuct1*width - "Cross-sectional area of all ducts 1"; - - final parameter Modelica.SIunits.Area flowCrossSection2=numDucts*heightDuct2*width - "Cross-sectional area of all ducts 2"; - - final parameter Modelica.SIunits.Area areaHX=(2*numDucts - 1)*length*width - "total heat-exchange-surface for one fluid"; - - annotation (Documentation(info="<html> - <p> - This record containes all information necessary to describe an air/air counterflow heat exchanger. <br> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 11, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end HXGeometry; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Geometry/package.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Geometry/package.mo deleted file mode 100644 index 9f6462ceb4fe170f3f126bb562abadb74efeb7d2..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Geometry/package.mo +++ /dev/null @@ -1,11 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow; -package Geometry -extends SorpLib.Internals.ClassTypes.RecordPackage; - - - - - -annotation (Documentation(info="<html> -</html>")); -end Geometry; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Geometry/package.order b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Geometry/package.order deleted file mode 100644 index 9a0b5014c3e010e92505353bae0b2669d3d6dea3..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Geometry/package.order +++ /dev/null @@ -1 +0,0 @@ -HXGeometry diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HXAirAirParallelflow.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HXAirAirParallelflow.mo deleted file mode 100644 index f793d15e8d5dbca50189e72df30a08ddfd048577..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HXAirAirParallelflow.mo +++ /dev/null @@ -1,434 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow; -model HXAirAirParallelflow "counterflow air-air heat exchanger" - - /*********************** SIM ***********************************/ - inner parameter TILMedia.GasTypes.BaseGas gasType=sim.gasType1 "Gas type" - annotation (Dialog(tab="SIM", group="SIM"), choices(choice=sim.gasType1 - "Gas 1 as defined in SIM", choice=sim.gasType2 - "Gas 2 as defined in SIM")); -protected - outer TIL.SystemInformationManager sim "System Information Manager"; - TIL.Internals.SimPort simPort; - - /************************** Connectors ***********************************/ - -public - TIL.Connectors.GasPort gasPort1A(final gasType=gasType) annotation (Placement( - transformation(extent={{-110,38},{-90,58}}), iconTransformation(extent={{-110,38}, - {-90,58}}))); - TIL.Connectors.GasPort gasPort1B(final gasType=gasType) annotation (Placement( - transformation(extent={{90,38},{110,58}}), iconTransformation(extent={{90,38}, - {110,58}}))); - TIL.Connectors.GasPort gasPort2B(final gasType=gasType) annotation (Placement( - transformation(extent={{-110,-56},{-90,-36}}), iconTransformation( - extent={{-110,-56},{-90,-36}}))); - TIL.Connectors.GasPort gasPort2A(final gasType=gasType) annotation (Placement( - transformation(extent={{90,-56},{110,-36}}), iconTransformation(extent={{90,-56}, - {110,-36}}))); - - /************************ Gas objects *************************/ - - TILMedia.Gas_ph gas1A( - final gasType=gasType, - final h=noEvent(actualStream(gasPort1A.h_outflow)), - final p=gasPort1A.p, - final xi=noEvent(actualStream(gasPort1A.xi_outflow))) - annotation (Placement(transformation(extent={{-80,18},{-60,38}}))); - TILMedia.Gas_ph gas1B( - final gasType=gasType, - final h=noEvent(actualStream(gasPort1B.h_outflow)), - final p=gasPort1B.p, - final xi=noEvent(actualStream(gasPort1B.xi_outflow))) - annotation (Placement(transformation(extent={{60,18},{80,38}}))); - TILMedia.Gas_ph gas2A( - final gasType=gasType, - final h=noEvent(actualStream(gasPort2A.h_outflow)), - final p=gasPort2A.p, - final xi=noEvent(actualStream(gasPort2A.xi_outflow))) - annotation (Placement(transformation(extent={{58,-42},{78,-22}}))); - TILMedia.Gas_ph gas2B( - final gasType=gasType, - final p=gasPort2B.p, - final h=noEvent(actualStream(gasPort2B.h_outflow)), - final xi=noEvent(actualStream(gasPort2B.xi_outflow))) - annotation (Placement(transformation(extent={{-80,-42},{-60,-22}}))); - - /******************** Geometry characteristics ***********************/ - - parameter Integer nCells(min=1) = 1 "Number of discretization cells" - annotation (Dialog(group="Discretization")); - - replaceable parameter Geometry.HXGeometry hxGeometry - constrainedby Geometry.HXGeometry "Heat exchanger geometry" - annotation (Dialog(group="Heat exchanger geometry"), - choicesAllMatching=true, Placement(transformation(extent={{58,-138},{78, - -118}}))); - - /************************** Components ************************************/ - - /************************** Gas volume **********************************/ - - Cells.Gas.Gas[nCells] gas1( - each final cellGeometry( - length=hxGeometry.length/nCells, - hydraulicDiameter=hxGeometry.hydraulicDiameter1, - flowCrossSection=hxGeometry.flowCrossSection1, - psi=1), - each final gasType=gasType, - each final TInitial=TInitial1, - each final xiInitial=xiInitial1, - each final pInitial=pInitial1, - each final m_flowStart=m_flowStart1, - each final generateEventsAtFlowReversal=generateEventsAtFlowReversal, - each final HydraulicMassFlowPosition=HydraulicMassFlowPosition1, - each final computeTransportProperties=computeTransportProperties1, - redeclare each final model PressureDropModel = PressureDrop1, - final fixedInitialPressure=cat(1, {fixedInitialPressure_firstCell1}, {fixedInitialPressure1 for i in 2:nCells})) - annotation (Placement(transformation(extent={{-10,40},{10,60}}))); - - Cells.Gas.Gas[nCells] gas2( - each final cellGeometry( - length=hxGeometry.length/nCells, - hydraulicDiameter=hxGeometry.hydraulicDiameter2, - flowCrossSection=hxGeometry.flowCrossSection2, - psi=1), - each final gasType=gasType, - each final TInitial=TInitial2, - each final xiInitial=xiInitial2, - each final pInitial=pInitial2, - each final m_flowStart=m_flowStart2, - each final generateEventsAtFlowReversal=generateEventsAtFlowReversal, - each final HydraulicMassFlowPosition=HydraulicMassFlowPosition2, - each final computeTransportProperties=computeTransportProperties2, - redeclare each final model PressureDropModel = PressureDrop2, - final fixedInitialPressure=cat(1, {fixedInitialPressure_firstCell2}, {fixedInitialPressure2 for i in 2:nCells})) - annotation (Placement(transformation( - extent={{-10,-10},{10,10}}, - rotation=180, - origin={0,-50}))); - - /********************** Pressure drop in gas cell **************************/ - - replaceable model PressureDrop1 = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.Partial.PartialPressureDrop - constrainedby - SorpLib.Components.Cells.Gas.PressureDropCorrelations.Partial.PartialPressureDrop - "Pressure drop model for fluid 1" annotation ( - Placement(transformation(extent={{-36,-40},{-16,-20}})), - choices( - choice(redeclare model PressureDrop1 = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.ZeroPressureDrop - "no pressure drop: dp = 0"), - choice(redeclare model PressureDrop1 = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.ConstantResistanceCoefficient - "constant pressure drop coefficient: zeta = konst"), - choice(redeclare model PressureDrop1 = - SorpLib.Components.HeatExchanger.HXAirAirParallelflow.PressureDropCorrelations.VDIWaermeatlasN6 - "pressure drop calculated using VDI Waermeatlas (N6)")), - Dialog(group="Pressure drop")); - - replaceable model PressureDrop2 = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.Partial.PartialPressureDrop - constrainedby - SorpLib.Components.Cells.Gas.PressureDropCorrelations.Partial.PartialPressureDrop - "Pressure drop model for fluid 2" annotation ( - Placement(transformation(extent={{-36,-40},{-16,-20}})), - choices( - choice(redeclare model PressureDrop2 = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.ZeroPressureDrop - "no pressure drop: dp = 0"), - choice(redeclare model PressureDrop2 = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.ConstantResistanceCoefficient - "constant pressure drop coefficient: zeta = konst"), - choice(redeclare model PressureDrop2 = - SorpLib.Components.HeatExchanger.HXAirAirParallelflow.PressureDropCorrelations.VDIWaermeatlasN6 - "pressure drop calculated using VDI Waermeatlas (N6)")), - Dialog(group="Pressure drop")); - - /************************** Wall ***************************************/ - - Cells.Wall.Wall[nCells] wall( - each final volume=hxGeometry.width*hxGeometry.length*hxGeometry.tSheet*2*(hxGeometry.numDucts + 0.5)/nCells, - each final TInitial=TInitialWall, - redeclare each final model WallMaterial = WallMaterial) - annotation (Placement(transformation(extent={{-10,-5},{10,5}}, - rotation=0, - origin={0,0}))); - - replaceable model WallMaterial = TILMedia.SolidTypes.TILMedia_Steel - constrainedby TILMedia.SolidTypes.BaseSolid "Wall material model" - annotation (Dialog(group="Wall material"), choicesAllMatching=true); - - final parameter Modelica.SIunits.Mass massHX=sum(wall.mass) - "Mass of heat exchanger"; - - final parameter Modelica.SIunits.Mass massCasing=2*(hxGeometry.totalheight*hxGeometry.width + hxGeometry.length* - hxGeometry.totalheight)*hxGeometry.tCasing*wall[1].wallMaterial.d "Mass of casing"; - - /************************** HeatTransfer *******************************/ - - HeatAndMassTransfer.HeatTransfer heatTransferGasWall1[nCells]( - redeclare each model HeatTransfer = HeatTransferGasWall1, - each n=1, - each useAlphaAInput=false, - cellGeometry_gas=gas1.cellGeometry, - properties_gas=gas1.properties, - mdotHydraulic_gas=gas1.mdotHydraulic, - each heatTransferArea=hxGeometry.areaHX/nCells) annotation (Placement(transformation( - extent={{-8,-4},{8,4}}, - rotation=90, - origin={0,22}))); - - HeatAndMassTransfer.HeatTransfer heatTransferGasWall2[nCells]( - each n=1, - each useAlphaAInput=false, - redeclare each model HeatTransfer = HeatTransferGasWall2, - cellGeometry_gas=gas2.cellGeometry, - properties_gas=gas2.properties, - mdotHydraulic_gas=gas2.mdotHydraulic, - each heatTransferArea=hxGeometry.areaHX/nCells) annotation (Placement(transformation( - extent={{-8,-4},{8,4}}, - rotation=270, - origin={0,-22}))); - - replaceable model HeatTransferGasWall1 = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - constrainedby - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - "Heat transfer model fluid 1 to wall" annotation (Dialog(group="Heat Transfer Model"), choices( - choice(redeclare model HeatTransferGasWall1 = - SorpLib.Components.HeatExchanger.HXAirAirParallelflow.HeatAndMassTransfer.TransportPhenomena.HeatTransfer.ConstantAlpha - "Constant heat transfer coefficient"))); - - replaceable model HeatTransferGasWall2 = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - constrainedby - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - "Heat transfer model fluid 2 to wall" annotation (Dialog(group="Heat Transfer Model"), choices( - choice(redeclare model HeatTransferGasWall2 = - SorpLib.Components.HeatExchanger.HXAirAirParallelflow.HeatAndMassTransfer.TransportPhenomena.HeatTransfer.ConstantAlpha - "Constant heat transfer coefficient"))); - - /************************** General parameters ***********************************/ - - final parameter Boolean computeTransportProperties1=heatTransferGasWall1[1].computeTransportProperties annotation(Dialog(tab="Advanced", group="Transport properties")); - - final parameter Boolean computeTransportProperties2=heatTransferGasWall2[1].computeTransportProperties annotation(Dialog(tab="Advanced", group="Transport properties")); - - parameter Boolean generateEventsAtFlowReversal=false "If true, events are generated at flow reversal" annotation(Evaluate=true, Dialog(tab="Advanced", group="Event-Handling")); - - parameter String HydraulicMassFlowPosition1="gas port B" "Position of hydraulic mass flow of gas cell (duct 1)" annotation(Evaluate=true, Dialog(tab="Advanced", group="Hydraulic mass flow position"), - choices( - choice="gas port A" "hydraulic mass flow at gas port A", - choice="gas port B" "hydraulic mass flow at gas port B")); - - parameter String HydraulicMassFlowPosition2="gas port B" "Position of hydraulic mass flow of gas cell (duct 2)" annotation(Evaluate=true, Dialog(tab="Advanced", group="Hydraulic mass flow position"), - choices( - choice="gas port A" "hydraulic mass flow at gas port A", - choice="gas port B" "hydraulic mass flow at gas port B")); - - /************************** Initialization ***********************************/ - - parameter Modelica.SIunits.Temperature TInitial1=293.15 - "Initial Value of duct Air Temperature 1" - annotation (Dialog(group="Gas volume 1", tab="Start and Initialization")); - parameter Modelica.SIunits.Temperature TInitial2=293.15 - "Initial Value of duct Air Temperature 2" - annotation (Dialog(group="Gas volume 2", tab="Start and Initialization")); - parameter Modelica.SIunits.Temperature TInitialWall=293.15 - "Initial Value Wall Temperature" - annotation (Dialog(group="Wall volume", tab="Start and Initialization")); - - parameter Modelica.SIunits.MassFraction xiInitial1[gasType.nc - 1]={0.01} - "Initial composition of fluid 1" - annotation (Dialog(group="Gas volume 1", tab="Start and Initialization")); - parameter Modelica.SIunits.MassFraction xiInitial2[gasType.nc - 1]={0.01} - "Initial composition of fluid 2" - annotation (Dialog(group="Gas volume 2", tab="Start and Initialization")); - - parameter Modelica.SIunits.Pressure pInitial1=1e5 - "Start pressure for iteration of fluid 1" - annotation (Dialog(group="Gas volume 1", tab="Start and Initialization")); - parameter Modelica.SIunits.Pressure pInitial2=1e5 - "Start pressure for iteration of fluid 2" - annotation (Dialog(group="Gas volume 2", tab="Start and Initialization")); - parameter Boolean fixedInitialPressure1=true - "If true, initial pressure is fixed" annotation (Dialog(group="Gas volume 1", tab="Start and Initialization")); - parameter Boolean fixedInitialPressure_firstCell1=true - "Use false, if two pressure boundaries are connected" annotation (Dialog(group="Gas volume 1", tab="Start and Initialization")); - parameter Boolean fixedInitialPressure2=true - "If true, initial pressure is fixed" annotation (Dialog(group="Gas volume 2", tab="Start and Initialization")); - parameter Boolean fixedInitialPressure_firstCell2=true - "Use false, if two pressure boundaries are connected" annotation (Dialog(group="Gas volume 2", tab="Start and Initialization")); - - parameter Modelica.SIunits.MassFlowRate m_flowStart1=0.2 - "Start mass flow rate for iteration of fluid 1" - annotation (Dialog(group="Gas volume 1", tab="Start and Initialization")); - parameter Modelica.SIunits.MassFlowRate m_flowStart2=0.2 - "Start mass flow rate for iteration of fluid 2" - annotation (Dialog(group="Gas volume 2", tab="Start and Initialization")); - - /****************************** Summary********************************/ - - inner parameter Boolean includeSummaryArrays=true - "include array entries in summary" annotation (Dialog(tab="Advanced", group="Summary")); - inner parameter Boolean includeDefaultSummary=true - "include default entries in summary" annotation (Dialog(tab="Advanced", group="Summary")); -protected - record Summary - extends TIL.Internals.ClassTypes.Record; - Modelica.SIunits.Temperature TGas1A if include; - Modelica.SIunits.Pressure pGas1A if include; - Modelica.SIunits.MassFraction xiGas1A if include; - TILMedia.Internals.Units.RelativeHumidity phiGas1A if include; - Modelica.SIunits.Temperature TGas1B if include; - Modelica.SIunits.Pressure pGas1B if include; - Modelica.SIunits.MassFraction xiGas1B if include; - TILMedia.Internals.Units.RelativeHumidity phiGas1B if include; - Modelica.SIunits.Temperature TGas2A if include; - Modelica.SIunits.Pressure pGas2A if include; - Modelica.SIunits.MassFraction xiGas2A if include; - TILMedia.Internals.Units.RelativeHumidity phiGas2A if include; - Modelica.SIunits.Temperature TGas2B if include; - Modelica.SIunits.Pressure pGas2B if include; - Modelica.SIunits.MassFraction xiGas2B if include; - TILMedia.Internals.Units.RelativeHumidity phiGas2B if include; - Modelica.SIunits.HeatFlowRate QdotGas1Wall if include; - Modelica.SIunits.HeatFlowRate QdotWallGas2 if include; - Modelica.SIunits.Pressure dp1 if include; - Modelica.SIunits.Pressure dp2 if include; - - protected - outer parameter Boolean includeDefaultSummary; - parameter Boolean include=includeDefaultSummary; - public - replaceable Arrays arrays; - record Arrays - parameter Integer n if includeArrays; - - Modelica.SIunits.Temperature TWall[n] if includeArrays; - Modelica.SIunits.Temperature TGas1[n] if includeArrays; - Modelica.SIunits.Temperature TGas2[n] if includeArrays; - Modelica.SIunits.Pressure pGas1[n] if includeArrays; - Modelica.SIunits.Pressure pGas2[n] if includeArrays; - Modelica.SIunits.MassFraction xiGas1[n,gasType.nc-1] if includeArrays; - Modelica.SIunits.MassFraction xiGas2[n,gasType.nc-1] if includeArrays; - TILMedia.Internals.Units.RelativeHumidity phiGas1[n] if includeArrays; - TILMedia.Internals.Units.RelativeHumidity phiGas2[n] if includeArrays; - Modelica.SIunits.HeatFlowRate QdotGas1Wall[n] if includeArrays; - Modelica.SIunits.HeatFlowRate QdotWallGas2[n] if includeArrays; - - protected - outer parameter Boolean includeSummaryArrays; - parameter Boolean includeArrays=includeSummaryArrays; - outer parameter TILMedia.GasTypes.BaseGas gasType; - end Arrays; - - end Summary; - - replaceable record SummaryClass = Summary; - -public - SummaryClass summary( - TGas1A=gas1A.T, - pGas1A=gas1A.p, - xiGas1A=gas1A.xi[1], - phiGas1A=gas1A.phi, - TGas1B=gas1B.T, - pGas1B=gas1B.p, - xiGas1B=gas1B.xi[1], - phiGas1B=gas1B.phi, - TGas2A=gas2A.T, - pGas2A=gas2A.p, - xiGas2A=gas2A.xi[1], - phiGas2A=gas2A.phi, - TGas2B=gas2B.T, - pGas2B=gas2B.p, - xiGas2B=gas2B.xi[1], - phiGas2B=gas2B.phi, - QdotGas1Wall=-sum(gas1[:].heatPortA.Q_flow), - QdotWallGas2=sum(gas2[:].heatPortA.Q_flow), - dp1=gasPort1A.p-gasPort1B.p, - dp2=gasPort2A.p-gasPort2B.p, - arrays( - final n=nCells, - TWall=wall.T, - TGas1=gas1.gas.T, - TGas2=gas2.gas.T, - pGas1=gas1.p, - pGas2=gas2.p, - xiGas1=gas1.xi, - xiGas2=gas2.xi, - phiGas1=gas1.gas.phi, - phiGas2=gas2.gas.phi, - QdotGas1Wall=-gas1.heatPortA.Q_flow, - QdotWallGas2=gas2.heatPortA.Q_flow)); - -equation - /************************** Connect ***********************************/ - - for i in 1:nCells - 1 loop - connect(gas1[i + 1].gasPortA,gas1 [i].gasPortB); - connect(gas2[i].gasPortA,gas2 [i + 1].gasPortB); - end for; - - connect(gasPort2B, gas2[1].gasPortB) annotation (Line( - points={{-100,-46},{-54,-46},{-54,-50},{-9.8,-50}}, - color={255,153,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(gas2[nCells].gasPortA, gasPort2A) annotation (Line( - points={{10,-50},{56,-50},{56,-46},{100,-46}}, - color={255,153,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(gasPort1A, gas1[1].gasPortA) annotation (Line( - points={{-100,48},{-56,48},{-56,50},{-10,50}}, - color={255,153,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(gas1[nCells].gasPortB, gasPort1B) annotation (Line( - points={{9.8,50},{54,50},{54,48},{100,48}}, - color={255,153,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(gas1.heatPortA, heatTransferGasWall1.heatPortB[1]) annotation (Line( - points={{0,40},{0,35},{0,30}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransferGasWall1.heatPortA, wall.heatPortB) annotation (Line( - points={{0,14},{0,4.75}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransferGasWall2.heatPortA, wall.heatPortA) annotation (Line( - points={{0,-14},{0,-5}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransferGasWall2.heatPortB[1], gas2.heatPortA) annotation (Line( - points={{0,-30},{0,-30},{0,-40}}, - color={204,0,0}, - thickness=0.5)); - annotation ( - Placement(transformation(extent={{50,-10},{70,10}})), - Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-80},{100,80}}), - graphics={Bitmap( - extent={{-124,-98},{122,94}}, - imageSource= - "iVBORw0KGgoAAAANSUhEUgAAAgYAAAF2CAYAAAAV9VD8AAAAAXNSR0ICQMB9xQAAAAlwSFlzAAAXEgAAFxIBZ5/SUgAAABl0RVh0U29mdHdhcmUATWljcm9zb2Z0IE9mZmljZX/tNXEAABYGSURBVHja7d0vUOPoH8DhgKqsrKxEViKRyEokEonEHaeQSAbFDMuCRFYikUgkshKJYvtLIOz19+7bNk0CS5LnZp65213avcm3efvpnyTJv//+mwAAZGwEAEAYAADCAAAQBgDAl4dB+s8gdZGaAQC1u0mNmhQGt4YGAJ/qoUlhYGAA8MmEAQDQ/DDwJQ4AaNbzqzAAAGEgDABAGAgDABAGwgAAhIEwAABhIAwAQBgIAwAQBsIAAISBMAAAYSAMAEAYCAMAEAbCAAAQBgCAMChw/4PUXcSxBw4An/jEfLrg+WeZm+z5KTUSBp8XBgcLrk39nOp58ALwSWFwt+D5p6hpHhe9kn+/MFhw//dLNvqeBy8A3zQMPjymhsKgnvveCu7/Jfj1xIMXgC8Kg9v8Y4J5k+CjhEVx8CAM6rnv4+D+j4I4yP574AEMwBeEwX6B2/RS49RTJA5GwqD6fT+FEZAX2/zfeegBDMB3CIO52w7z78KVfr4SBn/e707sY4PsewXB7997AAPwncIgv/0kuP2FMKh2v2exLxrmb9OEFbblQQxLX7l8fB56aJvAl4XBSfgdBWFQ/j7DJ///OzQxq67g7z32IIaF+9Ph3L7yZJvAl4XBTXD7U2FQ/j73lr39EvmYwWIHi/ene/sK/JUweAhuPxYG5e8z/ILhTuRnpqt+Bjq+qPUir1iEAXxBGATv1JX6Ppww+O/+BsEhidMFP3ca/N1nHsh0eAEb5O+k7eTvuF0sOFxKGMAnhkG+L4aH2mf7Yl8YlL+/sLJOFvzctlMkw+/9Yb/gGdiEAZQPg9gJjj7cLDjB0W3Z8+0Ig//u777oCSHy00w6RTIWMGEAXxEGZa6VsF/m3QJh8N99ba1zCsnI2zW3Hsx0dAHbXXK1N2EAfycM5k/Qd7buu9rC4N/oMZ9HK35+GNn4TpEMi/dRYQDlw+BxQXw/FAyE+3Weo4TBv3+cAnlWZANGPno48IAGYQCfEAb7BW+Xvft9EDnCbq2LKXU+DCLnJrgreLsDp0gGYQDfJQxWPEcVfgErDP48m+Hp3OFXy+xFNvrQgxqEAfztMMjvJ/yYfCoMVt9H7PoHVRx7UIMwgG8SBsPI89RgzX23c2GwV2MUWPxAGMC3CYP8vl7WPVtv18NgUnMYZLY9sEEYwDcJg+m6593pbBjkp48Mz2C4U8KtUySDMIDvFgaR5znvGKy4/WEdT+j5CV6cIhmEAXy3MBhHwqAvDBbf/qGOqyTmX2CcVrnEJQgDoM4wyJ+b7koejt+9MIicAvmp4v/LmVMkgzCAbxQGN5F3C8Yl9t3OhMFJkSsprnF/25FTJPc9wBEGwgC+Kgyyi//l5+KZRqLg9CueX5scBtOiV1Jc4z6fnCIZhAF8Qhg8LrlY2V3kir+zMh8hdDYMIqdAfqzp/+fEKZJBGMAnhEEVF+u+g93FMLhY50qKa9zvllMkgzCAbxIG2aH0u1/5/NrkMJgEb8EMa/x/ugnue8+DHGEgDGDNfed0xUcHoey55zi3s84lloUBIAwAYQAIA0AYAMIAEAaAMACEgWHC31hAdpd8ISo86deinxvYliAMhAG0YwHZr+GwqqFtCcJAGIAwEAYgDIQBtGwBGeTHTVfhMuUgDIQBAPWYXSbj2Y/N4zfX1a99IwyEAQBNDILrZPjrx8bD7GpjNu/X1cZ9+mfbtpEwMFCArkTBedKLRcG816vNs/TnHPUiDABofRhcJrvLomDu3YPn2VU9F8sTBsIAgO8aBtn3CQqEwe9AuNx4zGLCthMGAAiD+XcQJrPrZMs2FAYAtCkMsiMRSoRBHgcvr1ebJ7PzpG9bCgMAWuLt6IOScZAHwnR2lezblsIAgDa8a5AdmfBz47ZKHDi8URgA0LZAuEzG6ZP7U9VAeP25eeHwRmEAQEvePci+kJh9f6Diuwdvhzdm9ycMhAEAzQ+EweuPzZvKHy90+PBGYQBA+wLhMtlZdWZEhzcKAwC6FghXycH7xwMVv3/QocMbhQEA7Y6D9Ak9fWI/reHdg+zwxgNhIAwAaEMgXCdb6ZP7ncMbhUHzH8wlT/0JwOd5+5JjCw9vFAbCAACHNwoDYQBAjYHw1JbDG4WBMACgvkBo/OGNwkAYAFC75l6cSRgIAwDqe8eg8Yc0CgNhAEAN3s6V0IKTIAkDYQBAtXcJWnXaZGEgDAAoFwTZkQjjtj3nCAMAOmN2lRxWvXbC+6Wd23tpZmEAQPuDILvaYnYp5arfI2jp2Q6FAQDdCILrZPjr58Zt5Y8Nsks4p3HRhW0mDABoXxCcJ73s+1nvb/tX+tjguQtXVBQGALQ3Ci6TvffzCTj8UBgA0N0guE5GNV1W+a5Nhx8KAwC6FQTpq/r01f2Zww+FgTAA6HoUvH9sUP3ww+x8MS09/FAYANCNKKjh5G9vRyy0/PBDYQBA+6PgOhk5/FAYCAMAKr1bkB9+eGgbCgMAOh4GXT38UBgA0P4wuEoO1jz8cGS7CQMA2hoG58lg1VkN305ydJns2V7CAIAuxMFlshuLA4cfCgNhANDVOLhOhq8/Ny+yjwvePjLIgiD9PdtGGAgDABAGwgAAhIEwAABhIAwAQBgIAwAQBsIAAISBMAAAYSAMAEAYCAMAEAbCAACEgTAAAGEgDABAGAgDABAGwgAAhIEwAABhIAwAQBgIAwAQBsIAAISBMAAAYSAMAEAYCAMAEAbCAACEgTAAAIQBACAMAABhQPukgx+ldm0Lc8KsEAbCgORXkkxSj+kDoGd7mBNmhTAQBt1+ZTNOzXKHtok5YVYIA2HQ3QWsl76qefpYxNL/fkn/PbBtzAmzQhgIg24uYkdzr2zevCbJhW1jTpgVwkAYdG8BG+SvZmYRI9vInDArhIEw6JD0VczNggUse/vzwTYyJ8wKYSAMuvPKZnvRAjZn37YyJ8wKYSAMOiB79bJqEUt/ZupQK3PCrBAGwqD9r2z2C7yy+fjS1KltZk6YFcLAQNu7gPXyVy2FFrH8i1Rbtp05YVYIA1ooe7USWaRib3fO//rWtjMnzAphQPte2WxFFq3jyKuavcjvjW1Dc8KsEAa0SPYqJfZFqHDByn/2PvhZ53w3J8wKYUCLXtmMF71iiS1i+ZXhwp8/tC3NCbNCGNCOVzaPwauVu7kF7o9FLPOaJGeRz077tqc5YVYIA5r9yqa/7PSsixax/PSuz8Gfb9um5mRWZoUwoNmLWC/4fPM4+PPoIpb/2X7w+amrxJmTWZkVwoAWLGSD/Kpve5E/W7iI5X++m3/TemhbmhNmhTCg/Qvc0kUMc8KsEAYGahHDnDArhIEwsIiZvzlhVggDYWARs4iZE2aFMBAGWMTMCbNCGAgDLGLmhFkhDIQBFjFzwqwQBsIAi5g5YVYIA2GARcycMCuEgTDAImZOmBXCQBhgETMnzAphIAywiJkTZoUwEAZYxMzJNjErhIEwwCJmTuZkVggDYYBFDHMyK4SBMMAihjmZFcJAGGARw5zMCmEgDLCIYU5mhTAQBljEMCezQhgIAyximJNZIQyEARYxzMmsEAbCAIsY5mRWCANhgEUMczIrsxIGwgCLGOZkVmaFMMAihjlhVggDLGKYE2aFMMAihjlhVggDLGKYE2aFMMAihjlhVnQuDP755x86KFzEbBNzwqyo187OjjDAIoY5mZVZIQywiGFOZmVWCAMsYpgTZoUwwCKGOWFWCAMsYpgTZkUHwsDhig6tcmiVOWFWOFxRGFjELGLmhFkhDIQBFjFzwqwQBsIAi5g5YVYIA2GARcycMCuEgTDAImZOmBXCQBhgETMnzAphIAywiJkTZoUwEAZYxMwJs0IYCAMsYuaEWSEMhAEWMXMyJ7NCGAgDLGLmZE5mhTAQBljEMCezQhgIAyximJNZIQyEARYxzMmsEAbCAIsY5mRWCANhgEUMczIrhIEwwCKGOZkVwkAYYBHDnMwKYSAMsIhhTmaFMBAGWMQwJ7MyK2EgDLCIYU5mZVYIAyximBNmhTDAIoY5YVYIAyximBNmhTDAIoY5YVYIAyximBNmhTDAIoY5YVYIAw/ili5U419JcveaJBfpf/eLLmLpr3vpbU6y26b/fWhbmhNmhTCg+QtYP12Enj8WqWxBKrqI5Yve/J9v2abmZFZmhTCg+QvZLDBetYil/z2K3G5ke5oTZoUwoOHSVzST+cUo/fU0e0tz2SKW/sxDcJunj9tgTmZlVggDmv3qZpQuQi/zi1L2OeeiRSz99/6yV0SYk1mZFcKAhksXrdPg1Uq2qA0ji1Uvf/Uz/7MT29CcMCuEAe16hdOPLE634SKWveqJLHYj29CcMCuEAe1byA4ir2ZmkUVrflE7te3MCbNCGNBS4RegVixo0/AYbcwJs0IY0K5XONtFF7HsC1O2mTlhVggDA2251yS5KfDK5sG2MifMCmEgDLrxCmcQfu7pxCvmhFkhDIRBtxeyo0ULWHbaVtvInDArhIEw6NYi1svPvBb7BvXANjInzAphIAy6t5CNI69uDm0bc8KsEAbCoKPmz/meH3bl3O3mhFkhDIRBh1/hzJ/zfdc2MSfMCmEgDDouOxNbdipX28KcMCuEgTDg7Zzv2cVfbAtzwqwQBsIAAISBMAAAYSAMAEAYCAMAEAbCAACEgTAAAGEgDABAGAgDABAGwgAAhIEwAABhIAwAQBgIAwAQBsIAAISBMAAAYSAMAEAYCAMAEAbCAACEgTAAAGEgDABAGAgDABAGwgAAEAYAgDAAAIQBACAMAABhAAAIAwBAGAgDABAGwuDLzc6TwewqOZj92DxO/32Y/rpvuwAIA2HQvSDov15tns6uNmbzfl1tPKeBsG8bAQgDYdCVKLhKDtIAmIZRMBcHL7PLZMe2AhAGwqDNQXCdbP/6sfGwKAjmvf7YvLHNAISBMGhjEJwng+yJvkgQzL1r8GTbAQgDYdCuIOhlXyp8+2hgjSgQBgDCQBi0LQouk3H25L5uEPwOg58bt7YjgDAQBk0PgutkKw2Cu7JB8PvLh9fJyPYEEAbCoKlBsODwwxJRMBUFAMJAGDQ5Ct4PP3yu+i5BGhYnTnAEIAyEQVOD4DLZKXr44YoomGQfQdimAMJAGDQxCEocfhgNgsuNxzQudm1TAGEgDJoZBKUPP4yc9vgouz/bFUAYCIMmRsH74YfTqu8SvP7cvMjecbBNAYSBMGhiEFwno6qHH+bvEtxnp0S2TQGEgTBoYhDUefihqyUCCANh0OAouEoOqx5+CEC9sndvhYEw+NogqOnwQwCEgTBo9scGg+zaBHY8AGEgDDocBnUdfgiAMBAGTY+C62RYx+GHAAgDYdCeOKjlUEQAhIEwaNeXDve8ewAgDISBMPB9AwBhIAyEwYrvHjhCAUAYCANhEHy8sPN29cOKD+S3qzC6NgJAZwmDtgVCDWdBfP94wtUUAYSBMGhHHKSv+F+vNs9qeBvsKbtKo20KIAyEQRsC4f3wxvsaAmGS3teWbQogDIRBGwKhpsMb367eeJ70bVMAYSAMmh4H50kvfWI/qXp4Y35Z5gPbFEAYCIM2BML7qZUnlT9eyK7qeJ1s26YAwkAYtCEQLpPdWg5v/Ll54egFAGEgDNoSCFfJUeXDG7N3D3z3AEAYCIOWxEENhzdmX0y0LQGEgTBoUyBcJ9tlD2/MznlgGwIIA2HQxkAocXijMAAQBsKgzXFwnvTXObyxqRcLAUAYsE4gXCdbxQ5vdG4DAGEgDLoTCEsOb8wOWbSNAISBMOhaHJwnveydgewdhOyjg7d3ElxkCUAYCAMAEAbCAACEgTAAAGEgDABAGAgDoMT+OE4dpy5Sd6nHfN98yn99ljpKDWwvEAbCANobAzepl3B/XCL72dNU3zYEYSAMoMWLx5qeU9u2IwgDYQDtD4OPjw9O8n/fLfk57xyAMBAG0MLFI/tIYWfJz26lbiNxcGtbgjAQBtCOxeMl/7LhcI3bxOLAFxJBGHyP//FsQcte5aww9ECB6P4zKHGbfv79gvn9d9f2hML7UG/Bc1VfGNQTBsclvzj1lB9+ZUGD9fe7+2B/OrJdoPD+s7fgeelEGPzdMAi/XT32gIXC+91FsA+d2S5QeP+ZLHgumgqD7xMGHw49aKHQfnfrHQMote8MVjwP7QiD+sPgYsFnN/v5zx7ni9rLghO3bHnwwsr97iHYd/ZsFyi07xxGPtb+v+cwYVB/GBwXvF0v8naodw2g2CueMKxHtg2UiuqdyAvUnjD4C2Ewd/vwxC03HrywdJ85DfaZB9sFCu07W8G+c5f//n3d78AJg2phcBTc/tEDGBbuL8PIuwVj2wYK7T8nwb5zkP/+QfD7E2Hwd8NgXxhAoX2lF3ll490CKL4PTYOPDPr574cfz71UPWmYMKgWBid1lxq0dFG78GVdKL3/7Cw7lXjkEMZDYfB9vmMw9iCGlftZZt+2gdJhvRf8eXjSo3th8BfCIHJb7xbAn/vJUSQKjm0bKLwP9YKPCp7DIw8iPzOr8o6cMFhzwcrLLHzb5qGOQ0SgZQvafiQKLmwbWGs/2iuyD+VXOK3lFMnCIH4d+ZinBSc1OhIFIArgk/alSZGzG2bX7gmfz4RBPWFQxm1edOIAFu9XogDW35cGRa+HkH+cMK3jFMnCoL5rJTzXdZ5qaPBCdvaZV32Dju1Ph+vsS5H976zk3ysM5s8kNXdNhJhJ/jP3LqYEf7xaubE/QK371cM6XyhM/9mOvGDtlfh7hUHJoxL62eGJ2UmNIovhyIOaDi1e/cihuw5JhGr71ajMCcEi34fbK/F3C4Mqh1EtOKPbvQc2HVm8hpE49rEaVN+3Tspcnjxyu1th8MVhsKDsvGtAFxau7TwCwiN7nNEQqu9f4RcJz1Z81P0hdpbRwZp/tzCo48QrkVdNrjFPmxetvcgJVe4+zt8OVNq/dmv8YvzvCy4Jg68Pg7syb/tAQxeuu8jHBycFX9HEHNqu8Hv/uqg5DO7X/PuFQU1hcO+0r3Q4DKp6sl0henrjlyUn3lsm3MeGwuDrw+DFN7IRBsIAKu5b4VlDb0rez6TCUXfC4JO+fLjtQY4wEAZQ8Ql9t6bAeFrjtsKg4uGK/chJKCxytH3xGuXXiK+LkMZ+9ecpkEudoCi/r9gVF7cL3lYYlA2D/BjuSeTVz9iDHIA1n1OO6jil8dz93ZS5P2GwRhhkx2fnr272l5wW2XnhASjznPRQx0WQ5u5vXOYdCGFQ7+ekEw9uAEo8H42KXklxjfvsRU5CNhYGXxMGT45CAKDCc9rJZ7z7HDknwk2B2wiDCh4EAQA1PKdNP+PItvzj7/AUyX1hsHyDrXN2trFvUANQ8/PZIHiuOar5/sPnslWXb+5uGAAAwgAAEAYAgDAAAIQBACAMAABhIAwAQBgIAwAQBrH/cQCgfsIAAGhkGDwYGAB8qmmTwmAneb+qocEBQP2eUweNCQMAoOFfdLQRAABhAAAIAwBAGAAAwgAAEAYAgDAAAIQBACAMAABhAAAIAwBAGAAAwgAAEAYAgDAAAIQBACAMAABhAAAIAwBAGAAAwgAAaLL/AdUvUZQCESY1AAAAAElFTkSuQmCC", - fileName="modelica://SorpLib/Resources/Images/HXAirAir.png")}), - Diagram(coordinateSystem(extent={{-100,-80},{100,80}}, preserveAspectRatio= - false)), - Documentation(info="<html> - <p> - This model represents a counterflow air/air heat exchanger. The model consists of two gas channels, a separating wall cell, all connected by heat transfer resistances. At the moment, only a constant heat transfer coefficient is implemented. The model can be descretized in flow direction to build up a finite volume model. - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 12, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end HXAirAirParallelflow; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/HeatTransfer.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/HeatTransfer.mo deleted file mode 100644 index 875353e07d6426e15fd5908c0519129476a7fdd8..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/HeatTransfer.mo +++ /dev/null @@ -1,22 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow.HeatAndMassTransfer; -model HeatTransfer - extends SorpLib.Components.HeatTransfer.HeatTransfer; - - inner parameter Modelica.SIunits.Area heatTransferArea; - inner parameter SorpLib.Components.Cells.Gas.Geometry.CellGeometry cellGeometry_gas; - inner input TILMedia.Internals.PropertyRecord properties_gas; - inner input Modelica.SIunits.MassFlowRate mdotHydraulic_gas; - - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false)), - Documentation(info="<html> - <h4>Author Information</h4> - <p> - <ul> - <li>December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end HeatTransfer; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/ConstantAlpha.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/ConstantAlpha.mo deleted file mode 100644 index ac9aa0d160b58e90c9832fafc8c644fdf5920406..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/ConstantAlpha.mo +++ /dev/null @@ -1,37 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow.HeatAndMassTransfer.TransportPhenomena.HeatTransfer; -model ConstantAlpha - extends - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer(final computeTransportProperties=false); - - parameter Modelica.SIunits.CoefficientOfHeatTransfer constantAlpha(start=100) "Constant heat transfer coefficient"; - - outer parameter Modelica.SIunits.Area heatTransferArea "Heat transfer area"; - -equation - - alphaA = constantAlpha*heatTransferArea; - - annotation (Documentation(info="<html> -<p> - This simple transfer model calculates the heat flow based on the temperature differnce with a constant alpha. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> <i>Q</i><sub>in</sub> = <i><code>α</code> A</i> (<i>T</i><sub>in</sub> - <i>T</i><sub>out</sub>) </p> - <p>where <i><code>α</code></i> is a constant heat tranfer coefficient and <i>A</i> is the heat transfer area. </p> -</p> -<h4>Assumptions and limitations</h4> - <p> - In general, the heat transfer coefficient depends on fluid properties and geometry. Thus, a constant coefficient is only an approximation. - </p> -<h4>Author Information</h4> -<p> - <ul> - <li> - December 06, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end ConstantAlpha; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.mo deleted file mode 100644 index 4e880ccfbe70b8f76d081e69983e4ad34b4789b0..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.mo +++ /dev/null @@ -1,10 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow.HeatAndMassTransfer.TransportPhenomena; -package HeatTransfer - extends SorpLib.Internals.ClassTypes.ModelPackage; - - - - - - -end HeatTransfer; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.order b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.order deleted file mode 100644 index 3bb1fa51a77dd4a590921ee936e1f5261fad013e..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.order +++ /dev/null @@ -1 +0,0 @@ -ConstantAlpha diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/package.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/package.mo deleted file mode 100644 index 3eb2a5784aa20efb7d0a3867b21137e1437c5f20..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow.HeatAndMassTransfer; -package TransportPhenomena - extends SorpLib.Internals.ClassTypes.ModelPackage; - -end TransportPhenomena; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/package.order b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/package.order deleted file mode 100644 index 2dc6ac88dcb02452267722241d53e148e08190d1..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/TransportPhenomena/package.order +++ /dev/null @@ -1 +0,0 @@ -HeatTransfer diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/package.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/package.mo deleted file mode 100644 index 841cc38a68afaf02cec66758cc5d891c1f533760..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow; -package HeatAndMassTransfer - extends SorpLib.Internals.ClassTypes.ModelPackage; - - -end HeatAndMassTransfer; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/package.order b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/package.order deleted file mode 100644 index 905f22a3a23bffdcea4db13de42cf01c948e2fcd..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/HeatAndMassTransfer/package.order +++ /dev/null @@ -1,2 +0,0 @@ -HeatTransfer -TransportPhenomena diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/PressureDropCorrelations/VDIWaermeatlasN6.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/PressureDropCorrelations/VDIWaermeatlasN6.mo deleted file mode 100644 index fdf7853cc6186d7915094602e2bce49d4c57876c..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/PressureDropCorrelations/VDIWaermeatlasN6.mo +++ /dev/null @@ -1,75 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow.PressureDropCorrelations; -model VDIWaermeatlasN6 - "Pressure drop correlation for plate heat exchangers (phi = 0) according to VDI Wärmeatlas (N6)" - extends - SorpLib.Components.Cells.Gas.PressureDropCorrelations.Partial.PartialPressureDrop( - final computeTransportProperties=true); - - outer parameter Cells.Gas.Geometry.CellGeometry cellGeometry "cell geometry"; - - outer TILMedia.Internals.PropertyRecord properties "Fluid property record"; - - outer Modelica.SIunits.MassFlowRate mdotHydraulic - "Hydraulic mass flow rate"; - - Modelica.SIunits.ReynoldsNumber Re(start=1000) "Reynolds number"; - - Modelica.SIunits.Velocity v(start = 10); - - parameter Modelica.SIunits.Velocity vLimit = 0.1 - "Fluid velocity below which the pressure drop relation is regularized"; - - Real zeta(start=0.01); - Real zeta_lam(start=0.01); - Real zeta_tur(start=0.01); - - Real weightingFactor(start=0.5); - - /*************************************************************************/ - -equation - v = mdotHydraulic/properties.d/cellGeometry.flowCrossSection; - - Re = properties.d*abs(v)*cellGeometry.hydraulicDiameter/properties.transp.eta+10; - - zeta_lam = 64/Re; - zeta_tur = (1.8*log(Re)/log(10) - 1.5)^(-2); - zeta = weightingFactor*zeta_lam + (1 - weightingFactor)*zeta_tur; - - weightingFactor = TIL.Utilities.Numerics.smoothTransition( - Re, - 2000.0, - 100.0); - - pressureDrop=(cellGeometry.length/cellGeometry.hydraulicDiameter)/(2*properties.d*cellGeometry.flowCrossSection^2)*zeta*TIL.Utilities.Numerics.squareFunction(mdotHydraulic); - annotation (Documentation(info="<html> -<p> - This model calculates the pressure drop according to the VDI Wärmeatlas N6 (2011): pressure drop in plate heat exchangers. The model describes the special case for plates which have no angle (<code>φ</code>=0).<br> - The hydraulic mass flow rate, the fluid properties record, and the geometry are defined as outer objects and thus taken from the overlying model level. -</p> -<h4>Main equations</h4> -<p> -<p> - <p align=\"center\"> <i><code>Δ</code>p</i> = sgn(<i><code>ṁ</code></i><sub>hydraulic</sub>) <i>L</i> / <i>D</i> <code>ζ</code> / (2 <i><code>ρ</code></i> <i>A</i><sup>2</sup>) <i><code>ṁ</code></i><sub>hydraulic</sub><sup>2</sup> </p> -<p>where <i><code>Δ</code>p</i> is the pressure drop, <i><code>ṁ</code></i><sub>hydraulic</sub> is the hydraulic mass flow rate, <i>L</i> is the hydraulic length, <i>D</i> is the hydraulic diameter, <code>ζ</code> is the resistance coefficient, <i><code>ρ</code></i> is the fluid density and <i>A</i> is the cross sectional area. </p> -with - <p align=\"center\"> <code>ζ</code> = 64 / Re</p> -for Reynolds numbers Re <code><</code> 2300 and -<p align=\"center\"> <code>ζ</code> = (1.8 lg(Re) -1.5)<sup>-2</sup></p> -for Reynolds numbers Re <code>></code> 2300. -</p> -<h4>References</h4> -<ul> -<li>VDI e.V., VDI Wärmeatlas 11., bearbeitete und erweiterte Auflage, Chapter N6, Darmstadt: Springer Berlin Heidelberg, 2011. </li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - December 13, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end VDIWaermeatlasN6; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/PressureDropCorrelations/package.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/PressureDropCorrelations/package.mo deleted file mode 100644 index b7613eb5624a4b808a603db930f365729b77d316..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/PressureDropCorrelations/package.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow; -package PressureDropCorrelations - extends SorpLib.Internals.ClassTypes.ModelPackage; - - - - -end PressureDropCorrelations; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/PressureDropCorrelations/package.order b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/PressureDropCorrelations/package.order deleted file mode 100644 index 67b21bf1fe52ea6b29e158484c19a2942675d949..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/PressureDropCorrelations/package.order +++ /dev/null @@ -1 +0,0 @@ -VDIWaermeatlasN6 diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Testers/TestAirAirHX.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Testers/TestAirAirHX.mo deleted file mode 100644 index 9d3fa708ba447b2a49b02ff125ef8a66fb2d55a1..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Testers/TestAirAirHX.mo +++ /dev/null @@ -1,105 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow.Testers; -model TestAirAirHX - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.GasTypes.VDI4670_MoistAir gasType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundary1A( - V_flowFixed(displayUnit="m3/s") = -3, - use_volumeFlowRateInput=false, - streamVariablesInputType="T", - streamVariablesInputTypeConcentration="xi", - use_massFlowRateInput=false, - m_flowFixed=-0.33, - boundaryType="m_flow", - TFixed=432.15, - pFixed=111325) - annotation (Placement(transformation(extent={{-64,11},{-56,31}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundary1B( - V_flowFixed(displayUnit="m3/s") = -3, - use_volumeFlowRateInput=false, - streamVariablesInputType="T", - streamVariablesInputTypeConcentration="xi", - use_massFlowRateInput=false, - m_flowFixed=0.01, - boundaryType="p", - TFixed=293.15, - pFixed=101325) - annotation (Placement(transformation(extent={{56,10},{64,30}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundary2A( - V_flowFixed(displayUnit="m3/s") = -3, - use_volumeFlowRateInput=false, - streamVariablesInputType="T", - streamVariablesInputTypeConcentration="xi", - use_mixingRatioInput=false, - use_massFlowRateInput=false, - m_flowFixed=-0.33, - boundaryType="m_flow", - TFixed=313.15, - pFixed=111325) annotation (Placement(transformation( - extent={{-5,-13},{5,13}}, - rotation=180, - origin={61,-21}))); - TIL.GasComponents.Boundaries.Boundary gasBoundary2B( - m_flowFixed=-0.1, - V_flowFixed(displayUnit="m3/s") = -3, - use_volumeFlowRateInput=false, - streamVariablesInputType="T", - streamVariablesInputTypeConcentration="xi", - boundaryType="p", - use_massFlowRateInput=false, - TFixed=293.15, - pFixed=101325) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=0, - origin={-60,-20}))); - HXAirAirParallelflow hxAirAirCounterflow( - gasType=sim.gasType1, - nCells=5, - redeclare Geometry.HXGeometry hxGeometry( - length=1, - width=0.2, - heightDuct1=0.01, - heightDuct2=0.01, - tSheet=0.003, - tCasing=0.03, - numDucts=10), - redeclare model WallMaterial = TILMedia.SolidTypes.TILMedia_Steel, - includeSummaryArrays=true, - includeDefaultSummary=true, - generateEventsAtFlowReversal=false, - redeclare model PressureDrop1 = PressureDropCorrelations.VDIWaermeatlasN6, - redeclare model PressureDrop2 = PressureDropCorrelations.VDIWaermeatlasN6, - HydraulicMassFlowPosition1="gas port B", - HydraulicMassFlowPosition2="gas port B", - redeclare model HeatTransferGasWall1 = - HeatAndMassTransfer.TransportPhenomena.HeatTransfer.ConstantAlpha ( - constantAlpha=100), - redeclare model HeatTransferGasWall2 = - HeatAndMassTransfer.TransportPhenomena.HeatTransfer.ConstantAlpha ( - constantAlpha=100)) - annotation (Placement(transformation(extent={{-16,-14},{18,14}}))); - -equation - connect(gasBoundary2B.port, hxAirAirCounterflow.gasPort2B) annotation (Line( - points={{-60,-20},{-40,-20},{-40,-8.05},{-16,-8.05}}, - color={255,153,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(hxAirAirCounterflow.gasPort2A, gasBoundary2A.port) annotation (Line( - points={{18,-8.05},{26,-8.05},{26,-8},{40,-8},{40,-21},{61,-21}}, - color={255,153,0}, - thickness=0.5)); - connect(gasBoundary1A.port, hxAirAirCounterflow.gasPort1A) annotation (Line( - points={{-60,21},{-50,21},{-50,20},{-40,20},{-40,8.4},{-16,8.4}}, - color={255,153,0}, - thickness=0.5)); - connect(gasBoundary1B.port, hxAirAirCounterflow.gasPort1B) annotation (Line( - points={{60,20},{40,20},{40,8.4},{18,8.4}}, - color={255,153,0}, - thickness=0.5)); - annotation (Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, - -100},{100,100}})), - experiment(StopTime=1000, Interval=1), - __Dymola_experimentSetupOutput); -end TestAirAirHX; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Testers/package.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Testers/package.mo deleted file mode 100644 index 4c4154582821fa05b1c5a46da713972829fd4bcb..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Testers/package.mo +++ /dev/null @@ -1,7 +0,0 @@ -within SorpLib.Components.HeatExchanger.HXAirAirParallelflow; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - -annotation (Icon(graphics)); -end Testers; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Testers/package.order b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Testers/package.order deleted file mode 100644 index 03ed2bdf0c2e2a7424a30edbdfda204da264f282..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/Testers/package.order +++ /dev/null @@ -1 +0,0 @@ -TestAirAirHX diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/package.mo b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/package.mo deleted file mode 100644 index bf7001b31d05f1c4e3f451a29ea8fa3a992a5c7a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/package.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.HeatExchanger; -package HXAirAirParallelflow "counterflow air-air heat exchanger" -extends SorpLib.Internals.ClassTypes.ComponentPackage; - - - -annotation (Icon(graphics)); -end HXAirAirParallelflow; diff --git a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/package.order b/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/package.order deleted file mode 100644 index 19c00d2cb3de59f0deb37cd87cd2b3068aeb6ae7..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatExchanger/HXAirAirParallelflow/package.order +++ /dev/null @@ -1,5 +0,0 @@ -HXAirAirParallelflow -Geometry -HeatAndMassTransfer -PressureDropCorrelations -Testers diff --git a/SorpLib/Components/HeatExchanger/Recoolers/SimpleDryCooler.mo b/SorpLib/Components/HeatExchanger/Recoolers/SimpleDryCooler.mo new file mode 100644 index 0000000000000000000000000000000000000000..4aa7726e95e0ba1ecc4625928de8c1b02bcc0ab8 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Recoolers/SimpleDryCooler.mo @@ -0,0 +1,257 @@ +within SorpLib.Components.HeatExchanger.Recoolers; +model SimpleDryCooler "Model of a simple dry cooler" + extends SorpLib.Components.HeatExchanger.BaseClasses.PartialSimpleDryCooler( + final noDiff, + final X_i_initial, + final p_initial, + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final SorpLib.Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + final no_components=Medium_liq.nX); + + // + // Definition of parameters + // + replaceable package Medium_liq = + Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Liquid medium" + annotation (Dialog(tab = "General", group = "Medium"), + choicesAllMatching=true, + Evaluate=true, + HideResult=true); + replaceable package Medium_air = + Modelica.Media.Air.DryAirNasa + constrainedby Modelica.Media.Interfaces.PartialMedium + "Air medium" + annotation (Dialog(tab = "General", group = "Medium"), + choicesAllMatching=true, + Evaluate=true, + HideResult=true); + + // + // Definition of state records + // + Medium_liq.ThermodynamicState state_liq_in + "Record describing current state properties of liquid at inlet"; + Medium_air.ThermodynamicState state_air_in = Medium_air.setState_pT( + p = p_air, + T = T_air_in) + "Record describing current state properties of air at the inlet"; + +equation + // + // Calculation of fluid properties + // + if flowDirection == 1 then + // + // Flow from port a to port b + // + state_liq_in = Medium_liq.setState_phX( + p = port_a.p, + h = inStream(port_a.h_outflow), + X = inStream(port_a.Xi_outflow)) + "Record describing current state properties of liquid at inlet"; + + elseif flowDirection == 2 then + // + // Flow from port b to port a + // + state_liq_in = Medium_liq.setState_phX( + p = port_b.p, + h = inStream(port_b.h_outflow), + X = inStream(port_b.Xi_outflow)) + "Record describing current state properties of liquid at inlet"; + + else + // + // Actual flow direction + // + if avoid_events then + state_liq_in = Medium_liq.setState_phX( + p = SorpLib.Numerics.regStep_noEvent( + x=port_a.m_flow, + y1=port_a.p, + y2=port_a.p, + x_small=m_flow_small), + h = SorpLib.Numerics.regStep_noEvent( + x=port_a.m_flow, + y1=inStream(port_a.h_outflow), + y2=inStream(port_b.h_outflow), + x_small=m_flow_small), + X = SorpLib.Numerics.regStep_noEvent( + x=port_a.m_flow, + y1=inStream(port_a.Xi_outflow), + y2=inStream(port_b.Xi_outflow), + x_small=m_flow_small)) + "Record describing current state properties of liquid at inlet"; + + else + Medium_liq.setState_phX( + p = SorpLib.Numerics.regStep( + x=port_a.m_flow, + y1=port_a.p, + y2=port_a.p, + x_small=m_flow_small), + h = SorpLib.Numerics.regStep( + x=port_a.m_flow, + y1=inStream(port_a.h_outflow), + y2=inStream(port_b.h_outflow), + x_small=m_flow_small), + X = SorpLib.Numerics.regStep( + x=port_a.m_flow, + y1=inStream(port_a.Xi_outflow), + y2=inStream(port_b.Xi_outflow), + x_small=m_flow_small)) + "Record describing current state properties of liquid at inlet"; + + end if; + end if; + + // + // Calculate fluid properties at inlets + // + T_liq_in = Medium_liq.temperature(state=state_liq_in) + "Inlet temperature of liquid"; + cp_liq_in = Medium_liq.specificHeatCapacityCp(state=state_liq_in) + "Specific heat capacity of liquid at inlet"; + eta_liq_in = Medium_liq.dynamicViscosity(state=state_liq_in) + "Dynamic viscosity of liquid at inlet"; + + d_air_in = Medium_air.density(state=state_air_in) + "Density of air at inlet"; + cp_air_in = Medium_air.specificHeatCapacityCp(state=state_air_in) + "Specific heat capacity of air at inlet"; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +The model of the simple dry cooler describes the cooling of an (ideal) liquid. Air +is used as the cooling medium. The model can be adapted to the performance of real +dry coolers using two fitting parameters for the heat tranfer correlations. +</p> + +<h4>Main equations</h4> +<p> +The model has a steady-state energy balance +</p> +<pre> + 0 = ṁ<sub>liq,in</sub> + ṁ<sub>liq,out</sub>; +</pre> +<p> +and a steady-state energy balance +</p> +<pre> + h<sub>liq,out</sub> = h<sub>liq,in</sub> - Q_flow / ṁ<sub>liq,out</sub>; +</pre> +<p> +Herein, <i>ṁ<sub>liq,in</sub></i>/<i>ṁ<sub>liq,out</sub></i> are the +inlet/outlet liquid mass flow rates, <i>h<sub>liq,in</sub></i>/<i>h<sub>liq,out</sub></i> +are the liquid specific enthalies at inlet/outlet, <i>Q_flow</i> is the heat flow +rate transferred to the surrounding. The heat flow rate <i>Q_flow</i> ist calculated +with the effectiveness <i>ε</i> of the dry cooler and the maximal heat flow +rate <i>Q_flow<sub>max</sub></i> that can be transferred: +</p> +<pre> + Q_flow = ε * Q_flow<sub>max</sub> = ε * C_flow<sub>min</sub> * (T<sub>liq,in</sub> - T<sub>air,in</sub>); +</pre> +<p> +Herein, <i>T<sub>liq,in</sub></i>/<i>T<sub>air,in</sub></i> are the inlet temperatures of +the liquid/ambient air, and <i>C_flow<sub>min</sub></i> is the minimal heat capacity rate. +The minimal and maximal heat capacity rates are defined as follows: +</p> +<pre> + C_flow<sub>min</sub> = <strong>min</strong>(ṁ<sub>liq</sub>*c;<sub>p,liq</sub>, V_flow<sub>air</sub>*ρ;<sub>air</sub>*c;<sub>p,air</sub>); + + C_flow<sub>max</sub> = <strong>max</strong>(ṁ<sub>liq</sub>*c;<sub>p,liq</sub>, V_flow<sub>air</sub>*ρ;<sub>air</sub>*c;<sub>p,air</sub>); +</pre> +<p> +Herein, <i>c;<sub>p,liq</sub></i>/<i>c;<sub>p,air</sub></i> are the specific heat +capacities of the liquid/ambient air, <i>ρ<sub>air</sub></i> is the density of the +ambient air, and <i>V_flow<sub>air</sub></i> is the volume flow rate of the ambient air. +<br/><br/> +For a counter-current flow heat exchanger, the effectiveness <i>ε</i> is defined as +</p> +<pre> + ε = [1 - <strong>exp</strong>(-NTU * (1 - C_flow<sub>min</sub>/C_flow<sub>max</sub>)] / [1 - C_flow<sub>min</sub>/C_flow<sub>max</sub> * <strong>exp</strong>(-NTU * (1 - C_flow<sub>min</sub>/C_flow<sub>max</sub>]; +</pre> +<p> +where the number of transfer units <i>NTU</i> for the dry cooler was calculated as +</p> +<pre> + NTU = 1/C_flow<sub>min</sub> * (αA)<sub>liq</sub> * (αA)<sub>air</sub> / ((αA)<sub>liq</sub> + (αA)<sub>air</sub>); +</pre> +<p> +Herein, the products of heat transfer coefficients and areas describe the heat transfer +on the liquid side <i>(αA)<sub>liq</sub></i> and the ambient air side +<i>(αA)<sub>air</sub></i> . Gibelhaus et al. selected mass-flow-dependent approaches +for the two products: +</p> +<pre> + (αA)<sub>liq</sub> = 2 * δ * ṁ<sub>liq</sub>^(0.8) * η<sub>liq</sub>^(-0.8); + + (αA)<sub>air</sub> = 0.35 * γ * (V_flow<sub>air</sub> * ρ<sub>air</sub>)^(0.8); +</pre> +<p> +where <i>η<sub>liq</sub></i> is the dynamic viscosity of the liquid, and +<i>δ</i>/<i>γ</i> are fitting parameters. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The model is typically used to describe the cooling of the heat transfer fluid of +the condeser or of the adsorber to the surrounding. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>flowDirection</i>: + Defines the flow dirction and, thus, the inlet property calculation. + </li> + <li> + <i>typeDryRecooler</i>: + Defines the type of the dry cooler. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Engelpracht, M. (2024). Experimental demonstration and model-based optimization of adsorption heat transformation for waste heat upgrading. In: Aachener Beiträge zur technischen Thermodynamik 51. DOI: http://dx.doi.org/10.18154/RWTH-2024-06878. + </li> + <li> + Gibelhaus, A. and Tangkrachang, T. and Bau, U. and Seiler, J. and Bardow, A. (2019). Integrated design and control of full sorption chiller systems. Energy 185 (2019), pp. 409-422. DOI: https://doi.org/10.1016/j.energy.2019.06.169. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 26, 2024, by Mirko Engelpracht:<br/> + Minor adaptations and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SimpleDryCooler; diff --git a/SorpLib/Components/HeatExchanger/Recoolers/Tester/Test_SimpleDryCooler.mo b/SorpLib/Components/HeatExchanger/Recoolers/Tester/Test_SimpleDryCooler.mo new file mode 100644 index 0000000000000000000000000000000000000000..a4be70e16f0b34f2671ee0025b41190c79657572 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Recoolers/Tester/Test_SimpleDryCooler.mo @@ -0,0 +1,111 @@ +within SorpLib.Components.HeatExchanger.Recoolers.Tester; +model Test_SimpleDryCooler "Tester for the simple dry cooler" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + V_flow_fixed(displayUnit="l/min") = -0.0016666666666667, + use_TInput=true, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-50,-10},{-30,10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{50,-10},{30,10}}))); + + SorpLib.Components.Sensors.LiquidSensors.TemperatureSensor T_liqOut( + redeclare package Medium = Medium) + "Outlet liquid temperature" + annotation (Placement(transformation(extent={{10,4},{30,24}}))); + + // + // Definition of multi ports + // + SorpLib.Components.HeatExchanger.Recoolers.SimpleDryCooler dryCooler( + p_air=100000, + T_air_in(displayUnit="K") = 283.15, + redeclare final package Medium_liq = Medium) + "Simple dry cooler" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_fRelAir( + amplitude=0.45, + f=1/500, + offset=0.5) + "Input signal for relative air volume flow rate" + annotation (Placement(transformation(extent={{-40,-40},{-20,-20}}))); + Modelica.Blocks.Sources.Sine input_TLiq( + amplitude=20, + f=1/250, + offset=273.15+40) + "Input signal for liquid inlet temperature" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + +equation + // + // Connections + // + connect(fs_a.port, dryCooler.port_a) annotation (Line( + points={{-40,0},{-10,0}}, + color={28,108,200}, + thickness=1)); + connect(dryCooler.port_b, fs_b.port) annotation (Line( + points={{10,0},{40,0}}, + color={28,108,200}, + thickness=1)); + connect(T_liqOut.port, dryCooler.port_b) annotation (Line( + points={{20,6},{20,0},{10,0}}, + color={28,108,200}, + thickness=1)); + + connect(input_TLiq.y, fs_a.T_input) annotation (Line(points={{-59,0},{-50,0},{ + -50,-2},{-41.2,-2}}, color={0,0,127})); + connect(input_fRelAir.y, dryCooler.relativeFanSpeed) + annotation (Line(points={{-19,-30},{0,-30},{0,-6}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the simple dry cooler. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 26, 2024, by Mirko Engelpracht:<br/> + Adaptations due to restructering the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_SimpleDryCooler; diff --git a/SorpLib/Components/HeatExchanger/Recoolers/Tester/package.mo b/SorpLib/Components/HeatExchanger/Recoolers/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..407a43c5c2557347aa51e222d88e607484368f48 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Recoolers/Tester/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.HeatExchanger.Recoolers; +package Tester "Models to test and varify dry cooler models" + extends Modelica.Icons.ExamplesPackage; + + + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented dry coolers. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/HeatExchanger/Recoolers/Tester/package.order b/SorpLib/Components/HeatExchanger/Recoolers/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..683f3e4aba9b9948a5a8e23eee0b09fed95cbbbc --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Recoolers/Tester/package.order @@ -0,0 +1 @@ +Test_SimpleDryCooler diff --git a/SorpLib/Components/HeatExchanger/Recoolers/package.mo b/SorpLib/Components/HeatExchanger/Recoolers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..289eb7ab9dd15559d13f0c6472e9d8f1ffe55391 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Recoolers/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.HeatExchanger; +package Recoolers "Recoolers used in closed and open sorption systems" + extends SorpLib.Icons.RecoolersPackage; + + annotation (Documentation(info="<html> +<p> +This package contains recooler models that are based on the open-source Modelica +Standard Library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Recoolers; diff --git a/SorpLib/Components/HeatExchanger/Recoolers/package.order b/SorpLib/Components/HeatExchanger/Recoolers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..0265a95de3d0efdd187e25f43238a3db51b7ea78 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Recoolers/package.order @@ -0,0 +1,2 @@ +SimpleDryCooler +Tester diff --git a/SorpLib/Components/HeatExchanger/Records/GeometryClosedAdsorber.mo b/SorpLib/Components/HeatExchanger/Records/GeometryClosedAdsorber.mo new file mode 100644 index 0000000000000000000000000000000000000000..7f3f7da6dfc2f1d9a4577495cf4ee81026900e1c --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Records/GeometryClosedAdsorber.mo @@ -0,0 +1,229 @@ +within SorpLib.Components.HeatExchanger.Records; +record GeometryClosedAdsorber + "This record contains the geometry of closed adsorbers" + extends Modelica.Icons.Record; + + // + // Definition of parameters regarding the disretization + // + parameter Integer no_fluidVolumes(min=1) = 1 + "Number of fluid volumes" + annotation (Dialog(tab="General", group="Discretization", enable=false)); + parameter Integer no_wallVolumes(min=1) = 1 + "Number of wall volumes" + annotation (Dialog(tab="General", group="Discretization", enable=false)); + parameter Integer no_sorbentVolumes(min=1) = 1 + "Number of sorbent volumes" + annotation (Dialog(tab="General", group="Discretization", enable=false)); + + // + // Definition of parameters regarding the geometry of the casing + // + parameter Modelica.Units.SI.Length l_cas = 1.25 + "Length of the casing" + annotation (Dialog(tab="Casing", group="General")); + + parameter Modelica.Units.SI.Diameter d_inner_cas = 0.32 + "Inner diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_outer_cas = 0.325 + "Outer diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_hydInner_cas = d_inner_cas + "Hydraulic inner diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_hydOuter_cas = d_outer_cas + "Hydraulic outer diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + + parameter Modelica.Units.SI.Thickness t_wall_cas= + (d_outer_cas - d_inner_cas) / 2 + "Wall thickness of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + + parameter Modelica.Units.SI.Area A_crossInner_cas= + Modelica.Constants.pi/4 * d_inner_cas^2 + "Inner cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_crossOuter_cas= + Modelica.Constants.pi/4 * d_outer_cas^2 + "Outer cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_crossWall_cas= + A_crossOuter_cas - A_crossInner_cas + "Wall cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossInner_cas= + Modelica.Constants.pi/4 * d_hydInner_cas^2 + "Hydraulic inner cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossOuter_cas= + Modelica.Constants.pi/4 * d_hydOuter_cas^2 + "Hydraulic outer cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossWall_cas= + A_hydCrossOuter_cas - A_hydCrossInner_cas + "Hydaulic wall cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferInner_cas= + Modelica.Constants.pi * d_inner_cas * l_cas + "Inner heat transfer area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferOuter_cas= + Modelica.Constants.pi * d_outer_cas * l_cas + "Outer heat transfer area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + + parameter Modelica.Units.SI.Volume V_inner_cas= + Modelica.Constants.pi/4 * d_inner_cas^2 * l_cas + "Inner volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_outer_cas= + Modelica.Constants.pi/4 * d_outer_cas^2 * l_cas + "Outer volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_wall_cas= + V_outer_cas - V_inner_cas + "Wall volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_vapor_cas= + V_inner_cas - V_outer_hx - V_particles + "Vapor volume within the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + + // + // Definition of parameters regarding the the heat exchanger + // + parameter Integer no_hydraulicParallelTubes(min=1) = 1 + "Number of hydraulically parallel tubes" + annotation (Dialog(tab="Heat Exchanger", group="General")); + parameter Modelica.Units.SI.Length l_hx = 1 + "Length of the tube" + annotation (Dialog(tab="Heat Exchanger", group="General")); + parameter Modelica.Units.SI.Length roughness_hx = 7.5e-7 + "Absolute roughness of the tube" + annotation (Dialog(tab="Heat Exchanger", group="General")); + + parameter Modelica.Units.SI.Diameter d_inner_hx = 0.01 + "Inner diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_outer_hx = 0.012 + "Outer diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_hydInner_hx = d_inner_hx + "Hydraulic inner diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_hydOuter_hx = d_outer_hx + "Hydraulic outer diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Thickness t_wall_hx= + (d_outer_hx - d_inner_hx) / 2 + "Wall thickness of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + + parameter Modelica.Units.SI.Area A_crossInner_hx= + Modelica.Constants.pi/4 * d_inner_hx^2 + "Inner cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_crossOuter_hx= + Modelica.Constants.pi/4 * d_outer_hx^2 + "Outer cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_crossWall_hx= + A_crossOuter_hx - A_crossInner_hx + "Wall cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossInner_hx = A_crossInner_hx + "Hydraulic inner cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossOuter_hx = A_crossOuter_hx + "Hydraulic outer cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossWall_hx= + A_hydCrossOuter_hx - A_hydCrossInner_hx + "Hydraulic wall cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferInner_hx= + Modelica.Constants.pi * d_inner_hx * l_hx + "Total inner heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferOuter_hx= + Modelica.Constants.pi * d_outer_hx * l_hx + "Total outer heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Real f_finAreaRatioInner_hx(min=0, max=1) = 0 + "Ratio of total inner fin area to total inner heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Real f_finAreaRatioOuter_hx(min=0, max=1) = 0 + "Ratio of total outer fin area to total outer heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + + parameter Modelica.Units.SI.Volume V_inner_hx = A_crossInner_hx * l_hx + "Total inner volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_outer_hx = A_crossOuter_hx * l_hx + "Total outer volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_wall_hx = V_outer_hx - V_inner_hx + "Total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_sorbent_hx = 0.0025 + "Total volume that can be filled with sorbent" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Real f_finVolumeRatioInner_hx(min=0, max=1) = 0 + "Ratio of total inner fin volume to total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Real f_finVolumeRatioOuter_hx(min=0, max=1) = 0 + "Ratio of total outer fin volume to total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + + // + // Definition of parameters regarding the sorbent gemeotry + // + parameter Real no_particles = (1-psi_particles) * V_sorbent_hx / V_particle + "Number of particles" + annotation (Dialog(tab="Sorbent", group="General")); + parameter Real psi_particles(unit="1") = 1 - 0.74 + "Void fraction of the adsorber (i.e., ratio of the free fluid volume to + the total inner volume)" + annotation (Dialog(tab="Sorbent", group="General")); + + parameter Modelica.Units.SI.Diameter d_particle = 0.7 / 1000 + "Average diameter of the adsorbent particles" + annotation (Dialog(tab="Sorbent", group="Diameters")); + + parameter Modelica.Units.SI.Area A_cross_particle= + Modelica.Constants.pi/4 * d_particle^2 + "Average cross-sectional area of the particle" + annotation (Dialog(tab="Sorbent", group="Areas")); + parameter Modelica.Units.SI.Area A_surface_particle= + Modelica.Constants.pi * d_particle^2 + "Average suraface area of the particle" + annotation (Dialog(tab="Sorbent", group="Areas")); + + parameter Modelica.Units.SI.Volume V_particle= + Modelica.Constants.pi/6 * d_particle^3 + "Average volume of the particle" + annotation (Dialog(tab="Sorbent", group="Volumes")); + parameter Modelica.Units.SI.Volume V_particles= + no_particles * V_particle + "Average volume of all particles" + annotation (Dialog(tab="Sorbent", group="Volumes")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters required by models calculating the heat +transfer coefficients of closed adsorbers. +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryClosedAdsorber; diff --git a/SorpLib/Components/HeatExchanger/Records/GeometryCondenserEvaporator.mo b/SorpLib/Components/HeatExchanger/Records/GeometryCondenserEvaporator.mo new file mode 100644 index 0000000000000000000000000000000000000000..cdbfb8e88b25551c37880d0da17bcb3fd4ef0482 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Records/GeometryCondenserEvaporator.mo @@ -0,0 +1,200 @@ +within SorpLib.Components.HeatExchanger.Records; +record GeometryCondenserEvaporator + "This record contains the geometry of condensers or evaporators" + extends Modelica.Icons.Record; + + // + // Definition of parameters regarding the disretization + // + parameter Integer no_fluidVolumes(min=1) = 1 + "Number of fluid volumes" + annotation (Dialog(tab="General", group="Discretization", enable=false)); + parameter Integer no_wallVolumes(min=1) = 1 + "Number of wall volumes" + annotation (Dialog(tab="General", group="Discretization", enable=false)); + + // + // Definition of parameters regarding the geometry of the casing + // + parameter Modelica.Units.SI.Length l_cas = 1 + "Length of the casing" + annotation (Dialog(tab="Casing", group="General")); + + parameter Modelica.Units.SI.Diameter d_inner_cas = 0.100 + "Inner diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_outer_cas = 0.103 + "Outer diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_hydInner_cas = d_inner_cas + "Hydraulic inner diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_hydOuter_cas = d_outer_cas + "Hydraulic outer diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + + parameter Modelica.Units.SI.Thickness t_wall_cas= + (d_outer_cas - d_inner_cas) / 2 + "Wall thickness of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + + parameter Modelica.Units.SI.Area A_crossInner_cas= + Modelica.Constants.pi/4 * d_inner_cas^2 + "Inner cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_crossOuter_cas= + Modelica.Constants.pi/4 * d_outer_cas^2 + "Outer cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_crossWall_cas= + A_crossOuter_cas - A_crossInner_cas + "Wall cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossInner_cas= + Modelica.Constants.pi/4 * d_hydInner_cas^2 + "Hydraulic inner cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossOuter_cas= + Modelica.Constants.pi/4 * d_hydOuter_cas^2 + "Hydraulic outer cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossWall_cas= + A_hydCrossOuter_cas - A_hydCrossInner_cas + "Hydaulic wall cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferInner_cas= + Modelica.Constants.pi * d_inner_cas * l_cas + "Inner heat transfer area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferOuter_cas= + Modelica.Constants.pi * d_outer_cas * l_cas + "Outer heat transfer area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + + parameter Modelica.Units.SI.Volume V_inner_cas= + Modelica.Constants.pi/4 * d_inner_cas^2 * l_cas + "Inner volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_outer_cas= + Modelica.Constants.pi/4 * d_outer_cas^2 * l_cas + "Outer volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_wall_cas= + V_outer_cas - V_inner_cas + "Wall volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + + // + // Definition of parameters regarding the the heat exchanger + // + parameter Integer no_hydraulicParallelTubes(min=1) = 1 + "Number of hydraulically parallel tubes" + annotation (Dialog(tab="Heat Exchanger", group="General")); + parameter Modelica.Units.SI.Length l_hx = 1 + "Length of the tube" + annotation (Dialog(tab="Heat Exchanger", group="General")); + parameter Modelica.Units.SI.Length roughness_hx = 7.5e-7 + "Absolute roughness of the tube" + annotation (Dialog(tab="Heat Exchanger", group="General")); + + parameter Modelica.Units.SI.Diameter d_inner_hx = 0.01 + "Inner diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_outer_hx = 0.012 + "Outer diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_hydInner_hx = d_inner_hx + "Hydraulic inner diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_hydOuter_hx = d_outer_hx + "Hydraulic outer diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Thickness t_wall_hx= + (d_outer_hx - d_inner_hx) / 2 + "Wall thickness of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + + parameter Modelica.Units.SI.Area A_crossInner_hx= + Modelica.Constants.pi/4 * d_inner_hx^2 + "Inner cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_crossOuter_hx= + Modelica.Constants.pi/4 * d_outer_hx^2 + "Outer cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_crossWall_hx= + A_crossOuter_hx - A_crossInner_hx + "Wall cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossInner_hx = A_crossInner_hx + "Hydraulic inner cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossOuter_hx = A_crossOuter_hx + "Hydraulic outer cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossWall_hx= + A_hydCrossOuter_hx - A_hydCrossInner_hx + "Hydraulic wall cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferInner_hx= + Modelica.Constants.pi * d_inner_hx * l_hx + "Total inner heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferOuter_hx= + Modelica.Constants.pi * d_outer_hx * l_hx + "Total outer heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Real f_finAreaRatioInner_hx(min=0, max=1) = 0 + "Ratio of total inner fin area to total inner heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Real f_finAreaRatioOuter_hx(min=0, max=1) = 0 + "Ratio of total outer fin area to total outer heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + + parameter Modelica.Units.SI.Volume V_inner_hx = A_crossInner_hx * l_hx + "Total inner volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_outer_hx = A_crossOuter_hx * l_hx + "Total outer volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_wall_hx = V_outer_hx - V_inner_hx + "Total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Real f_finVolumeRatioInner_hx(min=0, max=1) = 0 + "Ratio of total inner fin volume to total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Real f_finVolumeRatioOuter_hx(min=0, max=1) = 0 + "Ratio of total outer fin volume to total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + + // + // Definition of parameters regarding the phase separator + // + parameter Modelica.Units.SI.Area A_refrigerant=0.05 + "Base area of the phase seprator" + annotation (Dialog(tab="Phase Seperator", group="Areas")); + parameter Modelica.Units.SI.Volume V_refrigerant= + V_inner_cas - V_outer_hx + "Total volume of the phase seperator" + annotation (Dialog(tab="Phase Seperator", group="Volumes")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters describing condensers or evaporators. +</p> +</html>", revisions="<html> +<ul> + <li> + March 4, 2024, by Mirko Engelpracht:<br/> + Minor adaptations. + </li> + <li> + January 14, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryCondenserEvaporator; diff --git a/SorpLib/Components/HeatExchanger/Records/ParametrizationDryCooler.mo b/SorpLib/Components/HeatExchanger/Records/ParametrizationDryCooler.mo new file mode 100644 index 0000000000000000000000000000000000000000..4323b88422cedbd9d4ce8a6d81c9418428df12cb --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Records/ParametrizationDryCooler.mo @@ -0,0 +1,59 @@ +within SorpLib.Components.HeatExchanger.Records; +record ParametrizationDryCooler + "This record contains parameters describing dry coolers" + extends Modelica.Icons.Record; + + // + // Definition of parameters + // + parameter Real gamma = 11.52 + "Factor for external heat transfer coefficient" + annotation (Dialog(tab="Genral", group="Heat Transfer")); + parameter Real delta = 303.09 + "Factor for internal heat transfer coefficient" + annotation (Dialog(tab="Genral", group="Heat Transfer")); + + parameter Modelica.Units.SI.MassFlowRate m_flow_liq_nom= + 28.78 / 3600 * 1000 + "Nominal mass flow rate of liquid medium that shall be cooled" + annotation (Dialog(tab="Genral", group="Nominal Operating Point")); + parameter Modelica.Units.SI.PressureDifference dp_liq_nom= + 0.77*10^5 + "Nominal pressure drop of liquid medium at nominal mass flow rate" + annotation (Dialog(tab="Genral", group="Nominal Operating Point")); + + parameter Modelica.Units.SI.VolumeFlowRate V_flow_air_max = 88368/3600 + "Maximal air flow rate" + annotation (Dialog(tab="Genral", group="Maximal Operating Point")); + parameter Modelica.Units.SI.Power P_el_fan_max = 16.2*10^3 + "Maximal power consumption of the fan units" + annotation (Dialog(tab="Genral", group="Maximal Operating Point")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains parameters characterizing dry coolers. The default parameters +correspond to the dry cooler GFHC WD 063 from Guenther, fitted by Gibelhaus (2019). +</p> + +<h4>References</h4> +<ul> + <li> + Gibelhaus, A. and Tangkrachang, T. and Bau, U. and Seiler, J. and Bardow, A. (2019). Integrated design and control of full sorption chiller systems. Energy 185 (2019), pp. 409-422. DOI: https://doi.org/10.1016/j.energy.2019.06.169. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 15, 2024, by Mirko Engelpracht:<br/> + Minor adaptations and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ParametrizationDryCooler; diff --git a/SorpLib/Components/HeatExchanger/Records/SummaryClosedAdsorber.mo b/SorpLib/Components/HeatExchanger/Records/SummaryClosedAdsorber.mo new file mode 100644 index 0000000000000000000000000000000000000000..cd2e81198939b28bb22d59b9a0d25b3c550a5751 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Records/SummaryClosedAdsorber.mo @@ -0,0 +1,118 @@ +within SorpLib.Components.HeatExchanger.Records; +record SummaryClosedAdsorber + "This record summarizes the most important variables of closed adsorbers" + extends Modelica.Icons.Record; + + // + // Variables describing the vapor + // + Modelica.Units.SI.Pressure p_vapor + "Average pressure in vapor volume" + annotation (Dialog(tab="General", group="Vapor volume")); + Modelica.Units.SI.Temperature T_vapor + "Average temperature in vapor volume" + annotation (Dialog(tab="General", group="Vapor volume")); + Modelica.Units.SI.Density rho_vapor + "Average density in vapor volume" + annotation (Dialog(tab="General", group="Vapor volume")); + + Modelica.Units.SI.Mass mass_vapor + "Fluid mass in vapor volume" + annotation (Dialog(tab="General", group="Vapor volume")); + + // + // Variables describing the sorbent + // + Modelica.Units.SI.Pressure p_adsorbate_avg + "Average adsorabte pressure" + annotation (Dialog(tab="General", group="Adsorbate")); + Modelica.Units.SI.Temperature T_adsorbate_avg + "Average adsorabte temperature" + annotation (Dialog(tab="General", group="Adsorbate")); + SorpLib.Units.Uptake x_adsorbate_avg + "Average adsorabte loading" + annotation (Dialog(tab="General", group="Adsorbate")); + + Modelica.Units.SI.Mass mass_adsorpt + "Adsorpt mass" + annotation (Dialog(tab="General", group="Adsorbate")); + + // + // Variables describing the heat exchanger + // + Modelica.Units.SI.Pressure p_liq_inlet + "Pressure of liquid at heat exchanger inlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Pressure p_liq_outlet + "Pressure of liquid at heat exchanger outlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Pressure p_liq_avg + "Average pressure of liquid in heat exchanger" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.PressureDifference dp_liq = p_liq_inlet - p_liq_outlet + "Pressure difference of liquid in heat exchanger"; + + Modelica.Units.SI.Temperature T_liq_inlet + "Temperature of liquid at heat exchanger inlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Temperature T_liq_outlet + "Temperature of liquid at heat exchanger outlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Temperature T_liq_avg + "Average temperature of liquid in heat exchanger" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + + Modelica.Units.SI.Temperature T_wall_avg + "Average wall temperature of heat exchanger" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + + // + // Variables required for balance equations + // + Modelica.Units.SI.MassFlowRate m_flow_liq_inlet + "Mass flow rate of liquid at inlet of heat exchanger" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.MassFlowRate m_flow_liq_outlet + "Mass flow rate of liquid at outlet of heat exchanger" + annotation (Dialog(tab="General", group="Balance Equations")); + + Modelica.Units.SI.MassFlowRate m_flow_evaporator + "Mass flow rate from evaporator" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.MassFlowRate m_flow_condenser + "Mass flow rate from condenser" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.MassFlowRate m_flow_massRecovery + "Mass flow rate from mass recovery ports" + annotation (Dialog(tab="General", group="Balance Equations")); + + Modelica.Units.SI.HeatFlowRate Q_flow_wallToSorbent + "Heat flow rate from heat exchanger walls to sorbent" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.HeatFlowRate Q_flow_fluidWall + "Heat flow rate from liquid to wall" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.HeatFlowRate DH_liquid + "Difference enthalpy flow of liquid in heat exchanger" + annotation (Dialog(tab="General", group="Balance Equations")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record summarizes the most important variables of closed adsorbers +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + Minor adaptations. + </li> + <li> + January 14, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SummaryClosedAdsorber; diff --git a/SorpLib/Components/HeatExchanger/Records/SummaryCondenserEvaporator.mo b/SorpLib/Components/HeatExchanger/Records/SummaryCondenserEvaporator.mo new file mode 100644 index 0000000000000000000000000000000000000000..4fc69cc2d548b4c4592b14d26233380097cbc04f --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Records/SummaryCondenserEvaporator.mo @@ -0,0 +1,97 @@ +within SorpLib.Components.HeatExchanger.Records; +record SummaryCondenserEvaporator + "This record summarizes the most important variables of condensers or evaporators" + extends Modelica.Icons.Record; + + // + // Variables describing the phase seperator + // + Modelica.Units.SI.Pressure p_VLE + "Average pressure in phase seperator" + annotation (Dialog(tab="General", group="Phase Seperator")); + Modelica.Units.SI.Density rho_VLE + "Average density in phase seperator" + annotation (Dialog(tab="General", group="Phase Seperator")); + Modelica.Units.SI.Temperature T_VLE + "Average temperature in phase seperator" + annotation (Dialog(tab="General", group="Phase Seperator")); + + Modelica.Units.SI.Mass mass + "Fluid mass in phase seperator" + annotation (Dialog(tab="General", group="Phase Seperator")); + + // + // Variables describing the heat exchanger + // + Modelica.Units.SI.Pressure p_liq_inlet + "Pressure of liquid at heat exchanger inlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Pressure p_liq_outlet + "Pressure of liquid at heat exchanger outlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Pressure p_liq_avg + "Average pressure of liquid in heat exchanger" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.PressureDifference dp_liq = p_liq_inlet - p_liq_outlet + "Pressure difference of liquid in heat exchanger"; + + Modelica.Units.SI.Temperature T_liq_inlet + "Temperature of liquid at heat exchanger inlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Temperature T_liq_outlet + "Temperature of liquid at heat exchanger outlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Temperature T_liq_avg + "Average temperature of liquid in heat exchanger" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + + Modelica.Units.SI.Temperature T_wall_avg + "Average wall temperature of heat exchanger" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + + // + // Variables required for balance equations + // + Modelica.Units.SI.MassFlowRate m_flow_liq_inlet + "Mass flow rate of liquid at inlet of heat exchanger" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.MassFlowRate m_flow_liq_outlet + "Mass flow rate of liquid at outlet of heat exchanger" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.MassFlowRate m_flow_vapor + "Mass flow rate of vapor from heat exchanger to working pair cells" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.MassFlowRate m_flow_liquid + "Mass flow rate of liquid" + annotation (Dialog(tab="General", group="Balance Equations")); + + Modelica.Units.SI.HeatFlowRate Q_flow_wallToPhaseSeparator + "Heat flow rate from heat exchanger walls to phase seperator" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.HeatFlowRate Q_flow_fluidWall + "Heat flow rate from liquid to wall" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.HeatFlowRate DH_liquid + "Difference enthalpy flow of liquid in heat exchanger" + annotation (Dialog(tab="General", group="Balance Equations")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record summarizes the most important variables of condensers or evaporators. +</p> +</html>", revisions="<html> +<ul> + <li> + March 4, 2024, by Mirko Engelpracht:<br/> + Minor adaptations. + </li> + <li> + January 14, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SummaryCondenserEvaporator; diff --git a/SorpLib/Components/HeatExchanger/Records/SummarySimpleClosedAdsorber.mo b/SorpLib/Components/HeatExchanger/Records/SummarySimpleClosedAdsorber.mo new file mode 100644 index 0000000000000000000000000000000000000000..1e448ed102fbd5b528dd1fb2b3e941ad4774e522 --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Records/SummarySimpleClosedAdsorber.mo @@ -0,0 +1,101 @@ +within SorpLib.Components.HeatExchanger.Records; +record SummarySimpleClosedAdsorber + "This record summarizes the most important variables of simple closed adsorbers" + extends Modelica.Icons.Record; + + // + // Variables describing the sorbent + // + Modelica.Units.SI.Pressure p_adsorbate_avg + "Average adsorabte pressure" + annotation (Dialog(tab="General", group="Adsorbate")); + Modelica.Units.SI.Temperature T_adsorbate_avg + "Average adsorabte temperature" + annotation (Dialog(tab="General", group="Adsorbate")); + SorpLib.Units.Uptake x_adsorbate_avg + "Average adsorabte loading" + annotation (Dialog(tab="General", group="Adsorbate")); + + Modelica.Units.SI.Mass mass_adsorpt + "Adsorpt mass" + annotation (Dialog(tab="General", group="Adsorbate")); + + // + // Variables describing the heat exchanger + // + Modelica.Units.SI.Pressure p_liq_inlet + "Pressure of liquid at heat exchanger inlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Pressure p_liq_outlet + "Pressure of liquid at heat exchanger outlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Pressure p_liq_avg + "Average pressure of liquid in heat exchanger" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.PressureDifference dp_liq = p_liq_inlet - p_liq_outlet + "Pressure difference of liquid in heat exchanger"; + + Modelica.Units.SI.Temperature T_liq_inlet + "Temperature of liquid at heat exchanger inlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Temperature T_liq_outlet + "Temperature of liquid at heat exchanger outlet" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + Modelica.Units.SI.Temperature T_liq_avg + "Average temperature of liquid in heat exchanger" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + + Modelica.Units.SI.Temperature T_wall_avg + "Average wall temperature of heat exchanger" + annotation (Dialog(tab="General", group="Heat Exchanger Tubes")); + + // + // Variables required for balance equations + // + Modelica.Units.SI.MassFlowRate m_flow_liq_inlet + "Mass flow rate of liquid at inlet of heat exchanger" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.MassFlowRate m_flow_liq_outlet + "Mass flow rate of liquid at outlet of heat exchanger" + annotation (Dialog(tab="General", group="Balance Equations")); + + Modelica.Units.SI.MassFlowRate m_flow_evaporator + "Mass flow rate from evaporator" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.MassFlowRate m_flow_condenser + "Mass flow rate from condenser" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.MassFlowRate m_flow_massRecovery + "Mass flow rate from mass recovery ports" + annotation (Dialog(tab="General", group="Balance Equations")); + + Modelica.Units.SI.HeatFlowRate Q_flow_wallToSorbent + "Heat flow rate from heat exchanger walls to sorbent" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.HeatFlowRate Q_flow_fluidWall + "Heat flow rate from liquid to wall" + annotation (Dialog(tab="General", group="Balance Equations")); + Modelica.Units.SI.HeatFlowRate DH_liquid + "Difference enthalpy flow of liquid in heat exchanger" + annotation (Dialog(tab="General", group="Balance Equations")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record summarizes the most important variables of simple closed adsorbers +</p> +</html>", revisions="<html> +<ul> + <li> + March 5, 2024, by Mirko Engelpracht:<br/> + Minor adaptations. + </li> + <li> + January 14, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SummarySimpleClosedAdsorber; diff --git a/SorpLib/Components/HeatExchanger/Records/package.mo b/SorpLib/Components/HeatExchanger/Records/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..37a961ef202af2655720fc8869579abc24f1e41d --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Records/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.HeatExchanger; +package Records "Package containing records" + extends Modelica.Icons.RecordsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains definitions of records. These records are used to cluster +variables and tidy up the model output. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Records; diff --git a/SorpLib/Components/HeatExchanger/Records/package.order b/SorpLib/Components/HeatExchanger/Records/package.order new file mode 100644 index 0000000000000000000000000000000000000000..1fa296418db39e35766df9958e11b2d8d750abaa --- /dev/null +++ b/SorpLib/Components/HeatExchanger/Records/package.order @@ -0,0 +1,6 @@ +GeometryCondenserEvaporator +GeometryClosedAdsorber +ParametrizationDryCooler +SummaryCondenserEvaporator +SummaryClosedAdsorber +SummarySimpleClosedAdsorber diff --git a/SorpLib/Components/HeatExchanger/package.mo b/SorpLib/Components/HeatExchanger/package.mo index a93fa27168f117eede6d0c8a6de33485df187df1..1723ab827676f05841c65045fd89fade5487e916 100644 --- a/SorpLib/Components/HeatExchanger/package.mo +++ b/SorpLib/Components/HeatExchanger/package.mo @@ -1,10 +1,18 @@ within SorpLib.Components; -package HeatExchanger -extends SorpLib.Internals.ClassTypes.ComponentPackage; +package HeatExchanger "Heat exchangers to transfer heat between different fluid fows" + extends SorpLib.Icons.HeatExchangersPackage; - - - - -annotation (Icon(graphics)); + annotation (Documentation(info="<html> +<p> +This package contains heat exchangers. Ready-to-use models are based on the Modelica +Standard library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); end HeatExchanger; diff --git a/SorpLib/Components/HeatExchanger/package.order b/SorpLib/Components/HeatExchanger/package.order index e8076f9fd909a6fc9369c69efc04e8db7f3b6f11..cd7bf27256063b038ef2c8ed99295697f50372ea 100644 --- a/SorpLib/Components/HeatExchanger/package.order +++ b/SorpLib/Components/HeatExchanger/package.order @@ -1 +1,5 @@ -HXAirAirParallelflow +BaseClasses +Records +CondensersEvaporators +Adsorbers +Recoolers diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/PartialClosedAdsorberHeatTransferCoefficient.mo b/SorpLib/Components/HeatTransfer/BaseClasses/PartialClosedAdsorberHeatTransferCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..268bce952ef95876f507aeae37c29d652720ad40 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/PartialClosedAdsorberHeatTransferCoefficient.mo @@ -0,0 +1,50 @@ +within SorpLib.Components.HeatTransfer.BaseClasses; +partial model PartialClosedAdsorberHeatTransferCoefficient + "Base model for all models calculating the product of heat transfer coefficient and area for closed adsorbers" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransferCoefficient; + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the sorbent)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Definition of parameters + // + replaceable parameter SorpLib.Components.HeatTransfer.Records.GeometryClosedAdsorber geometry + constrainedby + SorpLib.Components.HeatTransfer.Records.GeometryClosedAdsorber + "Geometry of the closed adsorber" + annotation(Dialog(tab = "General", group = "Heat Transfer", enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + January 22, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the product of +heat transfer coefficient and area <i>alphaA</i> describing the heat transfer +between the sorbent and heat exchanger tubes. It defines fundamental parameters +and variables required by all heat transfer coefficient models. Models that inherit +properties from this partial model have to add an equation for calculating the +product of heat transfer coefficient and area. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Product of heat transfer coefficient and area <i>alphaA</i>. + </li> +</ul> +</html>")); +end PartialClosedAdsorberHeatTransferCoefficient; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/PartialConductiveHeatTransferCoefficient.mo b/SorpLib/Components/HeatTransfer/BaseClasses/PartialConductiveHeatTransferCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..0d3223697e741469d097cbf88743f900d009fd16 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/PartialConductiveHeatTransferCoefficient.mo @@ -0,0 +1,48 @@ +within SorpLib.Components.HeatTransfer.BaseClasses; +partial model PartialConductiveHeatTransferCoefficient + "Base model for all models calculating the product of heat transfer coefficient and area for thermal conduction" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransferCoefficient; + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the volume)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Definition of parameters + // + parameter Integer no_hydraulicParallelFlows(min=1) = 1 + "Number of hydraulically parallel flows (e.g., tubes)" + annotation(Dialog(tab = "General", group = "Heat Transfer", enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + January 15, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the product of +heat transfer coefficient and area <i>alphaA</i> describing thermal conduction. +It defines fundamental parameters and variables required by all heat transfer +coefficient models. Models that inherit properties from this partial model have +to add an equation for calculating the product of heat transfer coefficient and +area. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Product of heat transfer coefficient and area <i>alphaA</i>. + </li> +</ul> +</html>")); +end PartialConductiveHeatTransferCoefficient; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/PartialGenericHeatTransferCoefficient.mo b/SorpLib/Components/HeatTransfer/BaseClasses/PartialGenericHeatTransferCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..ec63e43a663ff5e3f6d2db62d02fe13f0d131339 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/PartialGenericHeatTransferCoefficient.mo @@ -0,0 +1,33 @@ +within SorpLib.Components.HeatTransfer.BaseClasses; +partial model PartialGenericHeatTransferCoefficient + "Base model for all feneric models calculating the product of heat transfer coefficient and area" + extends SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransferCoefficient( + final computeTransportProperties=false); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + January 12, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all generic models calculating the product +of heat transfer coefficient and area <i>alphaA</i>. It defines fundamental parameters +and variables required by all heat transfer coefficient models. Models that inherit +properties from this partial model have to add an equation for calculating the +product of heat transfer coefficient and area. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Product of heat transfer coefficient and area <i>alphaA</i>. + </li> +</ul> +</html>")); +end PartialGenericHeatTransferCoefficient; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/PartialHeatTransfer.mo b/SorpLib/Components/HeatTransfer/BaseClasses/PartialHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..6eb54933b0674e20c658f2d417fcd112890e40b7 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/PartialHeatTransfer.mo @@ -0,0 +1,231 @@ +within SorpLib.Components.HeatTransfer.BaseClasses; +partial model PartialHeatTransfer + "Base model for all heat transfer models" + + // + // Definition of parameters regarding the calculation setup + // + parameter Integer n_a(min=1) = 1 + "Number of heat ports a" + annotation (Dialog(tab="General", group="Calculation Setup"), + Evaluate=true, + HideResult=true); + parameter Integer n_b(min=1) = 1 + "Number of heat ports b" + annotation (Dialog(tab="General", group="Calculation Setup"), + Evaluate=true, + HideResult=true); + + parameter Integer exponetTemperature(min=1) = 1 + "Exponent of the temperature when calculating the heat flow rate (i.e., 1 for + convection and conduction; 4 for radiation" + annotation (Dialog(tab="General", group="Calculation Setup", enable=false), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding the heat transfer coefficient + // + parameter Boolean useAlphaAInput = false + " = true, if alphaA is given by input; otherwise, alphaA is calculated by + selected model" + annotation (Dialog(tab="General", group="Heat Transfer Coefficient")); + parameter Boolean calculateFluidProperties = false + "= true, to calculate fluid properties including transport properties" + annotation (Dialog(tab="General", group="Heat Transfer Coefficient", + enable=not useAlphaAInput), + choicesAllMatching=true, + HideResult=true, + Evaluate=true); + replaceable model HeatTransferCoefficient = + SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransferCoefficient + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransferCoefficient( + T_avg_port_a = sum(hp_a.T)/n_a, + T_avg_port_b = sum(hp_b.T)/n_b) + "Model calculating the product of the heat transfer coefficient and area" + annotation (Dialog(tab="General", group="Heat Transfer Coefficient", + enable=not useAlphaAInput), + choicesAllMatching=true, + HideResult=true, + Evaluate=true); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput alphaA_input(final unit="W/K") if + useAlphaAInput + "Input for the product of the heat transfer coefficient and area" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=270, + origin={0,50}), + iconTransformation(extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,40}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput alphaA_internal(final unit="W/K") + "Needed for connecting to conditional connector"; + + // + // Definition of ports + // +public + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in[n_a] hp_a + "Heat port a" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}), + iconTransformation(extent={{-90,-10},{-70,10}}))); + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_out[n_b] hp_b + "Heat port b" + annotation (Placement(transformation(extent={{70,-10},{90,10}}), + iconTransformation(extent={{70,-10},{90,10}}))); + + // + // Definition of models + // + HeatTransferCoefficient heatTransferCoefficient if not useAlphaAInput + "Model calculating the product of the heat transfer coefficient and area"; + + // + // Definition of variables + // + Modelica.Units.SI.TemperatureDifference DT_avg= + (sum(hp_a.T)/n_a)^exponetTemperature - (sum(hp_b.T)/n_b)^exponetTemperature + "Average driving potential (i.e., temperature difference) between ports a + and b"; + Modelica.Units.SI.HeatFlowRate Q_flow= + sum(hp_a.Q_flow) + "Total heat flow rate transferred from ports a to b"; + +equation + // + // Assertions + // + if n_a < n_b then + assert(rem(n_b, n_a) == 0, + "Number of heat ports a must be a factor of the number of heat ports b!"); + + elseif n_a > n_b then + assert(rem(n_a, n_b) == 0, + "Number of heat ports a must be a factor of the number of heat ports b!"); + + end if; + + // + // Connectors + // + connect(alphaA_internal, alphaA_input); + connect(alphaA_internal, heatTransferCoefficient.alphaA); + + // + // Calculation of heat port properties depending on the discretization + // + 0 = sum(hp_a.Q_flow) + sum(hp_b.Q_flow) + "Overall energy balance"; + + if n_a < n_b then + // + // Number of heat ports a is less than number of heat ports b: + // Connect multiple heat ports b with one heat port a! + // + for i in 1:n_a-1 loop + 0 = hp_a[i].Q_flow + + sum(hp_b[1 + (i-1) * integer(n_b/n_a):i * integer(n_b/n_a)].Q_flow) + "N-1 energy balances"; + end for; + + for i in 1:n_a loop + for j in 1:integer(n_b/n_a) loop + hp_b[j + (i-1) * integer(n_b/n_a)].Q_flow = alphaA_internal/n_b * ( + hp_b[j + (i-1) * integer(n_b/n_a)].T^exponetTemperature - + hp_a[i].T^exponetTemperature) + "Heat flow calculation depending on discretization"; + end for; + end for; + + elseif n_a > n_b then + // + // Number of heat ports a is greater than number of heat ports b: + // Connect multiple heat ports a with one heat port b! + // + for i in 1:n_b-1 loop + 0 = hp_b[i].Q_flow + + sum(hp_a[1 + (i-1) * integer(n_a/n_b):i * integer(n_a/n_b)].Q_flow) + "N-1 energy balances"; + end for; + + for i in 1:n_b loop + for j in 1:integer(n_a/n_b) loop + hp_a[j + (i-1) * integer(n_a/n_b)].Q_flow = alphaA_internal/n_a * ( + hp_a[j + (i-1) * integer(n_a/n_b)].T^exponetTemperature - + hp_b[i].T^exponetTemperature) + "Heat flow calculation depending on discretization"; + end for; + end for; + + else + // + // Number of heat ports a equals number of heat ports b: + // Connect one heat port a with one heat port b! + // + for i in 1:n_a-1 loop + 0 = hp_a[i].Q_flow + hp_b[i].Q_flow + "N-1 energy balances"; + end for; + + for i in 1:n_a loop + hp_b[i].Q_flow = alphaA_internal/n_a * (hp_b[i].T^exponetTemperature - + hp_a[i].T^exponetTemperature) + "Heat flow calculation depending on discretisation"; + end for; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all heat transfers. It defines +fundamental parameters and variables required by all heat transfers. Models +that inherit properties from this partial model have to redeclare and constrain +the model calculating the product of heat transfer coefficient and area. In +this context, records may be added that containg geometry and fluid property +data. Furtheremore, it must be specified if the model calcualtes convective/conductive +heat transfer or radiation heat transfer. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Exponent of the temperatures defining the driving temperatures <i>exponetTemperature</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 12, 2024, by Mirko Engelpracht:<br/> + Separation into a partial model and documentation. + </li> + <li> + January 13, 2021, by Mirko Engelpracht:<br/> + Major revision allowing different discretizations for both ports. + </li> + <li> + December 06, 2017, by Andrej Gibelhaus:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>"), Icon(graphics={ + Line( + points={{60,-50},{-60,-50}}, + color={0,0,0}, + arrow={Arrow.Filled,Arrow.Filled}), Rectangle( + extent={{-80,-40},{80,40}}, + lineColor={238,46,47}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={238,46,47})})); +end PartialHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/PartialHeatTransferCoefficient.mo b/SorpLib/Components/HeatTransfer/BaseClasses/PartialHeatTransferCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..98f2ac68c34e4f63b62cecd4d906f4f113be155c --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/PartialHeatTransferCoefficient.mo @@ -0,0 +1,87 @@ +within SorpLib.Components.HeatTransfer.BaseClasses; +partial model PartialHeatTransferCoefficient + "Base model for all models calculating the product of heat transfer coefficient and area" + + // + // Definition of parameters regarding the heat transfer + // + parameter Boolean computeTransportProperties = false + "= true, if fluid transport properties are required and must be calculated" + annotation (Dialog(tab = "General", group = "Heat Transfer"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_avg_port_a + "Average temperature at port a" + annotation (Dialog(tab="General",group="Inputs", enable=false), + Evaluate=true); + input Modelica.Units.SI.Temperature T_avg_port_b + "Average temperature at port b" + annotation (Dialog(tab="General",group="Inputs", enable=false), + Evaluate=true); + + // + // Definition of outputs + // + Modelica.Blocks.Interfaces.RealOutput alphaA(final unit="W/K") + "Value for alphaA for entire heat transfer resistance"; + + // + // Annotations + // + annotation (Icon(graphics={Ellipse( + extent={{100,100},{-100,-100}}, + lineColor={0,0,0}, + fillColor={238,46,47}, + fillPattern=FillPattern.Solid), Text( + extent={{-80,80},{80,-80}}, + lineColor={0,0,0}, + fillColor={238,46,47}, + fillPattern=FillPattern.Solid, + textString="kA")}), Documentation(revisions="<html> +<ul> + <li> + January 12, 2024, by Mirko Engelpracht:<br/> + Smaller revision after resctructering of the library and documentation. + </li> + <li> + January 13, 2021, by Mirko Engelpracht:<br/> + Smaller revision after resctructering of the library. + </li> + <li> + December 06, 2017, by Andrej Gibelhaus:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the product of heat +transfer coefficient and area <i>alphaA</i>. It defines fundamental parameters and +variables required by all heat transfer coefficient models. Models that inherit +properties from this partial model have to add an equation for calculating the +product of heat transfer coefficient and area. In this context, records may be added +that containg geometry and fluid property data. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Product of heat transfer coefficient and area <i>alphaA</i>. + </li> +</ul> +</html>")); +end PartialHeatTransferCoefficient; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/PartialOpenAdsorberHeatTransferCoefficient.mo b/SorpLib/Components/HeatTransfer/BaseClasses/PartialOpenAdsorberHeatTransferCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..fb079010bb909b47c3ad18a81ae749a6874eb1de --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/PartialOpenAdsorberHeatTransferCoefficient.mo @@ -0,0 +1,55 @@ +within SorpLib.Components.HeatTransfer.BaseClasses; +partial model PartialOpenAdsorberHeatTransferCoefficient + "Base model for all models calculating the product of heat transfer coefficient and area for open adsorbers" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransferCoefficient; + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the gas (mixture) volume)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Modelica.Units.SI.MassFlowRate m_hyd_xMinus + "Hydraulic mass flow rate at design inlet" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Modelica.Units.SI.MassFlowRate m_hyd_xPlus + "Hydraulic mass flow rate at design outlet" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Definition of parameters + // + replaceable parameter SorpLib.Components.HeatTransfer.Records.GeometryOpenAdsorber geometry + constrainedby SorpLib.Components.HeatTransfer.Records.GeometryOpenAdsorber + "Geometry of the open adsorber" + annotation(Dialog(tab = "General", group = "Heat Transfer", enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + January 23, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the product of +heat transfer coefficient and area <i>alphaA</i> describing the heat transfer +between the sorbent and gas phase. It defines fundamental parameters and variables +required by all heat transfer coefficient models. Models that inherit properties +from this partial model have to add an equation for calculating the product of heat +transfer coefficient and area. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Product of heat transfer coefficient and area <i>alphaA</i>. + </li> +</ul> +</html>")); +end PartialOpenAdsorberHeatTransferCoefficient; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/PartialPoolBoilingHeatTransferCoefficient.mo b/SorpLib/Components/HeatTransfer/BaseClasses/PartialPoolBoilingHeatTransferCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..93326b7b79b410da6d35292dfcfcd7d48fb6aaca --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/PartialPoolBoilingHeatTransferCoefficient.mo @@ -0,0 +1,63 @@ +within SorpLib.Components.HeatTransfer.BaseClasses; +partial model PartialPoolBoilingHeatTransferCoefficient + "Base model for all models calculating the product of heat transfer coefficient and area for pool boiling" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransferCoefficient; + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the phase saperator fluid)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Real f_relativeFillingLevel(min=0, max=1, final unit="1") + "Relative filling level of the evaporator" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Definition of parameters + // + replaceable parameter SorpLib.Components.HeatTransfer.Records.GeometryTube geometry + constrainedby SorpLib.Components.HeatTransfer.Records.GeometryTube + "Geometry of the heat exchanger tubes providing the heat flow rate for pool + boiling" + annotation(Dialog(tab = "General", group = "Heat Transfer", enable=false)); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + January 17, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the product of +heat transfer coefficient and area <i>alphaA</i> describing pool boiling. It +defines fundamental parameters and variables required by all heat transfer +coefficient models. Models that inherit properties from this partial model have +to add an equation for calculating the product of heat transfer coefficient and +area. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Product of heat transfer coefficient and area <i>alphaA</i>. + </li> +</ul> +</html>")); +end PartialPoolBoilingHeatTransferCoefficient; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/PartialPoolCondensationHeatTransferCoefficient.mo b/SorpLib/Components/HeatTransfer/BaseClasses/PartialPoolCondensationHeatTransferCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..6dbfb8ce8ad4b532ff58af3632c74aed7d21c2fa --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/PartialPoolCondensationHeatTransferCoefficient.mo @@ -0,0 +1,53 @@ +within SorpLib.Components.HeatTransfer.BaseClasses; +partial model PartialPoolCondensationHeatTransferCoefficient + "Base model for all models calculating the product of heat transfer coefficient and area for (pool) condensation" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransferCoefficient; + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the phase saperator fluid)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Real f_relativeFillingLevel(min=0, max=1, final unit="1") + "Relative filling level of the condenser" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Definition of parameters + // + replaceable parameter SorpLib.Components.HeatTransfer.Records.GeometryTube geometry + constrainedby SorpLib.Components.HeatTransfer.Records.GeometryTube + "Geometry of the heat exchanger tubes providing the heat flow rate for (pool) + condensation" + annotation(Dialog(tab = "General", group = "Heat Transfer", enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + January 18, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the product of +heat transfer coefficient and area <i>alphaA</i> describing (pool) condensation, +such as film condensation. It defines fundamental parameters and variables required +by all heat transfer coefficient models. Models that inherit properties from this +partial model have to add an equation for calculating the product of heat transfer +coefficient and area. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Product of heat transfer coefficient and area <i>alphaA</i>. + </li> +</ul> +</html>")); +end PartialPoolCondensationHeatTransferCoefficient; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/PartialRadiationHeatTransferCoefficient.mo b/SorpLib/Components/HeatTransfer/BaseClasses/PartialRadiationHeatTransferCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..7f861632914a77b212f6bf9b52fceb2533d28901 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/PartialRadiationHeatTransferCoefficient.mo @@ -0,0 +1,33 @@ +within SorpLib.Components.HeatTransfer.BaseClasses; +partial model PartialRadiationHeatTransferCoefficient + "Base model for all models calculating the product of heat transfer coefficient and area for radiation heat transfer" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransferCoefficient; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + January 16, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the product of heat +heat transfer coefficient and area <i>alphaA</i> describing radiation heat transfer. +It defines fundamental parameters and variables required by all heat transfer +coefficient models. Models that inherit properties from this partial model have +to add an equation for calculating the product of heat transfer coefficient and area. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Product of heat transfer coefficient and area <i>alphaA</i>. + </li> +</ul> +</html>")); +end PartialRadiationHeatTransferCoefficient; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/PartialTubeInsideHeatTransferCoefficient.mo b/SorpLib/Components/HeatTransfer/BaseClasses/PartialTubeInsideHeatTransferCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..9ca0a26cb56d78da20299e05f3ff7e4fabe42f0f --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/PartialTubeInsideHeatTransferCoefficient.mo @@ -0,0 +1,55 @@ +within SorpLib.Components.HeatTransfer.BaseClasses; +partial model PartialTubeInsideHeatTransferCoefficient + "Base model for all models calculating the product of heat transfer coefficient and area for the tube-inside heat transfer" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialHeatTransferCoefficient; + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the fluid volume)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Modelica.Units.SI.MassFlowRate m_hyd_xMinus + "Hydraulic mass flow rate at design inlet" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Modelica.Units.SI.MassFlowRate m_hyd_xPlus + "Hydraulic mass flow rate at design outlet" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Definition of parameters + // + replaceable parameter SorpLib.Components.HeatTransfer.Records.GeometryTube geometry + constrainedby SorpLib.Components.HeatTransfer.Records.GeometryTube + "Geometry of the (heat exchanger) tubes" + annotation(Dialog(tab = "General", group = "Heat Transfer", enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + January 19, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the product of +heat transfer coefficient and area <i>alphaA</i> describing convective heat transfer +inside tubes. It defines fundamental parameters and variables required by all heat +transfer coefficient models. Models that inherit properties from this partial model +have to add an equation for calculating the product of heat transfer coefficient +and area. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Product of heat transfer coefficient and area <i>alphaA</i>. + </li> +</ul> +</html>")); +end PartialTubeInsideHeatTransferCoefficient; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/package.mo b/SorpLib/Components/HeatTransfer/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a68199c244064197bd473d5cd6556f84c7dc1278 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Components.HeatTransfer; +package BaseClasses "Base models and functions for all heat transfers" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial heat transfer and heat transfer coefficient models, +containing fundamental definitions of parameters and variables. The content of +this package is only of interest when adding new heat transfer and heat transfer +coefficient models to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Components/HeatTransfer/BaseClasses/package.order b/SorpLib/Components/HeatTransfer/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..a671d4d8a6d3bea68052811ccdbeb69baef6b03d --- /dev/null +++ b/SorpLib/Components/HeatTransfer/BaseClasses/package.order @@ -0,0 +1,10 @@ +PartialHeatTransfer +PartialHeatTransferCoefficient +PartialGenericHeatTransferCoefficient +PartialConductiveHeatTransferCoefficient +PartialRadiationHeatTransferCoefficient +PartialPoolBoilingHeatTransferCoefficient +PartialPoolCondensationHeatTransferCoefficient +PartialTubeInsideHeatTransferCoefficient +PartialClosedAdsorberHeatTransferCoefficient +PartialOpenAdsorberHeatTransferCoefficient diff --git a/SorpLib/Components/HeatTransfer/ClosedAdsorberHeatTransfer.mo b/SorpLib/Components/HeatTransfer/ClosedAdsorberHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..047d2ec9d8f98ffd774e5e5728e53b9a6a76c643 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/ClosedAdsorberHeatTransfer.mo @@ -0,0 +1,106 @@ +within SorpLib.Components.HeatTransfer; +model ClosedAdsorberHeatTransfer + "Model calculating a heat transfer describing heat transfer between sorbent and heat exchanger within closed adsorbers" + extends BaseClasses.PartialHeatTransfer( + final exponetTemperature=1, + redeclare replaceable model HeatTransferCoefficient = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.ConstantAlpha + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialClosedAdsorberHeatTransferCoefficient( + fluidProperties=fluidProperties, + geometry=geometry)); + + // + // Definition of parameters + // + replaceable parameter SorpLib.Components.HeatTransfer.Records.GeometryClosedAdsorber geometry + constrainedby + SorpLib.Components.HeatTransfer.Records.GeometryClosedAdsorber + "Geometry of the tube" + annotation(Dialog(tab = "General", group = "Heat Transfer Coefficient", + enable=false)); + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the sorbent)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The heat transfer model is used to describe the heat transfer between the sorbent +and heat exchanger within closed adsorbers. Thus, the closed adsorber heat transfer +model represents a thermal resistance between two models. Depending on the attached +temperatures (i.e., attached potential) and the chosen transport phenomena, this +model determines the heat flow rate between the connected models. +<br/><br/> +The model has two heat ports, which sizes can be defined via a parameter. The +scalable heat ports enable the connection of various models. For example, this +enables to connect a discretized model to a lumped model, or two different +disretized models. +</p> + +<h4>Main equations</h4> +<p> +The model has steady-state energy balance: +</p> +<pre> + 0 = ∑ (hp_a.Q_flow) + ∑ (hp_b.Q_flow); +</pre> +<p> +The heat flow rate <i>Q_flow</i> is proportional to the driving temperature +difference <i>ΔT = hp_a.T - hp_b.T</i> and the production of heat transfer +coefficient and area <i>αA</i>, which can be formulated as thermal resistance +<i>R<sub>closedAdsorber</sub></i>. This product can be given as an input or calculated +using models describing heat transfer coefficient correlations. +</p> +<pre> + hp_a.Q_flow = αA * ΔT = 1 / R<sub>closedAdsorber</sub> * (hp_a.T - hp_b.T); +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> + <li> + The number of ports a and b must be an even integer multiple of each other. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The closed adsorber heat transfer is typically used to describe the heat transfer +between the sorbent and heat exchanger within closed adsorbers. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useAlphaAInput</i>: + Defines if the product of heat transfer coefficient and area is given via + an input or calculated using an approproate correlation model for the heat + transfer coefficient. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 22, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Text( + extent={{-60,20},{60,-20}}, + lineColor={0,0,0}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={238,46,47}, + textString="Q_flow = 1/R_closedAdsorber * DT")})); +end ClosedAdsorberHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/ConductionHeatTransfer.mo b/SorpLib/Components/HeatTransfer/ConductionHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..d3e98a393e132a3b3843122b315c7f6b6868b494 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/ConductionHeatTransfer.mo @@ -0,0 +1,103 @@ +within SorpLib.Components.HeatTransfer; +model ConductionHeatTransfer + "Model calculating a heat transfer describing conduction" + extends BaseClasses.PartialHeatTransfer( + final exponetTemperature=1, + redeclare replaceable model HeatTransferCoefficient = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.ConstantResistance + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient( + fluidProperties=fluidProperties, + no_hydraulicParallelFlows=no_hydraulicParallelFlows)); + + // + // Definition of parameters + // + parameter Integer no_hydraulicParallelFlows(min=1) = 1 + "Number of hydraulically parallel flows (e.g., tubes)" + annotation(Dialog(tab = "General", group = "Heat Transfer Coefficient")); + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the volume)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The heat transfer model is used to thermally connect models which can exchange +heat due to thermal conduction. Thus, the conduction heat transfer model represents +a thermal resistance betweed two models. Depending on the attached temperatures (i.e., +attached potential) and the chosen transport phenomena, this model determines the +heat flow rate between the connected models. +<br/><br/> +The model has two heat ports, which sizes can be defined via a parameter. The +scalable heat ports enable the connection of various models. For example, this +enables to connect a discretized model to a lumped model, or two different +disretized models. +</p> + +<h4>Main equations</h4> +<p> +The model has steady-state energy balance: +</p> +<pre> + 0 = ∑ (hp_a.Q_flow) + ∑ (hp_b.Q_flow); +</pre> +<p> +The heat flow rate <i>Q_flow</i> is proportional to the driving temperature +difference <i>ΔT = hp_a.T - hp_b.T</i> and the production of heat transfer +coefficient and area <i>αA</i>, which can be formulated as thermal resistance +<i>R<sub>λ</sub></i>. This product can be given as an input or calculated using +models describing heat transfer coefficient correlations. +</p> +<pre> + hp_a.Q_flow = αA * ΔT = 1 / R<sub>λ</sub> * (hp_a.T - hp_b.T); +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> + <li> + The number of ports a and b must be an even integer multiple of each other. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The conductive heat transfer is typically used to desribe the heat transfer within +solid volumes, such as tube walls, in axial and radial direction. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useAlphaAInput</i>: + Defines if the product of heat transfer coefficient and area is given via + an input or calculated using an approproate correlation model for the heat + transfer coefficient. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 15, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Text( + extent={{-60,20},{60,-20}}, + lineColor={0,0,0}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={238,46,47}, + textString="Q_flow = 1/R_lambda * DT")})); +end ConductionHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/GenericHeatTransfer.mo b/SorpLib/Components/HeatTransfer/GenericHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..6de84bd9220edcc624c70184f1d1412a7fe85fa6 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/GenericHeatTransfer.mo @@ -0,0 +1,94 @@ +within SorpLib.Components.HeatTransfer; +model GenericHeatTransfer + "Model calculating a generic heat transfer" + extends BaseClasses.PartialHeatTransfer( + final exponetTemperature=1, + redeclare replaceable model HeatTransferCoefficient = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlpha + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialGenericHeatTransferCoefficient); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The generic heat transfer model is used to thermally connect models which can +exchange heat. Thus, the generic heat transfer model represents a thermal +resistance betweed two models. Depending on the attached temperatures (i.e., +attached potential) and the chosen transport phenomena, this model determines the +heat flow rate between the connected models. +<br/><br/> +The model has two heat ports, which sizes can be defined via a parameter. The +scalable heat ports enable the connection of various models. For example, this +enables to connect a discretized model to a lumped model, or two different +disretized models. +</p> + +<h4>Main equations</h4> +<p> +The model has steady-state energy balance: +</p> +<pre> + 0 = ∑ (hp_a.Q_flow) + ∑ (hp_b.Q_flow); +</pre> +<p> +The heat flow rate <i>Q_flow</i> is proportional to the driving temperature +difference <i>ΔT = hp_a.T - hp_b.T</i> and the production of heat transfer +coefficient and area <i>αA</i>. This product can be given as an input or +calculated using models describing heat transfer coefficient correlations. +</p> +<pre> + hp_a.Q_flow = αA * ΔT = αA * (hp_a.T - hp_b.T); +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> + <li> + The number of ports a and b must be an even integer multiple of each other. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The generic heat trasnfer is typically used to desribe the heat transfer between +two components via simple models for the heat transfer coefficient. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useAlphaAInput</i>: + Defines if the product of heat transfer coefficient and area is given via + an input or calculated using an approproate correlation model for the heat + transfer coefficient. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 12, 2024, by Mirko Engelpracht:<br/> + Separation into a partial model and documentation. + </li> + <li> + January 13, 2021, by Mirko Engelpracht:<br/> + Major revision allowing different discretizations for both ports. + </li> + <li> + December 06, 2017, by Andrej Gibelhaus:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>"), Icon(graphics={Text( + extent={{-60,20},{60,-20}}, + lineColor={0,0,0}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={238,46,47}, + textString="Q_flow = kA * DT")})); +end GenericHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/HeatTransfer.mo b/SorpLib/Components/HeatTransfer/HeatTransfer.mo deleted file mode 100644 index e344cea471f640285649c46955084fe8b2481727..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransfer.mo +++ /dev/null @@ -1,117 +0,0 @@ -within SorpLib.Components.HeatTransfer; -model HeatTransfer - - /***************************** Connectors ***************************/ - - TIL.Connectors.HeatPort heatPortA annotation (Placement(transformation(extent= - {{-90,-10},{-70,10}}, rotation=0))); - TIL.Connectors.HeatPort heatPortB[n] annotation (Placement(transformation( - extent={{70,-10},{90,10}}, rotation=0))); - - /***************************** Heat Transfer ******************************************/ - - replaceable model HeatTransfer = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlpha - constrainedby - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - "Heat Transfer Model" annotation (choices(choice(redeclare model - HeatTransfer = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlpha), - choice(redeclare model HeatTransfer = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA)), Dialog(enable=not useAlphaAInput, group="Heat transfer model")); - - HeatTransfer heatTransfer "Heat Transfer" annotation (Placement(transformation(extent={{-10,-10}, - {10,10}}, - rotation=0, - origin={0,0}))); - - Modelica.Blocks.Interfaces.RealInput alphaAInput if useAlphaAInput annotation (Placement( - transformation( - extent={{-20,-20},{20,20}}, - rotation=-90, - origin={0,45}), iconTransformation( - extent={{-10,-10},{10,10}}, - rotation=-90, - origin={0,36}))); - - final parameter Boolean computeTransportProperties=heatTransfer.computeTransportProperties; - -protected - Modelica.Blocks.Interfaces.RealInput alphaA_=heatTransfer.alphaA if not useAlphaAInput - annotation (Placement(transformation( - extent={{-20,-20},{20,20}}, - rotation=-90, - origin={40,45}), iconTransformation( - extent={{-20,-20},{20,20}}, - rotation=-90, - origin={0,28}))); - Modelica.Blocks.Interfaces.RealOutput getAlphaA annotation (Placement( - transformation( - extent={{-10,-10},{10,10}}, - rotation=-90, - origin={20,10}))); - - /********************* Parameters ************************************/ -public - parameter Integer n(min=1) = 1 "Number of heat ports B"; - parameter Boolean useAlphaAInput = false "If true, use alphaA input" annotation (Evaluate=true); - -equation - - //Energy balance - heatPortA.Q_flow + sum(heatPortB.Q_flow) = 0.0; - for i in 1:n loop - heatPortB[i].Q_flow = getAlphaA/n*(heatPortB[i].T - heatPortA.T); - end for; - - connect(alphaAInput, getAlphaA) annotation (Line(points={{0,45},{0,45},{0,22}, - {20,22},{20,18},{20,10}}, color={0,0,127})); - connect(getAlphaA, getAlphaA) - annotation (Line(points={{20,10},{20,10}}, color={0,0,127})); - connect(alphaA_, getAlphaA) annotation (Line(points={{40,45},{40,45},{40,22},{ - 20,22},{20,10}}, color={0,0,127})); - annotation (Icon(coordinateSystem(extent={{-80,-40},{80,40}}, - preserveAspectRatio=true), graphics={Rectangle( - extent={{-80,34},{80,-34}}, - lineColor={255,0,0}, - lineThickness=0.5), Text( - extent={{-42,22},{42,-30}}, - lineColor={0,0,0}, - lineThickness=0.5, - textStyle={TextStyle.Italic}, - textString="alpha A")}), - Diagram(coordinateSystem(extent={{-80,-40},{80,40}}, - preserveAspectRatio=true)), - Documentation(info="<html> - <p> - The heat transfer model is used to thermally connect models which can exchange heat. - The heat transfer model represents a thermal resistance betweed two models. - Depending on the attached temperatures (attached potential) and the chosen transport phenomena, the heat transfer model determines the heat flow rate between the connected models. - The heat transfer model itself does not have a thermal capacity.<br> - - The model has two heat ports, whereby one heat port (B) is scalable. - The number of heat ports B is automatically adapted depending on connected models. - The scalable heat port B enables the connection of various models to a single heat source or sink. - For example, this enables to connect a discretized model to a lumped model. - If two discretized models are connected, the heat transfer model itself can be disctretized in 1-1 configuration. - </p> - <h4>Main equations</h4> - <p> - The heat transfer model is modelled as thermal resistance with no thermal capacity. - Thus, the energy balance reads: - <p align=\"center\"><i>Q</i><sub>in</sub> = <i>Q</i><sub>out</sub> </p> - where <i>Q</i> ist the heat flow. - The heat flow is proportional to the attached temperature difference (potential) according to the following equation: - <p align=\"center\"><i>Q</i><sub>in</sub> = <i><code>α</code> A</i> (<i>T</i><sub>in</sub> - <i>T</i><sub>out</sub>) </p> - where <i><code>α</code> A</i> is the heat transfer coefficient multiplied with the heat transfer area, calculated in the internal heat transfer model, and <i>T</i> is the temperature. - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 06, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end HeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/ConstantAlpha.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/ConstantAlpha.mo new file mode 100644 index 0000000000000000000000000000000000000000..b7fcb1d5de41cbfb4250d66a65bbffa1b7bed08f --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/ConstantAlpha.mo @@ -0,0 +1,63 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber; +model ConstantAlpha + "Generic heat transfer correlation with constant heat transfer coefficient" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialClosedAdsorberHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.CoefficientOfHeatTransfer constantAlpha = 1000 + "Constant heat transfer coefficient" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Area A = geometry.A_heatTransferOuter_hx + "Constant heat transfer area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = geometry.no_hydraulicParallelTubes * constantAlpha * A / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>. +The product is enlarged by the number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> +to account for parallel flows modeled by just one flow: +</p> +<pre> + αA = no<sub>parallel flows</sub> * α * A / <strong>min</strong>(no<sub>sorbent volumes</sub>, no<sub>wall volumes</sub>) = const.; +</pre> +<p> +Note that the area <i>A</i> is calculated from the geometry record taking into +account the disretization: The smaller number of discretization volumes used for +the wall and the sorbent determines the number of heat transfer models that are used. +Accordingly, the total heat transfer surface is divided by the smaller number. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 22, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ConstantAlpha; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/ConstantAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/ConstantAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..07891ff03f0640c746feb36e96d99a1eeb601f1c --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/ConstantAlphaA.mo @@ -0,0 +1,59 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber; +model ConstantAlphaA + "Generic heat transfer correlation with constant product of heat transfer coefficient and area" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialClosedAdsorberHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + // + // Definition of parameters + // + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 1000 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = geometry.no_hydraulicParallelTubes * constantAlphaA / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>: +</p> +<pre> + αA = no<sub>parallel flows</sub> / <strong>min</strong>(no<sub>sorben volumes</sub>, no<sub>wall volumes</sub>) * const.; +</pre> +<p> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. Furhtermore, the product is diveded by the smaller discretization number +of sorbent or wall volumes to account for discretization: The smaller discretization +number determines the number of heat transfer models that are used. Thus, the product +<i>αA</i> is valid for one heat exchanger tube. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 22, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ConstantAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/ExponentialAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/ExponentialAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..fd98bc8f36a02d80ef313a728c73febe38fb51ff --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/ExponentialAlphaA.mo @@ -0,0 +1,114 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber; +model ExponentialAlphaA + "Generic heat transfer correlation with product of heat transfer coefficient and area exponentially dependent on the temperature" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialClosedAdsorberHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter SorpLib.Choices.TemperatureHeatTranferCorrelation calculationTemperature= + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA + "Defines the temperature used to calculate the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 25 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.ThermalConductance b = 0.1 + "Temperature dependancy (i.e., factor) of the exponential part" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real c(final unit="1/K") = 1/273.15 + "Temperature dependancy (i.e., exponential factor) of the exponential part" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + // + // Calculation of the product of heat transfer coefficient and area + // + if calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA then + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * exp(c * abs(T_avg_port_a))) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature at ports a"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortB then + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * exp(c * abs(T_avg_port_b))) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature at ports b"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.Average then + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * exp(c * abs((T_avg_port_a + T_avg_port_b) / 2))) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature at ports a and b"; + + else + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * exp(c * abs(T_avg_port_a - T_avg_port_b))) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature difference between ports a and b"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming it to be exponentially dependent on the temperature. The temperature +used for the calculation can be selected. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant part <i>αA<sub>const</sub></i> and a part that is exponential +dependent on the temperature <i>T</i>: +</p> +<pre> + αA = no<sub>parallel flows</sub> * [αA<sub>const</sub> + b * <strong>exp</strong>(c * <strong>abs</strong>(T))] / <strong>min</strong>(no<sub>sorben volumes</sub>, no<sub>wall volumes</sub>); +</pre> +<p> +Herein, <i>αA<sub>const</sub></i> and <i>b</i> are fitting parameters. +<br/><br/> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. Furhtermore, the product is diveded by the smaller discretization number +of sorbent or wall volumes to account for discretization: The smaller discretization +number determines the number of heat transfer models that are used. Thus, the product +<i>αA</i> is valid for one heat exchanger tube. +</p> + + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationTemperature</i>: + Defines the temperature that is used for calculations. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 22, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end ExponentialAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/LinearAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/LinearAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..c87acd8042725a3378fedae7b7a75aeb654e25e3 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/LinearAlphaA.mo @@ -0,0 +1,111 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber; +model LinearAlphaA + "Generic heat transfer correlation with product of heat transfer coefficient and area linearly dependent on the temperature" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialClosedAdsorberHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter SorpLib.Choices.TemperatureHeatTranferCorrelation calculationTemperature= + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA + "Defines the temperature used to calculate the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 25 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real b(final unit="W/(K2)") = 0.1 + "Temperature dependancy (i.e., linear factor) of the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + // + // Calculation of the product of heat transfer coefficient and area + // + if calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA then + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * abs(T_avg_port_a)) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature at ports a"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortB then + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * abs(T_avg_port_b)) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature at ports b"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.Average then + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * abs((T_avg_port_a + T_avg_port_b) / 2)) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature at ports a and b"; + + else + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * abs(T_avg_port_a - T_avg_port_b)) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature difference between ports a and b"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming it to be linearly dependent on the temperature. The temperature used +for the calculation can be selected. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant part <i>αA<sub>const</sub></i> and a part that is linear +dependent on the temperature <i>T</i>: +</p> +<pre> + αA = no<sub>parallel flows</sub> * [αA<sub>const</sub> + b * <strong>abs</strong>(T)]/ <strong>min</strong>(no<sub>sorben volumes</sub>, no<sub>wall volumes</sub>); +</pre> +<p> +Herein, <i>αA<sub>const</sub></i> and <i>b</i> are fitting parameters. +<br/><br/> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. Furhtermore, the product is diveded by the smaller discretization number +of sorbent or wall volumes to account for discretization: The smaller discretization +number determines the number of heat transfer models that are used. Thus, the product +<i>αA</i> is valid for one heat exchanger tube. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationTemperature</i>: + Defines the temperature that is used for calculations. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 22, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end LinearAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/PolynomialAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/PolynomialAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..5f3a8072c2313631ea45c895533fb52a1971d01f --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/PolynomialAlphaA.mo @@ -0,0 +1,113 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber; +model PolynomialAlphaA + "Generic heat transfer correlation with product of heat transfer coefficient and area polynomially dependent on the temperature" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialClosedAdsorberHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter SorpLib.Choices.TemperatureHeatTranferCorrelation calculationTemperature= + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA + "Defines the temperature used to calculate the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 25 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.ThermalConductance b = 0.1 + "Temperature dependancy (i.e., factor) of the polynomial part" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real c(final unit="1") = 1/3 + "Temperature dependancy (i.e., exponent) of the polynomial part" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + // + // Calculation of the product of heat transfer coefficient and area + // + if calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA then + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * abs(T_avg_port_a) ^ c) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature at ports a"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortB then + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * abs(T_avg_port_b) ^ c) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature at ports b"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.Average then + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * abs((T_avg_port_a + T_avg_port_b) / 2) ^ c) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature at ports a and b"; + + else + alphaA = geometry.no_hydraulicParallelTubes * ( + constantAlphaA + b * abs(T_avg_port_a - T_avg_port_b) ^ c) / + min(geometry.no_wallVolumes, geometry.no_sorbentVolumes) + "Average temperature difference between ports a and b"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming it to be polynomially dependent on the temperature. The temperature +used for the calculation can be selected. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant part <i>αA<sub>const</sub></i> and a part that is polynomial +dependent on the temperature <i>T</i>: +</p> +<pre> + αA = no<sub>parallel flows</sub> * [αA<sub>const</sub> + b * <strong>abs</strong>(T)<sup>c</sup>] / <strong>min</strong>(no<sub>sorben volumes</sub>, no<sub>wall volumes</sub>); +</pre> +<p> +Herein, <i>αA<sub>const</sub></i> and <i>b</i> are fitting parameters. +<br/><br/> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. Furhtermore, the product is diveded by the smaller discretization number +of sorbent or wall volumes to account for discretization: The smaller discretization +number determines the number of heat transfer models that are used. Thus, the product +<i>αA</i> is valid for one heat exchanger tube. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationTemperature</i>: + Defines the temperature that is used for calculations. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 22, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PolynomialAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d9b4475b586a5ebd7424af2995e1f2039efcfd8d --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/package.mo @@ -0,0 +1,44 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations; +package ClosedAdsorber "Correlations for heat transfer coefficients describing the heat transfer within closed adsorbers" +extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains correlations for heat transfer coefficients describing +the heat transfer between sorbent and heat exchanger within closed adsorbers: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.ConstantAlpha\">ConstantAlpha</a>: + Generic heat transfer correlation with constant heat transfer coefficient. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.ConstantAlphaA\">ConstantAlphaA</a>: + Generic heat transfer correlation with constant product of heat transfer + coefficient and area. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.LinearAlphaA\">LinearAlphaA</a>: + Generic heat transfer correlation with a product of heat transfer coefficient + and area that is linearly dependent on the temperature. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.ExponentialAlphaA\">ExponentialAlphaA</a>: + Generic heat transfer correlation with a product of heat transfer coefficient + and area that is exponentially dependent on the temperature. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.PolynomialAlphaA\">PolynomialAlphaA</a>: + Generic heat transfer correlation with a product of heat transfer coefficient + and area that is polynomially dependent on the temperature. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ClosedAdsorber; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/package.order b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/package.order new file mode 100644 index 0000000000000000000000000000000000000000..4dba73a67d8852e982052b1621d5915d33f9ae8e --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/ClosedAdsorber/package.order @@ -0,0 +1,5 @@ +ConstantAlpha +ConstantAlphaA +LinearAlphaA +ExponentialAlphaA +PolynomialAlphaA diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/ConstantCylindricalWall.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/ConstantCylindricalWall.mo new file mode 100644 index 0000000000000000000000000000000000000000..2269041931b346a9d219f391c797410121bb2f15 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/ConstantCylindricalWall.mo @@ -0,0 +1,81 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction; +model ConstantCylindricalWall + "Heat transfer correlation describing thermal conduction through a cylindrical wall using constant fluid properties" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust the heat transfer coefficient correlation" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + parameter Modelica.Units.SI.ThermalConductivity lambda = 230 + "Thermal conductivity of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Length l_wall = 0.25 + "Length of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Diameter d_inner = 0.010 + "Inner diameter of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Diameter d_outer = 0.012 + "Outer diameter of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = f_correction * + no_hydraulicParallelFlows * lambda * 2 * Modelica.Constants.pi * + l_wall / Modelica.Math.log(d_outer / d_inner) + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area for thermal conduction through a cylindrical wall assuming consant fluid +properties. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant thermal resistance <i>R<sub>λ</sub></i>. It is +enlarged by the number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> +to account for parallel flows modeled by just one flow: +</p> +<pre> + αA = no<sub>parallel flows</sub> * 1 / R<sub>λ</sub> = no<sub>parallel flows</sub> * λ * 2 * π * l / <strong>ln</strong>(d<sub>outer</sub>/d<sub>inner</sub>); +</pre> +<p> +Herein, <i>λ</i> is the thermal conductivity, <i>l</i> is the wall length, +<i>d<sub>outer</sub></i> is the outer diameter of the cylinder, and <i>d<sub>inner</sub></i> +is the inner diameter of the cylinder. + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change. Then, this model can be used to describe thermal +conduction, e.g., in radial flow direction of a heat exchanger tube. +</p> + +<h4>References</h4> +<ul> + <li> + Hahne, E. (2010). E1 Steady-State Heat Conduction. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_32. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 15, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end ConstantCylindricalWall; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/ConstantPlainWall.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/ConstantPlainWall.mo new file mode 100644 index 0000000000000000000000000000000000000000..159fa6faf1a6594afbb7868e9c393942caaa22f6 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/ConstantPlainWall.mo @@ -0,0 +1,75 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction; +model ConstantPlainWall + "Heat transfer correlation describing thermal conduction through a plain wall using constant fluid properties" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust the heat transfer coefficient correlation" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + parameter Modelica.Units.SI.ThermalConductivity lambda = 230 + "Thermal conductivity of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Area A_cross = 0.1 + "Cross-sectional area of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Thickness delta_wall = 0.25 + "Thickness of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = f_correction * + no_hydraulicParallelFlows * lambda * A_cross / delta_wall + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area for thermal conduction through a plain wall assuming consant fluid properties. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant thermal resistance <i>R<sub>λ</sub></i>. It is +enlarged by the number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> +to account for parallel flows modeled by just one flow: +</p> +<pre> + αA = no<sub>parallel flows</sub> * 1 / R<sub>λ</sub> = no<sub>parallel flows</sub> * λ * A<sub>cross</sub> / δ; +</pre> +<p> +Herein, <i>λ</i> is the thermal conductivity, <i>A<sub>cross</sub></i> is the +cross sectional area of the plain wall, and <i>δ</i> is the wall thickness. + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change. Then, this model can be used to describe thermal +conduction, e.g., in axial flow direction of a heat exchanger tube. +</p> + +<h4>References</h4> +<ul> + <li> + Hahne, E. (2010). E1 Steady-State Heat Conduction. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_32. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 15, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end ConstantPlainWall; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/ConstantResistance.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/ConstantResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..a466cd5bd0f0f097093bc01a87951fa5a90791d3 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/ConstantResistance.mo @@ -0,0 +1,53 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction; +model ConstantResistance + "Constant thermal resistance describing thermal conduction" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.ThermalResistance constantR = 0.6 * 0.1 / 0.25 + "Constant thermal resistance describing thermal conduction" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = no_hydraulicParallelFlows * 1 / constantR + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area for thermal conduction assuming a constant thermal resistance. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant thermal resistance <i>R<sub>λ</sub></i>. It is +enlarged by the number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> +to account for parallel flows modeled by just one flow: +</p> +<pre> + αA = no<sub>parallel flows</sub> * 1 / R<sub>λ</sub>; +</pre> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 15, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end ConstantResistance; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/CylindricalWall.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/CylindricalWall.mo new file mode 100644 index 0000000000000000000000000000000000000000..22e26a2400671a463b736f934c2f185b08d98b00 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/CylindricalWall.mo @@ -0,0 +1,76 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction; +model CylindricalWall + "Heat transfer correlation describing thermal conduction through a cylindrical wall" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient( + final computeTransportProperties=true, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust the heat transfer coefficient correlation" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + parameter Modelica.Units.SI.Length l_wall = 0.25 + "Length of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Diameter d_inner = 0.010 + "Inner diameter of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Diameter d_outer = 0.012 + "Outer diameter of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = f_correction * + no_hydraulicParallelFlows * fluidProperties.lambda * 2 * + Modelica.Constants.pi * l_wall / Modelica.Math.log(d_outer / d_inner) + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area for thermal conduction through a cylindrical wall. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a thermal resistance <i>R<sub>λ</sub></i>. It is +enlarged by the number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> +to account for parallel flows modeled by just one flow: +</p> +<pre> + αA = no<sub>parallel flows</sub> * 1 / R<sub>λ</sub> = no<sub>parallel flows</sub> * λ * 2 * π * l / <strong>ln</strong>(d<sub>outer</sub>/d<sub>inner</sub>); +</pre> +<p> +Herein, <i>λ</i> is the thermal conductivity, <i>l</i> is the wall length, +<i>d<sub>outer</sub></i> is the outer diameter of the cylinder, and <i>d<sub>inner</sub></i> +is the inner diameter of the cylinder. + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used to describe thermal +conduction, e.g., in radial flow direction of a heat exchanger tube. +</p> + +<h4>References</h4> +<ul> + <li> + Hahne, E. (2010). E1 Steady-State Heat Conduction. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_32. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 15, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end CylindricalWall; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/PlainWall.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/PlainWall.mo new file mode 100644 index 0000000000000000000000000000000000000000..d12244f6cdc15d162bfa2a360c6b4d8cf6bf15ad --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/PlainWall.mo @@ -0,0 +1,72 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction; +model PlainWall + "Heat transfer correlation describing thermal conduction through a plain wall" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient( + final computeTransportProperties=true, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust the heat transfer coefficient correlation" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + parameter Modelica.Units.SI.Area A_cross = 0.1 + "Cross-sectional area of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Thickness delta_wall = 0.25 + "Thickness of the wall" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = f_correction * + no_hydraulicParallelFlows * fluidProperties.lambda * + A_cross / delta_wall + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area for thermal conduction through a plain wall. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a thermal resistance <i>R<sub>λ</sub></i>. It is +enlarged by the number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> +to account for parallel flows modeled by just one flow: +</p> +<pre> + αA = no<sub>parallel flows</sub> * 1 / R<sub>λ</sub> = no<sub>parallel flows</sub> * λ * A<sub>cross</sub> / δ; +</pre> +<p> +Herein, <i>λ</i> is the thermal conductivity, <i>A<sub>cross</sub></i> is the +cross sectional area of the plain wall, and <i>δ</i> is the wall thickness. + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used to describe thermal +conduction, e.g., in axial flow direction of a heat exchanger tube. +</p> + +<h4>References</h4> +<ul> + <li> + Hahne, E. (2010). E1 Steady-State Heat Conduction. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_32. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 15, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PlainWall; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..cd2cadf5b07ab1086615bfb1a25ba6deb718f25f --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/package.mo @@ -0,0 +1,40 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations; +package Conduction "Correlations for heat transfer coefficients describing thermal conduction" +extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains correlations for heat transfer coefficients describing +thermal conduction: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.ConstantResistance\">ConstantResistance</a>: + Constant thermal resistance. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.ConstantPlainWall\">ConstantPlainWall</a>: + Constant thermal conduction through plane wall. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.ConstantCylindricalWall\">ConstantCylindricalWall</a>: + Constant thermal conduction through cylindrical wall. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.PlainWall\">PlainWall</a>: + Thermal conduction through plane wall based on fluid properties. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall\">CylindricalWall</a>: + Thermal conduction through cylindrical wall based on fluid properties. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Conduction; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/package.order b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e773690a8e63ab37708049816135d090dedcc9f3 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Conduction/package.order @@ -0,0 +1,5 @@ +ConstantResistance +ConstantPlainWall +ConstantCylindricalWall +PlainWall +CylindricalWall diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/ConstantAlpha.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/ConstantAlpha.mo new file mode 100644 index 0000000000000000000000000000000000000000..fd98b12f28efc5c3400c3c8fa17a4f2b1635779c --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/ConstantAlpha.mo @@ -0,0 +1,61 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic; +model ConstantAlpha + "Generic heat transfer correlation with constant heat transfer coefficient" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialGenericHeatTransferCoefficient( + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.CoefficientOfHeatTransfer constantAlpha = 25 + "Constant heat transfer coefficient" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Area A = 1 + "Constant heat transfer area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = constantAlpha*A + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>: +</p> +<pre> + αA = α * A = const.; +</pre> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 12, 2024, by Mirko Engelpracht:<br/> + Completed documentation. + </li> + <li> + January 13, 2021, by Mirko Engelpracht:<br/> + Smaller revision after resctructering of the library. + </li> + <li> + December 06, 2017, by Andrej Gibelhaus:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end ConstantAlpha; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/ConstantAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/ConstantAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..9fec7d05db20029cd56d335cd0c1d9cf3df1a9d5 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/ConstantAlphaA.mo @@ -0,0 +1,58 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic; +model ConstantAlphaA + "Generic heat transfer correlation with constant product of heat transfer coefficient and area" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialGenericHeatTransferCoefficient( + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 25 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA =constantAlphaA + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>: +</p> +<pre> + αA = const.; +</pre> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 12, 2024, by Mirko Engelpracht:<br/> + Completed documentation. + </li> + <li> + January 13, 2021, by Mirko Engelpracht:<br/> + Smaller revision after resctructering of the library. + </li> + <li> + December 06, 2017, by Andrej Gibelhaus:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end ConstantAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/ExponentialAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/ExponentialAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..17c94cba641d22da3e3cb8f500756c1ecbda2c16 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/ExponentialAlphaA.mo @@ -0,0 +1,97 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic; +model ExponentialAlphaA + "Generic heat transfer correlation with product of heat transfer coefficient and area exponentially dependent on the temperature" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialGenericHeatTransferCoefficient( + final avoid_events=false); + + // + // Definition of parameters + // + parameter SorpLib.Choices.TemperatureHeatTranferCorrelation calculationTemperature= + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA + "Defines the temperature used to calculate the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 25 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.ThermalConductance b = 0.1 + "Temperature dependancy (i.e., factor) of the exponential part" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real c(final unit="1/K") = 1/273.15 + "Temperature dependancy (i.e., exponential factor) of the exponential part" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + // + // Calculation of the product of heat transfer coefficient and area + // + if calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA then + alphaA = constantAlphaA + b * exp(c * abs(T_avg_port_a)) + "Average temperature at ports a"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortB then + alphaA = constantAlphaA + b * exp(c * abs(T_avg_port_b)) + "Average temperature at ports b"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.Average then + alphaA = constantAlphaA + b * exp(c * abs((T_avg_port_a + T_avg_port_b) / 2)) + "Average temperature at ports a and b"; + + else + alphaA = constantAlphaA + b * exp(c * abs(T_avg_port_a - T_avg_port_b)) + "Average temperature difference between ports a and b"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming it to be exponentially dependent on the temperature. The temperature +used for the calculation can be selected. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant part <i>αA<sub>const</sub></i> and a part that is exponential +dependent on the temperature <i>T</i>: +</p> +<pre> + αA = αA<sub>const</sub> + b * <strong>exp</strong>(c * <strong>abs</strong>(T)); +</pre> +<p> +Herein, <i>αA<sub>const</sub></i>, <i>b</i>, and <i>c</i> are fitting parameters. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationTemperature</i>: + Defines the temperature that is used for calculations. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 12, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end ExponentialAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/LinearAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/LinearAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..d6f57276eec70c5043f82c794a85f8d0ac3facd6 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/LinearAlphaA.mo @@ -0,0 +1,95 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic; +model LinearAlphaA + "Generic heat transfer correlation with product of heat transfer coefficient and area linearly dependent on the temperature" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialGenericHeatTransferCoefficient( + final avoid_events=false); + + // + // Definition of parameters + // + parameter SorpLib.Choices.TemperatureHeatTranferCorrelation calculationTemperature= + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA + "Defines the temperature used to calculate the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 25 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real b(final unit="W/(K2)") = 0.1 + "Temperature dependancy (i.e., linear factor) of the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + // + // Calculation of the product of heat transfer coefficient and area + // + if calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA then + alphaA = constantAlphaA + b * abs(T_avg_port_a) + "Average temperature at ports a"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortB then + alphaA = constantAlphaA + b * abs(T_avg_port_b) + "Average temperature at ports b"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.Average then + alphaA = constantAlphaA + b * abs((T_avg_port_a + T_avg_port_b) / 2) + "Average temperature at ports a and b"; + + else + alphaA = constantAlphaA + b * abs(T_avg_port_a - T_avg_port_b) + "Average temperature difference between ports a and b"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming it to be linearly dependent on the temperature. The temperature used +for the calculation can be selected. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant part <i>αA<sub>const</sub></i> and a part that is linear +dependent on the temperature <i>T</i>: +</p> +<pre> + αA = αA<sub>const</sub> + b * <strong>abs</strong>(T); +</pre> +<p> +Herein, <i>αA<sub>const</sub></i> and <i>b</i> are fitting parameters. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationTemperature</i>: + Defines the temperature that is used for calculations. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 12, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end LinearAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/PolynomialAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/PolynomialAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..711e085971f8ec63eed5d1a97f4b42f057e4345c --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/PolynomialAlphaA.mo @@ -0,0 +1,97 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic; +model PolynomialAlphaA + "Generic heat transfer correlation with product of heat transfer coefficient and area polynomially dependent on the temperature" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialGenericHeatTransferCoefficient( + final avoid_events=false); + + // + // Definition of parameters + // + parameter SorpLib.Choices.TemperatureHeatTranferCorrelation calculationTemperature= + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA + "Defines the temperature used to calculate the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 25 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.ThermalConductance b = 0.1 + "Temperature dependancy (i.e., factor) of the polynomial part" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real c(final unit="1") = 1/3 + "Temperature dependancy (i.e., exponent) of the polynomial part" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + // + // Calculation of the product of heat transfer coefficient and area + // + if calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA then + alphaA = constantAlphaA + b * abs(T_avg_port_a) ^ c + "Average temperature at ports a"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortB then + alphaA = constantAlphaA + b * abs(T_avg_port_b) ^ c + "Average temperature at ports b"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.Average then + alphaA = constantAlphaA + b * abs((T_avg_port_a + T_avg_port_b) / 2) ^ c + "Average temperature at ports a and b"; + + else + alphaA = constantAlphaA + b * abs(T_avg_port_a - T_avg_port_b) ^ c + "Average temperature difference between ports a and b"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming it to be polynomially dependent on the temperature. The temperature +used for the calculation can be selected. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant part <i>αA<sub>const</sub></i> and a part that is polynomial +dependent on the temperature <i>T</i>: +</p> +<pre> + αA = αA<sub>const</sub> + b * <strong>abs</strong>(T)<sup>c</sup>; +</pre> +<p> +Herein, <i>αA<sub>const</sub></i>, <i>b</i>, and <i>c</i> are fitting parameters. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationTemperature</i>: + Defines the temperature that is used for calculations. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 12, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PolynomialAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..8c75d10826066396b3de400265fa909dedd1ca6e --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/package.mo @@ -0,0 +1,43 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations; +package Generic "Generic correlations for heat transfer coefficients" +extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains generic correlations for heat transfer coefficients: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlpha\">ConstantAlpha</a>: + Generic heat transfer correlation with constant heat transfer coefficient. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlphaA\">ConstantAlphaA</a>: + Generic heat transfer correlation with constant product of heat transfer + coefficient and area. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.LinearAlphaA\">LinearAlphaA</a>: + Generic heat transfer correlation with a product of heat transfer coefficient + and area that is linearly dependent on the temperature. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ExponentialAlphaA\">ExponentialAlphaA</a>: + Generic heat transfer correlation with a product of heat transfer coefficient + and area that is exponentially dependent on the temperature. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic.PolynomialAlphaA\">PolynomialAlphaA</a>: + Generic heat transfer correlation with a product of heat transfer coefficient + and area that is polynomially dependent on the temperature. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructering the library. + </li> +</ul> +</html>")); +end Generic; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/package.order b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/package.order new file mode 100644 index 0000000000000000000000000000000000000000..4dba73a67d8852e982052b1621d5915d33f9ae8e --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Generic/package.order @@ -0,0 +1,5 @@ +ConstantAlpha +ConstantAlphaA +LinearAlphaA +ExponentialAlphaA +PolynomialAlphaA diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/CasingGasKast.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/CasingGasKast.mo new file mode 100644 index 0000000000000000000000000000000000000000..fe8d80f43dd879658b6f342036595db72b6186d7 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/CasingGasKast.mo @@ -0,0 +1,213 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.OpenAdsorber; +model CasingGasKast + "Heat transfer correlation describing the heat transfer between gas and casing according to Kast" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialOpenAdsorberHeatTransferCoefficient( + final computeTransportProperties=true); + + // + // Definition of parameters + // + parameter SorpLib.Choices.MassFlowRateHeatTranferCorrelation calculationMassFlowRate= + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXMinus + "Defines the hydraulic mass flow rate used for calculations" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Real f_particle = 12 + "Particle factor (i.e., 12 for spherical particles; 6 for cylinders)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real f_length = 1.15 + "Length factor (i.e., 11.5 for spherical particles; 1.4 for broken spherical + particles; 1.75 for cylinders)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real f_correction = 1 + "Correction factor" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + // + // Definition of variables + // + Modelica.Units.SI.CoefficientOfHeatTransfer alpha + "Heat tranfer coefficient"; + + Modelica.Units.SI.Velocity v + "Hydraulic velocity"; + Modelica.Units.SI.PecletNumber Pe + "Peclet number"; + Modelica.Units.SI.ReynoldsNumber Nu + "Nusselt number"; + + + // + // Definition of protected variables + // +protected + Modelica.Units.SI.NusseltNumber Nu_length + "Nusselt number correction to account for enhanced length"; + + Modelica.Units.SI.Length l_mixture + "Mixture length of spherical particles"; + + Modelica.Units.SI.Length l_heatTransfer + "Length of the tube accounting for discretization"; + Modelica.Units.SI.Area A_heatTransfer + "Heat transfer area accounting for discretization"; + +equation + // + // Calculation of the velocity and Peclet number + // + if calculationMassFlowRate== + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXMinus then + v = abs(m_hyd_xMinus) / (fluidProperties.rho * + geometry.A_crossInner_cas * geometry.psi_particles) + "Hydraulic velocity"; + + elseif calculationMassFlowRate== + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXPlus then + v = abs(m_hyd_xPlus) / (fluidProperties.rho * + geometry.A_crossInner_cas * geometry.psi_particles) + "Hydraulic velocity"; + + else + v = (abs(m_hyd_xMinus) + abs(m_hyd_xPlus)) / 2 / (fluidProperties.rho * + geometry.A_crossInner_cas * geometry.psi_particles) + "Hydraulic velocity"; + + end if; + + Pe = v * l_mixture * fluidProperties.rho * fluidProperties.cp / + fluidProperties.lambda + "Peclet number"; + + // + // Calculation of the Nusselt numbers + // + l_mixture = f_length * geometry.d_particle + "Mixture length of spherical particles"; + + l_heatTransfer = geometry.l_cas / geometry.no_volumes + "Length of the tube accounting for discretization"; + A_heatTransfer = geometry.A_heatTransferInner_cas / geometry.no_volumes + "Length of the tube accounting for discretization"; + + Nu_length = -1.55e-6*Pe^2 + 0.04285*Pe + 24.57 + "Nusselt number correction to account for enhanced length: Own fit for + spherical particles from Kast (1988), p. 136"; + Nu = f_correction * Nu_length / (1 + f_particle * l_heatTransfer / + geometry.d_inner_cas / max(Pe, 1e-12)) + "Nusselt number"; + + // + // Calculation of the heat transfer coefficient + // + alpha = Nu * fluidProperties.lambda/l_mixture + "Heat transfer coefficient"; + alphaA = geometry.no_hydraulicParallelTubes * alpha * A_heatTransfer + "Product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This heat transfer model calculates the product of heat transfer coefficient and +area describing the heat transfer between the gas and casing in open adsorbers. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +from the Nussel number <i>Nu</i>: +</p> +<pre> + αA = no<sub>parallel flows</sub> * Nu * λ / l<sub>mixture</sub> * A<sub>heat transfer</sub> / no<sub>volumes</sub>; +</pre> +<p> +Herein, <i>λ</i> is the thermal conductivity, <i>l<sub>mixture</sub></i> +is the mixture length, and <i>A<sub>heat transfer</sub></i> is the heat transfer +area accounting for the discretization. The product is enlarged by the number of +hydrualic parallel flows <i>no<sub>parallel flows</sub></i> to account for parallel +flows modeled by just one flow. +<br/><br/> +The Nusselt number is calculated as: +</p> +<pre> + Nu = f<sub>correction</sub> * Nu<sub>length</sub> / [1 + f<sub>correction</sub> * l<sub>heat transfer</sub> / (Pe * d<sub>inner casing</sub>)]; +</pre> +<p> +with: +</p> +<pre> + Nu<sub>length</sub> = -1.55E<sup>-6</sup> * Pe<sup></sup> + 0.04285 * Pe + 24.57; + + l<sub>mixture</sub> = f<sub>particle</sub> * d<sub>particle</sub>; +</pre> +<p> +Herein, <i>f<sub>i</sub></i> are correction factors, <i>Pe</i> is the Peclet number, +<i>Nu<sub>length</sub></i> is the Nusselt number correction, <i>d<sub>inner casing</sub></i> +is the inner diameter of the casing, and <i>l<sub>heat transfer</sub></i> is the heat +transfer length accounting for the discretization: +</p> +<pre> + Pe = v * l<sub>mixture</sub> * ρ * c<sub>p</sub> / λ; + + v = <strong>abs</strong>(m<sub>flow,hyd</sub>) / (ρ * A<sub>cross,inner casing</sub> * ψ); + + l<sub>heat transfer</sub> = l<sub>cas</sub> / no<sub>volumes</sub>; +</pre> +<p> +Herein, <i>v</i> is the hydraulic flow velocity, <i>m<sub>flow,hyd</sub></i> is +the hydraulic mass flow rate, <i>l<sub>cas</sub></i> is the length of the casing, +<i>A<sub>cross,inner casing</sub></i> is the cross-sectional inner area of the +casing, <i>ψ</i> is the void fraction, <i>ρ</i> is the fluid density, +<i>c<sub>p</sub></i> is the isobaric heat capacity, and <i>λ</i> is the +thermal conductivity. +</p> + +<h4>Typical use</h4> +<p> +This heat transfer correlation model is typically used to calculate the heat transfer +between the gas and casing if accurate results are required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationMassFlowRate</i>: + Defines the hydraulic mass flow rate that is used for calculations. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Gnielinski, V. (2010). G9 Fluid-Particle Heat Transfer in Flow Through Packed Beds of Solids. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_42. + </li> + <li> + Kast, W. (1998). Adsorption aus der Gasphase: Ingenieurwissenschaftliche Grundlagen und technische Verfahren (in German). VCH Verlagsgesellschaft, Weinheim, Basel, Cambridge, New York. DOI: https://doi.org/10.1002/bbpc.19900940122. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 23, 2024, by Mirko Engelpracht:<br/> + Minor revisions after restructering of the library. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructering of the library. + </li> + <li> + December 11, 2017, by Andrej Gibelhaus:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end CasingGasKast; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/CasingSorbentKast.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/CasingSorbentKast.mo new file mode 100644 index 0000000000000000000000000000000000000000..0063184acfe0997ff64ba3eef97a483262574419 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/CasingSorbentKast.mo @@ -0,0 +1,202 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.OpenAdsorber; +model CasingSorbentKast + "Heat transfer correlation describing the heat transfer between gas and sorbent according to Kast" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialOpenAdsorberHeatTransferCoefficient( + final computeTransportProperties=true); + + // + // Definition of parameters + // + parameter SorpLib.Choices.MassFlowRateHeatTranferCorrelation calculationMassFlowRate= + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXMinus + "Defines the hydraulic mass flow rate used for calculations" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Real f_particle = 1 + 1.5 * (1 - geometry.psi_particles) + "Form factor for the particles (i.e., 1 + 1.5 * (1 - geometry.psi_particles) + for spherical particles; 1.6 for cylinders)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.NusseltNumber Nu_min = 2 + "Minimum Nusselt number (i.e., 2 for spherical particles; 0.3 for cylinders)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + parameter Real f_correctionLaminar = 1 + "Correction factor for the laminar flow regime" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real f_correctionTurbulent = 1 + "Correction factor for the tubulent flow regime" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + // + // Definition of variables + // + Modelica.Units.SI.CoefficientOfHeatTransfer alpha + "Heat tranfer coefficient"; + + Modelica.Units.SI.ReynoldsNumber Re + "Reynolds number"; + Modelica.Units.SI.PrandtlNumber Pr + "Prandtl number"; + Modelica.Units.SI.ReynoldsNumber Nu + "Nusselt number"; + + Modelica.Units.SI.NusseltNumber Nu_lamianr + "Nusselt number for laminar flow regime"; + Modelica.Units.SI.NusseltNumber Nu_turbulent + "Nusselt number for turbulent regime"; + + // + // Definition of protected variables + // +protected + Modelica.Units.SI.Area A_heatTransfer + "Heat transfer area accounting for discretization"; + +equation + // + // Calculation of the Reynolds and Prandtl number + // + if calculationMassFlowRate== + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXMinus then + Re = abs(m_hyd_xMinus) * geometry.d_particle / + (geometry.A_crossInner_cas * geometry.psi_particles * fluidProperties.eta) + "Reynolds number"; + + elseif calculationMassFlowRate== + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXPlus then + Re = abs(m_hyd_xPlus) * geometry.d_particle / + (geometry.A_crossInner_cas * geometry.psi_particles * fluidProperties.eta) + "Reynolds number"; + + else + Re = (abs(m_hyd_xMinus) + abs(m_hyd_xPlus)) / 2 * geometry.d_particle / + (geometry.A_crossInner_cas * geometry.psi_particles * fluidProperties.eta) + "Reynolds number"; + + end if; + + Pr = fluidProperties.eta * fluidProperties.cp / fluidProperties.lambda + "Prandtl number"; + + // + // Calculation of the Nusselt numbers + // + A_heatTransfer = geometry.no_particles * geometry.A_surface_particle / + geometry.no_volumes + "Length of the tube accounting for discretization"; + + Nu_lamianr = f_correctionLaminar * (0.664 * max(Re,1e-6)^0.5 * Pr^0.5) + "Nusselt number for laminar flow regime"; + Nu_turbulent = f_correctionTurbulent * (0.037 * max(Re,1e-6)^0.8 * Pr) / + (1 + 2.443 * max(Re,1e-6)^(-0.8) * (Pr^(2/3) - 1)) + "Nusselt number for turbulent regime"; + + Nu = f_particle * (Nu_min * (Nu_lamianr^2 + Nu_turbulent^2)^0.5) + "Nusselt number"; + + // + // Calculation of the heat transfer coefficient + // + alpha = Nu * fluidProperties.lambda/geometry.d_particle + "Heat transfer coefficient"; + alphaA = geometry.no_hydraulicParallelTubes * alpha * A_heatTransfer + "Product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This heat transfer model calculates the product of heat transfer coefficient and +area describing the heat transfer between gas and sorbent within open adsorbers. +The model considers both, the laminar and turbulent flow regime. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +from the Nussel number <i>Nu</i> using Nusselt correlations for different flow +regimes: +</p> +<pre> + αA = no<sub>parallel flows</sub> * Nu * λ / d<sub>particle</sub> * A<sub>particles</sub> / no<sub>volumes</sub>; +</pre> +<p> +Herein, <i>λ</i> is the thermal conductivity, <i>d<sub>particle</sub></i> +is the diameter of one particle, and <i>A<sub>particles</sub></i> is the heat +transfer area of all particles accounting for the discretization. The product is +enlarged by the number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> +to account for parallel flows modeled by just one flow. +<br/><br/> +The Nusselt number depends on the flow regime: +</p> +<pre> + Nu = f<sub>particle</sub> * [Nu<sub>min</sub> * (Nu<sup>2</sup><sub>laminar</sub> + Nu<sup>2</sup><sub>turbulent</sub>)<sup>0.5</sup>]; + + Nu<sub>laminar</sub> = f<sub>correction,laminar</sub> * [0.664 * Re<sup>0.5</sup> * Pr<sup>0.5</sup>]; + + Nu<sub>turbulent</sub> = f<sub>correction,turbulent</sub> * 0.037 * Re<sup>0.8</sup> * Pr / (1 + 2.443 * Re<sup>-0.8</sup> * (Pr<sup>2/3</sup> - 1)); +</pre> +<p> +Herein, <i>f<sub>i</sub></i> are correction factors for the Nusselt correlations +<i>Nu<sub>i</sub></i> of the different flow regimes <i>i</i>, <i>Nu<sub>min</sub> +is a minimal Nusselt number, </i><i>Re</i> is the Reynolds number, and <i>Pr</i> is +the Prandtl number: +</p> +<pre> + Re = <strong>abs</strong>(m<sub>flow,hyd</sub>) * d<sub>particle</sub> / A<sub>cross,inner casing</sub> / ψ / η; + + Pr = η * c<sub>p</sub> / λ; +</pre> +<p> +Herein, <i>m<sub>flow,hyd</sub></i> is the hydraulic mass flow rate, +<i>A<sub>cross,inner casing</sub></i> is the hydraulic cross-sectional inner area +of the casing, <i>ψ</i> is the void fraction, <i>η</i> is the dynamic +viscosity, <i>λ</i> is the thermal conductivity, and <i>c<sub>p</sub></i> +is the isobaric heat capacity. +</p> + +<h4>Typical use</h4> +<p> +This heat transfer correlation model is typically used to calculate the heat transfer +between the sorbent and casing if accurate results are required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationMassFlowRate</i>: + Defines the hydraulic mass flow rate that is used for calculations. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Gnielinski, V. (2010). G1 Heat Transfer in Pipe Flow. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_34. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 23, 2024, by Mirko Engelpracht:<br/> + Minor revisions after restructering of the library. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructering of the library. + </li> + <li> + December 11, 2017, by Andrej Gibelhaus:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end CasingSorbentKast; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/ConstantAlpha.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/ConstantAlpha.mo new file mode 100644 index 0000000000000000000000000000000000000000..92ae3906434d89c06159a574ca23259d8a841cca --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/ConstantAlpha.mo @@ -0,0 +1,62 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.OpenAdsorber; +model ConstantAlpha + "Generic heat transfer correlation with constant heat transfer coefficient" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialOpenAdsorberHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.CoefficientOfHeatTransfer constantAlpha = 1000 + "Constant heat transfer coefficient" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Area A = geometry.A_heatTransferInner_cas + "Constant heat transfer area (i.e., geometry.A_heatTransferInner_cas or + geometry.no_particles * geometry.A_surface_particle)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = geometry.no_hydraulicParallelTubes * constantAlpha * A / + geometry.no_volumes + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>. +The product is enlarged by the number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> +to account for parallel flows modeled by just one flow: +</p> +<pre> + αA = no<sub>parallel flows</sub> * α * A / no<sub>volumes</sub> = const.; +</pre> +<p> +Note that the area <i>A</i> is calculated from the geometry record taking into +account the disretization. Thus, the area <i>A</i> belongs to one adsorber column. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 23, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ConstantAlpha; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/ConstantAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/ConstantAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..d69ba2a011886b9077461b2c367cd1cff20e25ae --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/ConstantAlphaA.mo @@ -0,0 +1,57 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.OpenAdsorber; +model ConstantAlphaA + "Generic heat transfer correlation with constant product of heat transfer coefficient and area" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialOpenAdsorberHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + // + // Definition of parameters + // + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 1000 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = geometry.no_hydraulicParallelTubes * constantAlphaA / + geometry.no_volumes + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>: +</p> +<pre> + αA = no<sub>parallel flows</sub> / no<sub>volumes</sub> * const.; +</pre> +<p> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. Furhtermore, the product is diveded by the discretization number. Thus, +the product <i>αA</i> is valid for one adsorber column. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 23, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ConstantAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..1df2a033495c72f6312b2f97b7c7f6bfcf99603c --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/package.mo @@ -0,0 +1,39 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations; +package OpenAdsorber "Correlations for heat transfer coefficients describing the heat transfer within open adsorbers" +extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains correlations for heat transfer coefficients describing +the heat transfer between gas and sorbent/casing within open adsorbers: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.OpenAdsorber.ConstantAlpha\">ConstantAlpha</a>: + Generic heat transfer correlation with constant heat transfer coefficient. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.OpenAdsorber.ConstantAlphaA\">ConstantAlphaA</a>: + Generic heat transfer correlation with constant product of heat transfer + coefficient and area. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.OpenAdsorber.CasingGasKast\">CasingGasKast</a>: + Heat transfer correlation describing the heat transfer between the gas volume + and casing according to Kast. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.OpenAdsorber.CasingSorbentKast\">CasingSorbentKast</a>: + Heat transfer correlation describing the heat transfer between the gas volume + and sorbent according to Kast. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end OpenAdsorber; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/package.order b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/package.order new file mode 100644 index 0000000000000000000000000000000000000000..d57aac9d90e84154e7e7385f4f50d66de3895423 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/OpenAdsorber/package.order @@ -0,0 +1,4 @@ +ConstantAlpha +ConstantAlphaA +CasingGasKast +CasingSorbentKast diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/ConstantAlpha.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/ConstantAlpha.mo new file mode 100644 index 0000000000000000000000000000000000000000..e849a9ff9ca227dc53f234bb708d7a56ac53ddaa --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/ConstantAlpha.mo @@ -0,0 +1,54 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling; +model ConstantAlpha + "Generic heat transfer correlation with constant heat transfer coefficient" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolBoilingHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.CoefficientOfHeatTransfer constantAlpha = 10000 + "Constant heat transfer coefficient" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Area A = 1 + "Constant heat transfer area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = constantAlpha*A + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>: +</p> +<pre> + αA = α * A = const.; +</pre> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 17, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end ConstantAlpha; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/ConstantAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/ConstantAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..179ec088f24a602f23e277ea463dfb2909006a48 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/ConstantAlphaA.mo @@ -0,0 +1,51 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling; +model ConstantAlphaA + "Generic heat transfer correlation with constant product of heat transfer coefficient and area" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolBoilingHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 10000 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA =constantAlphaA + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>: +</p> +<pre> + αA = const.; +</pre> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 17, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ConstantAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/LinearAlphaA_T.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/LinearAlphaA_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..32fcff73f1c766dc12bb88abfd9aafb224da0118 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/LinearAlphaA_T.mo @@ -0,0 +1,96 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling; +model LinearAlphaA_T + "Generic heat transfer correlation with product of heat transfer coefficient and area linearly dependent on the temperature" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolBoilingHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter SorpLib.Choices.TemperatureHeatTranferCorrelation calculationTemperature= + SorpLib.Choices.TemperatureHeatTranferCorrelation.Difference + "Defines the temperature used to calculate the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 100 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real b(final unit="W/(K2)") = 5000 + "Temperature dependancy (i.e., linear factor) of the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + // + // Calculation of the product of heat transfer coefficient and area + // + if calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA then + alphaA = constantAlphaA + b * abs(T_avg_port_a) + "Average temperature at ports a"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortB then + alphaA = constantAlphaA + b * abs(T_avg_port_b) + "Average temperature at ports b"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.Average then + alphaA = constantAlphaA + b * abs((T_avg_port_a + T_avg_port_b) / 2) + "Average temperature at ports a and b"; + + else + alphaA = constantAlphaA + b * abs(T_avg_port_a - T_avg_port_b) + "Average temperature difference between ports a and b"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming it to be linearly dependent on the temperature. The temperature used +for the calculation can be selected. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant part <i>αA<sub>const</sub></i> and a part that is linear +dependent on the temperature <i>T</i>: +</p> +<pre> + αA = αA<sub>const</sub> + b * <strong>abs</strong>(T); +</pre> +<p> +Herein, <i>αA<sub>const</sub></i> and <i>b</i> are fitting parameters. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationTemperature</i>: + Defines the temperature that is used for calculations. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 17, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end LinearAlphaA_T; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/LinearAlphaA_fRel.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/LinearAlphaA_fRel.mo new file mode 100644 index 0000000000000000000000000000000000000000..026ae72ac232bb0ba2ff40ae533c25724c24e6f7 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/LinearAlphaA_fRel.mo @@ -0,0 +1,67 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling; +model LinearAlphaA_fRel + "Generic heat transfer correlation with product of heat transfer coefficient and area linearly dependent on the temperature" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolBoilingHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 10 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.ThermalConductance b = 10000 + "Temperature dependancy (i.e., linear factor) of the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = constantAlphaA + b * f_relativeFillingLevel + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming it to be linearly dependent on the relative filling level. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant part <i>αA<sub>const</sub></i> and a part that is linear +dependent on the relative filling levekl <i>f<sub>rel</sub></i>: +</p> +<pre> + αA = αA<sub>const</sub> + b * f<sub>rel</sub>; +</pre> +<p> +Herein, <i>αA<sub>const</sub></i> and <i>b</i> are fitting parameters. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationTemperature</i>: + Defines the temperature that is used for calculations. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 17, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end LinearAlphaA_fRel; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..eb28af1731d2a6d0897e6b257adac94faa421c15 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/package.mo @@ -0,0 +1,39 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations; +package PoolBoiling "Correlations for heat transfer coefficients describing pool boiling" +extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains correlations for heat transfer coefficients describing +pool boiling: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling.ConstantAlpha\">ConstantAlpha</a>: + Generic heat transfer correlation with constant heat transfer coefficient. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling.ConstantAlphaA\">ConstantAlphaA</a>: + Generic heat transfer correlation with constant product of heat transfer + coefficient and area. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling.LinearAlphaA_T\">LinearAlphaA_T</a>: + Generic heat transfer correlation with a product of heat transfer coefficient + and area that is linearly dependent on the temperature. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling.LinearAlphaA_fRel\">LinearAlphaA_fRel</a>: + Generic heat transfer correlation with a product of heat transfer coefficient + and area that is linearly dependent on the relative filling level. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PoolBoiling; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/package.order b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/package.order new file mode 100644 index 0000000000000000000000000000000000000000..fab30c1e27963f608d22343b3dfe87910bf594a5 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolBoiling/package.order @@ -0,0 +1,4 @@ +ConstantAlpha +ConstantAlphaA +LinearAlphaA_T +LinearAlphaA_fRel diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/ConstantAlpha.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/ConstantAlpha.mo new file mode 100644 index 0000000000000000000000000000000000000000..6fefccfa6854d4e28cba23db40abc8203b95ac37 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/ConstantAlpha.mo @@ -0,0 +1,54 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation; +model ConstantAlpha + "Generic heat transfer correlation with constant heat transfer coefficient" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolCondensationHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.CoefficientOfHeatTransfer constantAlpha = 15000 + "Constant heat transfer coefficient" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Area A = 1 + "Constant heat transfer area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = constantAlpha*A + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>: +</p> +<pre> + αA = α * A = const.; +</pre> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 18, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end ConstantAlpha; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/ConstantAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/ConstantAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..661b6227eda81e883fff26ab111cde91c2daeb4a --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/ConstantAlphaA.mo @@ -0,0 +1,51 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation; +model ConstantAlphaA + "Generic heat transfer correlation with constant product of heat transfer coefficient and area" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolCondensationHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 10000 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA =constantAlphaA + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>: +</p> +<pre> + αA = const.; +</pre> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 18, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ConstantAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/LinearAlphaA_T.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/LinearAlphaA_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..89d757e66490c0aa89ae753cd119c664f4866029 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/LinearAlphaA_T.mo @@ -0,0 +1,96 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation; +model LinearAlphaA_T + "Generic heat transfer correlation with product of heat transfer coefficient and area linearly dependent on the temperature" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolCondensationHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter SorpLib.Choices.TemperatureHeatTranferCorrelation calculationTemperature= + SorpLib.Choices.TemperatureHeatTranferCorrelation.Difference + "Defines the temperature used to calculate the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 100 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real b(final unit="W/(K2)") = 5000 + "Temperature dependancy (i.e., linear factor) of the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + // + // Calculation of the product of heat transfer coefficient and area + // + if calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortA then + alphaA = constantAlphaA + b * abs(T_avg_port_a) + "Average temperature at ports a"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.PortB then + alphaA = constantAlphaA + b * abs(T_avg_port_b) + "Average temperature at ports b"; + + elseif calculationTemperature == + SorpLib.Choices.TemperatureHeatTranferCorrelation.Average then + alphaA = constantAlphaA + b * abs((T_avg_port_a + T_avg_port_b) / 2) + "Average temperature at ports a and b"; + + else + alphaA = constantAlphaA + b * abs(T_avg_port_a - T_avg_port_b) + "Average temperature difference between ports a and b"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming it to be linearly dependent on the temperature. The temperature used +for the calculation can be selected. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant part <i>αA<sub>const</sub></i> and a part that is linear +dependent on the temperature <i>T</i>: +</p> +<pre> + αA = αA<sub>const</sub> + b * <strong>abs</strong>(T); +</pre> +<p> +Herein, <i>αA<sub>const</sub></i> and <i>b</i> are fitting parameters. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationTemperature</i>: + Defines the temperature that is used for calculations. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 18, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end LinearAlphaA_T; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/LinearAlphaA_fRel.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/LinearAlphaA_fRel.mo new file mode 100644 index 0000000000000000000000000000000000000000..220681c0719069921f164f6f6a2c9a485e90b1a6 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/LinearAlphaA_fRel.mo @@ -0,0 +1,67 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation; +model LinearAlphaA_fRel + "Generic heat transfer correlation with product of heat transfer coefficient and area linearly dependent on the temperature" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolCondensationHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 15000 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.ThermalConductance b = -15000 + "Temperature dependancy (i.e., linear factor) of the product of heat transfer + coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = constantAlphaA + b * f_relativeFillingLevel + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming it to be linearly dependent on the relative filling level. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant part <i>αA<sub>const</sub></i> and a part that is linear +dependent on the relative filling level <i>f<sub>rel</sub></i>: +</p> +<pre> + αA = αA<sub>const</sub> + b * f<sub>rel</sub>; +</pre> +<p> +Herein, <i>αA<sub>const</sub></i> and <i>b</i> are fitting parameters. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationTemperature</i>: + Defines the temperature that is used for calculations. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 18, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end LinearAlphaA_fRel; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..1a7d1be93bc1bb0cf1202c783905de2cec0961f1 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/package.mo @@ -0,0 +1,39 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations; +package PoolCondensation "Correlations for heat transfer coefficients describing (pool) condensation" +extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains correlations for heat transfer coefficients describing +(pool) condensation: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation.ConstantAlpha\">ConstantAlpha</a>: + Generic heat transfer correlation with constant heat transfer coefficient. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation.ConstantAlphaA\">ConstantAlphaA</a>: + Generic heat transfer correlation with constant product of heat transfer + coefficient and area. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation.LinearAlphaA_T\">LinearAlphaA_T</a>: + Generic heat transfer correlation with a product of heat transfer coefficient + and area that is linearly dependent on the temperature. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation.LinearAlphaA_fRel\">LinearAlphaA_fRel</a>: + Generic heat transfer correlation with a product of heat transfer coefficient + and area that is linearly dependent on the relative filling level. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PoolCondensation; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/package.order b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/package.order new file mode 100644 index 0000000000000000000000000000000000000000..fab30c1e27963f608d22343b3dfe87910bf594a5 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/PoolCondensation/package.order @@ -0,0 +1,4 @@ +ConstantAlpha +ConstantAlphaA +LinearAlphaA_T +LinearAlphaA_fRel diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/ConstantResistance.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/ConstantResistance.mo new file mode 100644 index 0000000000000000000000000000000000000000..e6c63b8eb44ae9c98d6d56ab94c81a677b357d7c --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/ConstantResistance.mo @@ -0,0 +1,51 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Radiation; +model ConstantResistance + "Constant thermal resistance describing thermal radiation" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialRadiationHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real constantR(final unit="W/K4") = 1 / Modelica.Constants.sigma / 0.1 + "Constant thermal resistance describing thermal radiation" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = 1 / (1 * constantR) + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area for thermal conduction assuming a constant thermal resistance. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant thermal resistance <i>R<sub>σ</sub></i>: +</p> +<pre> + αA = 1 / R<sub>σ</sub>; +</pre> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 16, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end ConstantResistance; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/GrayCylinderInGrayCylinder.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/GrayCylinderInGrayCylinder.mo new file mode 100644 index 0000000000000000000000000000000000000000..a222b1e71a554e1464fb2f63c09cb543859c6f1f --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/GrayCylinderInGrayCylinder.mo @@ -0,0 +1,78 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Radiation; +model GrayCylinderInGrayCylinder + "Heat transfer correlation describing thermal radiation between a gray cylinder within a bigger gray cylinder" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialRadiationHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust the heat transfer coefficient correlation" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + parameter Real epsilon_1(min=0, max=1) = 0.15 + "Emissivity of suraface 1 (i.e., inner cylinder)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real epsilon_2(min=0, max=1) = 0.15 + "Emissivity of suraface 2 (i.e., outer cylinder)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Area A_1 = 0.1 + "Surface 1 (i.e., inner cylinder)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Area A_2 = 0.2 + "Surface 2 (i.e., outer cylinder)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = f_correction * 1 * Modelica.Constants.sigma / + (1/epsilon_1 + A_1/A_2 * (1/epsilon_2 - 1)) + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area for thermal radiation between a gray cylinder within a bigger gray cylinder. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant thermal resistance <i>R<sub>σ</sub></i>: +</p> +<pre> + αA = 1 / R<sub>σ</sub> = σ / (1/ε<sub>1</sub> + A<sub>1</sub>/A<sub>2</sub>) * (1/ε<sub>2</sub> - 1)); +</pre> +<p> +Herein, <i>σ</i> is the Stefan-Blotzmann constant, <i>A<sub>1</sub></i> is +the area of the inner cylinder, <i>A<sub>2</sub></i> is the area of the outer +cylinder, <i>ε<sub>1</sub></i> emission constant of surface 1, and +<i>ε<sub>2</sub></i> emission constant of surface 2. + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change. Then, this model can be used to describe thermal +radiation between a gray cylinder within a bigger gray cylinder. +</p> + +<h4>References</h4> +<ul> + <li> + Kabelac, S. and Vortmeyer, D. (2010). K1 Radiation of Surfaces. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_64. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 16, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end GrayCylinderInGrayCylinder; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/ParallelGraySurfaces.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/ParallelGraySurfaces.mo new file mode 100644 index 0000000000000000000000000000000000000000..52729d30198ad5824476936f3668ee622c292a08 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/ParallelGraySurfaces.mo @@ -0,0 +1,75 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Radiation; +model ParallelGraySurfaces + "Heat transfer correlation describing thermal radation between two parallel, gray surfaces" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialRadiationHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real f_correction = 1 + "Correction factor to adjust the heat transfer coefficient correlation" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + parameter Real epsilon_1(min=0, max=1) = 0.15 + "Emissivity of suraface 1" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real epsilon_2(min=0, max=1) = 0.15 + "Emissivity of suraface 2" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Area A_surfaces = 0.1 + "Identical area of the surfaces exchanging heat" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = f_correction * 1 * Modelica.Constants.sigma * A_surfaces / + (1/epsilon_1 + 1/epsilon_2 - 1) + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area for thermal radiation between two parallel, gray surfaces that have an equal +area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant thermal resistance <i>R<sub>σ</sub></i>: +</p> +<pre> + αA = 1 / R<sub>σ</sub> = σ * A / (1/ε<sub>1</sub> + 1/ε<sub>2</sub> - 1); +</pre> +<p> +Herein, <i>σ</i> is the Stefan-Blotzmann constant, <i>A</i> is the area of the +surfaces that exhange heat, <i>ε<sub>1</sub></i> emission constant of surface +1, and <i>ε<sub>2</sub></i> emission constant of surface 2. + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change. Then, this model can be used to describe thermal +radiation between two parallel, gray surfaces. +</p> + +<h4>References</h4> +<ul> + <li> + Kabelac, S. and Vortmeyer, D. (2010). K1 Radiation of Surfaces. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_64. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 16, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end ParallelGraySurfaces; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..82ed765018b22db0189e4830ab64f09360f89b8e --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/package.mo @@ -0,0 +1,32 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations; +package Radiation "Correlations for heat transfer coefficients describing thermal radiation" +extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains correlations for heat transfer coefficients describing +thermal radiation: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Radiation.ConstantResistance\">ConstantResistance</a>: + Constant thermal resistance. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Radiation.ParallelGraySurfaces\">ParallelGraySurfaces</a>: + Constant thermal radiation between two parallel, gray surfaces. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Radiation.GrayCylinderInGrayCylinder\">GrayCylinderInGrayCylinder</a>: + Constant thermal radiation between a gray cylinder within a bigger, gray cylinder. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Radiation; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/package.order b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/package.order new file mode 100644 index 0000000000000000000000000000000000000000..cc67718671e6709abae54cf147810b3641613c8f --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/Radiation/package.order @@ -0,0 +1,3 @@ +ConstantResistance +ParallelGraySurfaces +GrayCylinderInGrayCylinder diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/ConstantAlpha.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/ConstantAlpha.mo new file mode 100644 index 0000000000000000000000000000000000000000..606975e044982d48c7c7a8cf1e5feec57595989c --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/ConstantAlpha.mo @@ -0,0 +1,63 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside; +model ConstantAlpha + "Generic heat transfer correlation with constant heat transfer coefficient" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialTubeInsideHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.CoefficientOfHeatTransfer constantAlpha = 30000 + "Constant heat transfer coefficient" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Area A = geometry.A_heatTransferInner + "Constant heat transfer area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = geometry.no_hydraulicParallelTubes * constantAlpha * A / + min(geometry.no_fluidVolumes, geometry.no_wallVolumes) + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>. +The product is enlarged by the number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> +to account for parallel flows modeled by just one flow: +</p> +<pre> + αA = no<sub>parallel flows</sub> * α * A / <strong>min</strong>(no<sub>fluid volumes</sub>, no<sub>wall volumes</sub>) = const.; +</pre> +<p> +Note that the area <i>A</i> is calculated from the geometry record taking into +account the disretization: The smaller number of discretization volumes used for +the fluid and the wall determines the number of heat transfer models that are used. +Accordingly, the total heat transfer surface is divided by the smaller number. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 19, 2024, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end ConstantAlpha; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/ConstantAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/ConstantAlphaA.mo new file mode 100644 index 0000000000000000000000000000000000000000..6bdffa257359fa7a79d74f8fd6e66b3aaa841d24 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/ConstantAlphaA.mo @@ -0,0 +1,60 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside; +model ConstantAlphaA + "Generic heat transfer correlation with constant product of heat transfer coefficient and area" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialTubeInsideHeatTransferCoefficient( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.ThermalConductance constantAlphaA = 30000 + "Constant product of heat transfer coefficient and area" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + +equation + alphaA = geometry.no_hydraulicParallelTubes * constantAlphaA / + min(geometry.no_fluidVolumes, geometry.no_wallVolumes) + "Calculation of the product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of heat transfer coefficient and +area assuming a constant heat transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +assuming a constant heat transfer coefficient <i>α</i> and area <i>A</i>: +</p> +<pre> + αA = no<sub>parallel flows</sub> / <strong>min</strong>(no<sub>fluid volumes</sub>, no<sub>wall volumes</sub>) * const.; +</pre> +<p> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. Furhtermore, the product is diveded by the smaller discretization number +of fluid or wall volumes to account for discretization: The smaller discretization +number determines the number of heat transfer models that are used. Thus, the product +<i>αA</i> is valid for one heat exchanger tube. +</p> + +<h4>Typical use</h4> +<p> +This simple heat transfer correlation model is typically used if the heat transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 19, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ConstantAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/GnielinskiDittusBoelter.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/GnielinskiDittusBoelter.mo new file mode 100644 index 0000000000000000000000000000000000000000..d6fac1f3ae27ff5a536b7538ef9e6256699f27ec --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/GnielinskiDittusBoelter.mo @@ -0,0 +1,415 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside; +model GnielinskiDittusBoelter + "Heat transfer correlation according to Gnielinski, Dittus, and Boelter for straight tubes" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialTubeInsideHeatTransferCoefficient( + final computeTransportProperties=true); + + // + // Definition of parameters + // + parameter SorpLib.Choices.MassFlowRateHeatTranferCorrelation calculationMassFlowRate= + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXMinus + "Defines the hydraulic mass flow rate used for calculations" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Real f_correctionNoFlow = 1 + "Correction factor to adjust the Nusselt-correlation for the no-flow regime" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real f_correctionLaminar = 1 + "Correction factor to adjust the Nusselt-correlation for the laminar regime" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real f_correctionGnielinski = 1 + "Correction factor to adjust the Nusselt-correlation for the turbulent regime + described by the correlation of Gnielinski" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real f_correctionDittusBoelter = 1.7 + "Correction factor to adjust the Nusselt-correlation for the turbulent regime + described by the correlation of Dittus and Boelter" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + parameter Modelica.Units.SI.ReynoldsNumber Re_critNoFlow = 10 + "Critical Reynolds number for the no-flow regime" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.ReynoldsNumber Re_critLaminar = 2300 + "Critical Reynolds number for the laminar regime" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.ReynoldsNumber Re_critGnielinski = 1e4 + "Critical Reynolds number for the turbulent regime described by the + correlation of Gnielinski" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.ReynoldsNumber Re_critDittusBoelter = 1e6 + "Critical Reynolds number for the turbulent regime described by the + correlation of Dittus and Boelter" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true, + HideResult=true); + + parameter Integer noDiff = 2 + "Specification how often transition functions can be differentiated" + annotation(Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.ReynoldsNumber Re_transitionNoFlow = 1 + "Transition length for the no-flow regime" + annotation(Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.ReynoldsNumber Re_transitionLaminar = 10 + "Transition length for the laminar regime" + annotation(Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.ReynoldsNumber Re_transitionTurbulent = 100 + "Transition length for the turbulent regime" + annotation(Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.CoefficientOfHeatTransfer alpha + "Heat tranfer coefficient"; + + Modelica.Units.SI.ReynoldsNumber Re + "Reynolds number"; + Modelica.Units.SI.PrandtlNumber Pr + "Prandtl number"; + Modelica.Units.SI.ReynoldsNumber Nu + "Nusselt number"; + + Modelica.Units.SI.NusseltNumber Nu_noFlow + "Nusselt number for no-flow regime"; + Modelica.Units.SI.NusseltNumber Nu_lamianr + "Nusselt number for laminar flow regime"; + Modelica.Units.SI.NusseltNumber Nu_transition + "Nusselt number for transition regime"; + Modelica.Units.SI.NusseltNumber Nu_Gnielinski + "Nusselt number for turbulent flow regime according to Gnielinski"; + Modelica.Units.SI.NusseltNumber Nu_DittusBoelter + "Nusselt number for turbulent flow regime according to Dittus and Boelter"; + + // + // Definition of protected variables + // +protected + Modelica.Units.SI.NusseltNumber Nu_lamianrFlow_transition + "Nusselt number for laminar flow at the transition point"; + Modelica.Units.SI.NusseltNumber Nu_Gnielinski_transition + "Nusselt number for turbulent flow according to Gnielinski at the + transition point"; + + Modelica.Units.SI.NusseltNumber Nu_aux1 + "Nusselt number according to transition between no-flow and laminar flow + regime"; + Modelica.Units.SI.NusseltNumber Nu_aux2 + "Nusselt number according to transition between laminar flow regime and + transition regime"; + Modelica.Units.SI.NusseltNumber Nu_aux3 + "Nusselt number according to transition between transition regime and + turbulent regime according to Gnielinski"; + + Modelica.Units.SI.Length l_heatTransfer + "Length of the tube accounting for discretization"; + Modelica.Units.SI.Area A_heatTransfer + "Heat transfer area accounting for discretization"; + + Real zeta + "Auxillary variable for Gnielinski's Nusselt correlation"; + Real zeta_transition + "Auxillary variable for Gnielinski's Nusselt correlation at the transition + point"; + + Real wf_noFlowLaminar + "Transition factor to change between no-flow and laminar flow regime"; + Real wf_laminarTransition + "Transition factor for change between laminar and transition regime"; + Real gamma + "Transition fractor transition regime"; + Real wf_transitionGnielinski + "Transition factor for change between first transition regime and turbulent + regime according to Gnielinski"; + Real wf_GnielinskiDittusBoelter + "Transition factor for change between turbulent regime according to Gnielinski + and turbulent regime according to Dittus and Boelter"; + +equation + // + // Calculation of transition functions + // + gamma = (Re - Re_critLaminar) / (Re_critGnielinski - Re_critLaminar) + "Transition fractor transition regime"; + + if avoid_events then + wf_noFlowLaminar = SorpLib.Numerics.smoothTransition_noEvent( + x=Re, + transitionPoint=Re_critNoFlow, + transitionLength=Re_transitionNoFlow, + noDiff=noDiff) + "Transition factor to change between no-flow and laminar flow regime"; + wf_laminarTransition = SorpLib.Numerics.smoothTransition_noEvent( + x=Re, + transitionPoint=Re_critLaminar, + transitionLength=Re_transitionLaminar, + noDiff=noDiff) + "Transition factor for change between laminar and transition regime"; + wf_transitionGnielinski = SorpLib.Numerics.smoothTransition_noEvent( + x=Re, + transitionPoint=Re_critGnielinski, + transitionLength=Re_transitionTurbulent, + noDiff=noDiff) + "Transition factor for change between first transition regime and turbulent + regime according to Gnielinski"; + wf_GnielinskiDittusBoelter = SorpLib.Numerics.smoothTransition_noEvent( + x=Re, + transitionPoint=Re_critDittusBoelter, + transitionLength=Re_transitionTurbulent, + noDiff=noDiff) + "Transition factor for change between turbulent regime according to Gnielinski + and turbulent regime according to Dittus and Boelter"; + + else + wf_noFlowLaminar = SorpLib.Numerics.smoothTransition( + x=Re, + transitionPoint=Re_critNoFlow, + transitionLength=Re_transitionNoFlow, + noDiff=noDiff) + "Transition factor to change between no-flow and laminar flow regime"; + wf_laminarTransition = SorpLib.Numerics.smoothTransition( + x=Re, + transitionPoint=Re_critLaminar, + transitionLength=Re_transitionLaminar, + noDiff=noDiff) + "Transition factor for change between laminar and transition regime"; + wf_transitionGnielinski = SorpLib.Numerics.smoothTransition( + x=Re, + transitionPoint=Re_critGnielinski, + transitionLength=Re_transitionTurbulent, + noDiff=noDiff) + "Transition factor for change between first transition regime and turbulent + regime according to Gnielinski"; + wf_GnielinskiDittusBoelter = SorpLib.Numerics.smoothTransition( + x=Re, + transitionPoint=Re_critDittusBoelter, + transitionLength=Re_transitionTurbulent, + noDiff=noDiff) + "Transition factor for change between turbulent regime according to Gnielinski + and turbulent regime according to Dittus and Boelter"; + + end if; + + // + // Calculation of the Reynolds and Prandtl number + // + if calculationMassFlowRate== + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXMinus then + Re = abs(m_hyd_xMinus) * geometry.d_hydInner / + (geometry.A_hydCrossInner * fluidProperties.eta) + "Reynolds number"; + + elseif calculationMassFlowRate== + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXPlus then + Re = abs(m_hyd_xPlus) * geometry.d_hydInner / + (geometry.A_hydCrossInner * fluidProperties.eta) + "Reynolds number"; + + else + Re = (abs(m_hyd_xMinus) + abs(m_hyd_xPlus)) / 2 * geometry.d_hydInner / + (geometry.A_hydCrossInner * fluidProperties.eta) + "Reynolds number"; + + end if; + + Pr = fluidProperties.eta * fluidProperties.cp / fluidProperties.lambda + "Prandtl number"; + + // + // Calculation of the Nusselt numbers + // + l_heatTransfer = geometry.l / + min(geometry.no_fluidVolumes, geometry.no_wallVolumes) + "Length of the tube accounting for discretization"; + A_heatTransfer = geometry.A_heatTransferInner / + min(geometry.no_fluidVolumes, geometry.no_wallVolumes) + "Length of the tube accounting for discretization"; + + zeta = + (1.8 * Modelica.Math.log10(max(Re,1e-12)) - 1.5)^(-2) + "Auxillary variable for Gnielinski's Nusselt correlation"; + zeta_transition = + (1.8 * Modelica.Math.log10(max(Re_critGnielinski,1e-12)) - 1.5)^(-2) + "Auxillary variable for Gnielinski's Nusselt correlation at the transition + point"; + + Nu_noFlow = f_correctionNoFlow * 3.66 + "Nusselt number for laminar flow at the transition point"; + Nu_lamianr = f_correctionLaminar * ( + 3.66^3 + + 0.7^3 + + (1.615 * (Re * Pr * geometry.d_hydInner/l_heatTransfer)^(1/3) - 0.7)^3 + + ((2 / (1 + 22 * Pr))^(1/6) * (Re * Pr * geometry.d_hydInner/l_heatTransfer)^(1/2))^3)^(1/3) + "Nusselt number for laminar flow regime"; + Nu_lamianrFlow_transition = f_correctionLaminar * ( + 3.66^3 + + 0.7^3 + + (1.615 * (Re_critLaminar * Pr * geometry.d_hydInner/l_heatTransfer)^(1/3) - 0.7)^3 + + ((2 / (1 + 22 * Pr))^(1/6) * (Re_critLaminar * Pr * geometry.d_hydInner/l_heatTransfer)^(1/2))^3)^(1/3) + "Nusselt number for laminar flow at the transition point"; + Nu_transition = (1-gamma) * Nu_lamianrFlow_transition + + gamma * Nu_Gnielinski_transition + "Nusselt number for transition regime"; + Nu_Gnielinski_transition = f_correctionGnielinski * (zeta_transition/8) * Re_critGnielinski * Pr / + (1 + 12.7*sqrt(zeta_transition/8) * (Pr^(2/3) - 1)) * + (1 + (geometry.d_hydInner/l_heatTransfer)^(2/3)) + "Nusselt number for turbulent flow according to Gnielinski at the + transition point"; + Nu_Gnielinski = f_correctionGnielinski * (zeta/8) * Re * Pr / + (1 + 12.7*sqrt(zeta/8) * (Pr^(2/3) - 1)) * + (1 + (geometry.d_hydInner/l_heatTransfer)^(2/3)) + "Nusselt number for turbulent flow regime according to Gnielinski"; + Nu_DittusBoelter = f_correctionDittusBoelter * 0.023 * Re^(4/5) * Pr^(1/3) + "Nusselt number for turbulent flow regime according to Dittus and Boelter"; + + Nu_aux1 = wf_noFlowLaminar * Nu_noFlow + + (1-wf_noFlowLaminar) * Nu_lamianr + "Nusselt number according to transition between no-flow and laminar flow + regime"; + Nu_aux2 = wf_laminarTransition * Nu_aux1 + + (1-wf_laminarTransition) * Nu_transition + "Nusselt number according to transition between laminar flow regime and + transition regime"; + Nu_aux3 = wf_transitionGnielinski * Nu_aux2 + + (1-wf_transitionGnielinski) * Nu_Gnielinski + "Nusselt number according to transition between transition regime and + turbulent regime according to Gnielinski"; + Nu = wf_GnielinskiDittusBoelter * Nu_aux3 + + (1-wf_GnielinskiDittusBoelter) * Nu_DittusBoelter + "Nusselt number"; + + // + // Calculation of the heat transfer coefficient + // + alpha = Nu * fluidProperties.lambda/geometry.d_hydInner + "Heat transfer coefficient"; + alphaA = geometry.no_hydraulicParallelTubes * alpha * A_heatTransfer + "Product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This heat transfer model calculates the product of heat transfer coefficient and +area describing convective heat transfer within tubes. The model considers both, +the laminar and turbulent flow regime. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +from the Nussel number <i>Nu</i> using Nusselt correlations for different flow +regimes: +</p> +<pre> + αA = no<sub>parallel flows</sub> * Nu * λ / d<sub>hyd,inner</sub> * A<sub>heat transfer</sub> / <strong>min</strong>(no<sub>fluid volumes</sub>, no<sub>wall volumes</sub>); +</pre> +<p> +Herein, <i>λ</i> is the thermal conductivity, <i>d<sub>hyd,inner</sub></i> +is the hydraulic inner diameter, and <i>A<sub>heat transfer</sub></i> is the heat +transfer area accounting for the discretization. The product is enlarged by the +number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> to account +for parallel flows modeled by just one flow. +<br/><br/> +The Nusselt number depends on the flow regime: +</p> +<pre> + Nu<sub>no flow</sub> = f<sub>correction,no flow</sub> * 3.66; + + Nu<sub>laminar</sub> = f<sub>correction,laminar</sub> * [3.66<sup>3</sup> + 0.7<sup>3</sup> + (1.615 * (Re * Pr * d<sub>hyd,inner</sub>/l<sub>heat transfer</sub>)<sup>(1/3)</sup> - 0.7)<sup>3</sup> + ((2 / (1 + 22 * Pr))<sup>(1/6)</sup> * (Re * Pr * d<sub>hyd,inner</sub>/l<sub>heat transfer</sub>)<sup>(1/2)</sup>)<sup>3</sup>]<sup>(1/3)</sup>; + + Nu<sub>transition</sub> = (1-γ) * Nu<sub>laminar</sub>(Re<sub>crit,laminar</sub>) + γ * Nu<sub>Gnielinski</sub>(Re<sub>crit,Gnielinski</sub>); + + Nu<sub>Gnielinski</sub> = f<sub>correction,Gnielinski</sub> * [(ζ/8) * Re * Pr / (1 + 12.7 * <strong>sqrt</strong>(ζ/8) * (Pr<sup>(2/3)</sup> - 1)) * (1 + (d<sub>hyd,inner</sub>/l<sub>heat transfer</sub>)<sup>(2/3)</sup>)]; + + Nu<sub>Dittus,Boelter</sub> = f<sub>correction,Dittus,Boelter</sub> * [0.023 * Re<sup>(4/5)</sup> * Pr<sup>(1/3)</sup>]; +</pre> +<p> +with: +</p> +<pre> + ζ = 1 / [1.8 * <strong>log<sub>10</sub></strong>(Re) - 1.5]<sup>2</sup>; + + γ = (Re - Re<sub>crit,laminar</sub>) / (Re<sub>crit,Gnielinski</sub> - Re<sub>crit,laminar</sub>); +</pre> +<p> +Herein, <i>f<sub>i</sub></i> are correction factors for the Nusselt correlations +<i>Nu<sub>i</sub></i> of the different flow regimes <i>i</i>, <i>Re</i> is the +Reynolds number, <i>Pr</i> is the Prandtl number, <i>ζ</i> is a auxillary +variable, <i>γ</i> is a transition factor, and <i>l<sub>heat transfer</sub></i> +is the heat transfer length accounting for the discretization: +</p> +<pre> + Re = <strong>abs</strong>(m<sub>flow,hyd</sub>) * d<sub>hyd,inner</sub> / A<sub>cross,inner</sub> / η; + + Pr = η * c<sub>p</sub> / λ; + + l<sub>heat transfer</sub> = l<sub>tube</sub> / <strong>min</strong>(no<sub>fluid volumes</sub>, no<sub>wall volumes</sub>); +</pre> +<p> +Herein, <i>m<sub>flow,hyd</sub></i> is the hydraulic mass flow rate, +<i>A<sub>cross,inner</sub></i> is the hydraulic cross-sectional inner area, <i>η</i> +is the dynamic viscosity, <i>λ</i> is the thermal conductivity, and +<i>l<sub>tube</sub></i> is the tube length. +<br/><br/> +Smooth transition is applied using the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition\">SorpLib.Numerics.smoothTransition</a> +to change between the different regimes using the corresponding critical Reynold +numbers <i>Re<sub>i</sub></i>. +</p> + +<h4>Typical use</h4> +<p> +This heat transfer correlation model is typically used to describe convective +heat transfer within tubes if accurate results are required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationMassFlowRate</i>: + Defines the hydraulic mass flow rate that is used for calculations. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Gnielinski, V. (2010). G1 Heat Transfer in Pipe Flow. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_34. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 19, 2024, by Mirko Engelpracht:<br/> + Major extensions (more flow regimes, documentation, stability). + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GnielinskiDittusBoelter; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/Schmidt.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/Schmidt.mo new file mode 100644 index 0000000000000000000000000000000000000000..8f542ad78cd0dbc72888652caef45494f0bdfcf0 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/Schmidt.mo @@ -0,0 +1,338 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside; +model Schmidt + "Heat transfer correlation according to Schmidt for helix tubes" + extends + SorpLib.Components.HeatTransfer.BaseClasses.PartialTubeInsideHeatTransferCoefficient( + final computeTransportProperties=true); + + // + // Definition of parameters + // + parameter SorpLib.Choices.MassFlowRateHeatTranferCorrelation calculationMassFlowRate= + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXMinus + "Defines the hydraulic mass flow rate used for calculations" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true); + + parameter Modelica.Units.SI.Length h_coil = 0.015 + "Gradient of the helix (i.e., pitch between two coils)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Diameter d_coil = 0.1 + "Average diameter of the helix (i.e., top-view projection)" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Modelica.Units.SI.Diameter d_helix= + d_coil * (1 + (h_coil / (Modelica.Constants.pi * d_coil))^2) + "Average beinding diameter of the tube" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + parameter Real f_correctionLaminar = 1 + "Correction factor to adjust the Nusselt-correlation for the laminar regime" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + parameter Real f_correctionTurbulent = 1 + "Correction factor to adjust the Nusselt-correlation for the turbulent regime" + annotation(Dialog(tab = "General", group = "Heat Transfer")); + + parameter Modelica.Units.SI.ReynoldsNumber Re_critLaminar= + 2300 * (1 + 8.6 * (geometry.d_hydInner / d_helix)^(0.45)) + "Critical Reynolds number for the laminar regime" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.ReynoldsNumber Re_critTurbulent = 2.2e4 + "Critical Reynolds number for the turbulent regime" + annotation(Dialog(tab = "General", group = "Heat Transfer"), + Evaluate=true, + HideResult=true); + + parameter Integer noDiff = 2 + "Specification how often transition functions can be differentiated" + annotation(Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.ReynoldsNumber Re_transitionLaminar = 10 + "Transition length for the laminar regime" + annotation(Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.ReynoldsNumber Re_transitionTurbulent = 100 + "Transition length for the turbulent regime" + annotation(Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.CoefficientOfHeatTransfer alpha + "Heat tranfer coefficient"; + + Modelica.Units.SI.ReynoldsNumber Re + "Reynolds number"; + Modelica.Units.SI.PrandtlNumber Pr + "Prandtl number"; + Modelica.Units.SI.ReynoldsNumber Nu + "Nusselt number"; + + Modelica.Units.SI.NusseltNumber Nu_lamianr + "Nusselt number for laminar flow regime"; + Modelica.Units.SI.NusseltNumber Nu_transition + "Nusselt number for transition regime"; + Modelica.Units.SI.NusseltNumber Nu_turbulent + "Nusselt number for turbulent flow regime"; + + // + // Definition of protected variables + // +protected + Modelica.Units.SI.NusseltNumber Nu_laminar_transition + "Nusselt number for laminar regime at the transition point"; + Modelica.Units.SI.NusseltNumber Nu_turbulent_transition + "Nusselt number for turbulent regime at the transition point"; + + Modelica.Units.SI.NusseltNumber Nu_aux + "Nusselt number according to transition between laminar and turbulent + regime"; + + Modelica.Units.SI.Area A_heatTransfer + "Heat transfer area accounting for discretization"; + + Real m + "Auxillary variable for the laminar Nusselt correlation"; + Real zeta + "Auxillary variable for the turbulent Nusselt correlation"; + Real zeta_transition + "Auxillary variable for the turbulent Nusselt correlation at the transition + point"; + + Real wf_laminarTransition + "Transition factor for change between laminar and transition regime"; + Real gamma + "Transition fractor transition regime"; + Real wf_transitionTurbulent + "Transition factor for change between transition regime and turbulent regime"; + +equation + // + // Calculation of transition functions + // + gamma = (Re_critTurbulent - Re) / (Re_critTurbulent - Re_critLaminar) + "Transition fractor transition regime"; + + if avoid_events then + wf_laminarTransition = SorpLib.Numerics.smoothTransition_noEvent( + x=Re, + transitionPoint=Re_critLaminar, + transitionLength=Re_transitionLaminar, + noDiff=noDiff) + "Transition factor for change between laminar and transition regime"; + wf_transitionTurbulent = SorpLib.Numerics.smoothTransition_noEvent( + x=Re, + transitionPoint=Re_critTurbulent, + transitionLength=Re_transitionTurbulent, + noDiff=noDiff) + "Transition factor for change between transition regime and turbulent + regime"; + + else + wf_laminarTransition = SorpLib.Numerics.smoothTransition( + x=Re, + transitionPoint=Re_critLaminar, + transitionLength=Re_transitionLaminar, + noDiff=noDiff) + "Transition factor for change between laminar and transition regime"; + wf_transitionTurbulent = SorpLib.Numerics.smoothTransition( + x=Re, + transitionPoint=Re_critTurbulent, + transitionLength=Re_transitionTurbulent, + noDiff=noDiff) + "Transition factor for change between transition regime and turbulent + regime"; + + end if; + + // + // Calculation of the Reynolds and Prandtl number + // + if calculationMassFlowRate== + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXMinus then + Re = abs(m_hyd_xMinus) * geometry.d_hydInner / + (geometry.A_hydCrossInner * fluidProperties.eta) + "Reynolds number"; + + elseif calculationMassFlowRate== + SorpLib.Choices.MassFlowRateHeatTranferCorrelation.PortXPlus then + Re = abs(m_hyd_xPlus) * geometry.d_hydInner / + (geometry.A_hydCrossInner * fluidProperties.eta) + "Reynolds number"; + + else + Re = (abs(m_hyd_xMinus) + abs(m_hyd_xPlus)) / 2 * geometry.d_hydInner / + (geometry.A_hydCrossInner * fluidProperties.eta) + "Reynolds number"; + + end if; + + Pr = fluidProperties.eta * fluidProperties.cp / fluidProperties.lambda + "Prandtl number"; + + // + // Calculation of the Nusselt numbers + // + A_heatTransfer = geometry.A_heatTransferInner / + min(geometry.no_fluidVolumes, geometry.no_wallVolumes) + "Length of the tube accounting for discretization"; + + m = 0.5 + 0.2903 * (geometry.d_hydInner / d_helix)^0.194 + "Auxillary variable for the laminar Nusselt correlation"; + zeta = 0.3164 / max(Re,1e-12)^0.25 + + 0.03 * (geometry.d_hydInner/d_helix)^0.5 + "Auxillary variable for Gnielinski's Nusselt correlation"; + zeta_transition = 0.3164 / max(Re_critTurbulent,1e-12)^0.25 + + 0.03 * (geometry.d_hydInner/d_helix)^0.5 + "Auxillary variable for Gnielinski's Nusselt correlation at the transition + point"; + + Nu_lamianr = f_correctionLaminar * (3.66 + 0.08 * (1 + 0.8 * + (geometry.d_hydInner / d_helix)^0.9) * Re^m * Pr^(1/3)) + "Nusselt number for laminar flow regime"; + Nu_laminar_transition = f_correctionLaminar * (3.66 + 0.08 * (1 + 0.8 * + (geometry.d_hydInner / d_helix)^0.9) * Re_critLaminar^m * Pr^(1/3)) + "Nusselt number for laminar regime at the transition point"; + Nu_transition = gamma*Nu_laminar_transition + + (1-gamma) * Nu_turbulent_transition + "Nusselt number for transition regime"; + Nu_turbulent_transition = f_correctionTurbulent * (zeta_transition/8) * + Re_critTurbulent * Pr / (1 + 12.7*sqrt(zeta_transition/8) * (Pr^(2/3) - 1)) + "Nusselt number for turbulent regime at the transition point"; + Nu_turbulent = f_correctionTurbulent * (zeta/8) * Re * Pr / + (1 + 12.7*sqrt(zeta/8) * (Pr^(2/3) - 1)) + "Nusselt number for turbulent flow regime"; + + Nu_aux = wf_laminarTransition * Nu_lamianr + + (1-wf_laminarTransition) * Nu_transition + "Nusselt number according to transition between laminar and turbulent + regime"; + Nu = wf_transitionTurbulent * Nu_transition + + (1-wf_transitionTurbulent) * Nu_turbulent + "Nusselt number"; + + // + // Calculation of the heat transfer coefficient + // + alpha = Nu * fluidProperties.lambda/geometry.d_hydInner + "Heat transfer coefficient"; + alphaA = geometry.no_hydraulicParallelTubes * alpha * A_heatTransfer + "Product of heat transfer coefficient and area"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This heat transfer model calculates the product of heat transfer coefficient and +area describing convective heat transfer within helix tubes. The model considers +both, the laminar and turbulent flow regime. +</p> + +<h4>Main equations</h4> +<p> +The product of heat transfer coefficient and area <i>αA</i> is calculated +from the Nussel number <i>Nu</i> using Nusselt correlations for different flow +regimes: +</p> +<pre> + αA = no<sub>parallel flows</sub> * Nu * λ / d<sub>hyd,inner</sub> * A<sub>heat transfer</sub> / <strong>min</strong>(no<sub>fluid volumes</sub>, no<sub>wall volumes</sub>); +</pre> +<p> +Herein, <i>λ</i> is the thermal conductivity, <i>d<sub>hyd,inner</sub></i> +is the hydraulic inner diameter, and <i>A<sub>heat transfer</sub></i> is the heat +transfer area accounting for the discretization. The product is enlarged by the +number of hydrualic parallel flows <i>no<sub>parallel flows</sub></i> to account +for parallel flows modeled by just one flow. +<br/><br/> +The Nusselt number depends on the flow regime: +</p> +<pre> + Nu<sub>laminar</sub> = f<sub>correction,laminar</sub> * [3.66 + 0.08 * (1 + 0.8 * (d<sub>hyd,inner</sub>/d<sub>helix</sub>)<sup>0.9</sup>) * Re^m * Pr^(1/3)]; + + Nu<sub>transition</sub> = (1-γ) * Nu<sub>turbulent</sub>(Re<sub>crit,turbulent</sub>) + γ * Nu<sub>laminar</sub>(Re<sub>crit,laminar</sub>); + + Nu<sub>turbulent</sub> = f<sub>correction,turbulent</sub> * [(ζ/8) * Re * Pr / (1 + 12.7 * <strong>sqrt</strong>(ζ/8) * (Pr<sup>(2/3)</sup> - 1))]; +</pre> +<p> +with: +</p> +<pre> + m = 0.5 + 0.2903 * (d<sub>hyd,inner</sub>/d<sub>helix</sub>)<sup>0.194</sup>; + + ζ = 0.3164 / Re^(0.25) + 0.03 * (d<sub>hyd,inner</sub>/d<sub>helix</sub>)<sup>0.5</sup>; + + γ = (Re<sub>crit,turbulent</sub> - Re) / (Re<sub>crit,turbulent</sub> - Re<sub>crit,laminar</sub>); +</pre> +<p> +Herein, <i>f<sub>i</sub></i> are correction factors for the Nusselt correlations +<i>Nu<sub>i</sub></i> of the different flow regimes <i>i</i>, <i>Re</i> is the +Reynolds number, <i>Pr</i> is the Prandtl number, <i>m</i> is a auxillary variable +for the laminar flow regime, <i>ζ</i> is a auxillary variable for the turbulent +flow regime, <i>γ</i> is a transition factor, and <i>d<sub>helix</sub></i> +is the average bending diameter of the helix tube: +</p> +<pre> + Re = <strong>abs</strong>(m<sub>flow,hyd</sub>) * d<sub>hyd,inner</sub> / A<sub>cross,inner</sub> / η; + + Pr = η * c<sub>p</sub> / λ; + + d<sub>helix</sub> = d<sub>coil</sub> * [1 + (h<sub>coil</sub> / π / d<sub>coil</sub>)<sup>2</sup>]; +</pre> +<p> +Herein, <i>m<sub>flow,hyd</sub></i> is the hydraulic mass flow rate, +<i>A<sub>cross,inner</sub></i> is the hydraulic cross-sectional inner area, +<i>η</i> is the dynamic viscosity, <i>λ</i> is the thermal conductivity, +<i>c<sub>p</sub></i> is ther isobaric heat capacity, <i>d<sub>coil</sub></i> is +the diameter of one coil (i.e., top-down view), and <i>h<sub>coil</sub></i> is the +gradient of the helix (i.e., pitch between two coils). +<br/><br/> +Smooth transition is applied using the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition\">SorpLib.Numerics.smoothTransition</a> +to change between the different regimes using the corresponding critical Reynold +numbers <i>Re<sub>i</sub></i>. +</p> + +<h4>Typical use</h4> +<p> +This heat transfer correlation model is typically used to describe convective +heat transfer within tubes if accurate results are required. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>calculationMassFlowRate</i>: + Defines the hydraulic mass flow rate that is used for calculations. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Gnielinski, V. (2010). G3 Heat Transfer in Helically Coiled Tubes. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_36. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 19, 2024, by Mirko Engelpracht:<br/> + Major extensions (more flow regimes, documentation, stability). + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Schmidt; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2eb06bcaae51a2203548f6ce06e4638c5ea54e80 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/package.mo @@ -0,0 +1,39 @@ +within SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations; +package TubeInside "Correlations for heat transfer coefficients describing convective heat transfer within tubes" +extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains correlations for heat transfer coefficients describing +convective heat transfer within tubes: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.ConstantAlpha\">ConstantAlpha</a>: + Generic heat transfer correlation with constant heat transfer coefficient. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.ConstantAlphaA\">ConstantAlphaA</a>: + Generic heat transfer correlation with constant product of heat transfer + coefficient and area. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.GnielinskiDittusBoelter\">GnielinskiDittusBoelter</a>: + Heat transfer correlation according to Gielinski, Dittus, and Boelter for + laminar and turbulent flow regimes within straigt tubes. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.Schmidt\">Schmidt</a>: + Heat transfer correlation according to Schmidt for laminar and turbulent + flow regimes within helix tubes. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end TubeInside; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/package.order b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6866f77fa509e4ebdb7a95117b98022256e5c98a --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/TubeInside/package.order @@ -0,0 +1,4 @@ +ConstantAlpha +ConstantAlphaA +GnielinskiDittusBoelter +Schmidt diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..4301fd3e98212798146a70194ee1db59719b74be --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/package.mo @@ -0,0 +1,55 @@ +within SorpLib.Components.HeatTransfer; +package HeatTransferCoefficientCorrelations "Package containing correlations for heat transfer coefficients" +extends Modelica.Icons.FunctionsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains correlations for heat transfer coefficients that can be used +within heat transfer models. The correlations calculate the product of heat transfer +coefficient and area as a function of fluid property data, gemeotry, and flow regime. +Correlations for heat transfer coefficients are implemented for the following heat +transfer models: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Generic\">Generic</a>: + Correlations for generic heat transfer coefficients. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction\">Conduction</a>: + Correlations for conduction heat transfer coefficients. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Radiation\">Radiation</a>: + Correlations for radiation heat transfer coefficients. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling\">PoolBoiling</a>: + Correlations for radiation heat transfer describing pool boiling. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation\">PoolCondensation</a>: + Correlations for radiation heat transfer describing (pool) condensation. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside\">TubeInside</a>: + Correlations for heat transfer coefficients inside of tubes (i.e., (foreced) convection). + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber\">ClosedAdsorber</a>: + Correlations for heat transfer coefficients inside of closed adsorbers (i.e., (foreced) convection). + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.OpenAdsorber\">OpenAdsorber</a>: + Correlations for heat transfer coefficients inside of open adsorbers (i.e., (foreced) convection). + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructering the library. + </li> +</ul> +</html>")); +end HeatTransferCoefficientCorrelations; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/package.order b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/package.order new file mode 100644 index 0000000000000000000000000000000000000000..7fab39bf34937fd575a96ee26e7cd8ed0f8965c8 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/HeatTransferCoefficientCorrelations/package.order @@ -0,0 +1,8 @@ +Generic +Conduction +Radiation +PoolBoiling +PoolCondensation +TubeInside +ClosedAdsorber +OpenAdsorber diff --git a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/ConstantAlpha.mo b/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/ConstantAlpha.mo deleted file mode 100644 index dfa2441effaa334517a0076a13e8d2c6b6ce8f65..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/ConstantAlpha.mo +++ /dev/null @@ -1,37 +0,0 @@ -within SorpLib.Components.HeatTransfer.HeatTransferPhenomena; -model ConstantAlpha - extends - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer(final computeTransportProperties=false); - - parameter Modelica.SIunits.CoefficientOfHeatTransfer constantAlpha(start=100)=100 "Constant heat transfer coefficient"; - - parameter Modelica.SIunits.Area heatTransferArea(start=1)=1 "Heat transfer area"; - -equation - - alphaA = constantAlpha*heatTransferArea; - - annotation (Documentation(info="<html> -<p> - This simple transfer model calculates the heat flow based on the temperature differnce with a constant alpha. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> <i>Q</i><sub>in</sub> = <i><code>α</code> A</i> (<i>T</i><sub>in</sub> - <i>T</i><sub>out</sub>) </p> - <p>where <i><code>α</code></i> is a constant heat tranfer coefficient and <i>A</i> is the heat transfer area. </p> -</p> -<h4>Assumptions and limitations</h4> - <p> - In general, the heat transfer coefficient depends on fluid properties and geometry. Thus, a constant coefficient is only an approximation. - </p> -<h4>Author Information</h4> -<p> - <ul> - <li> - December 06, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end ConstantAlpha; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/ConstantAlphaA.mo b/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/ConstantAlphaA.mo deleted file mode 100644 index 2f0975bb2f4b5c06e193cabe186522d0c525e0cf..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/ConstantAlphaA.mo +++ /dev/null @@ -1,34 +0,0 @@ -within SorpLib.Components.HeatTransfer.HeatTransferPhenomena; -model ConstantAlphaA - extends - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer(final computeTransportProperties=false); - - parameter Modelica.SIunits.ThermalConductance constantAlphaA(start=100) - "Constant heat transfer coefficient multiplied with heat transfer area"; - -equation - alphaA = constantAlphaA; - annotation (Documentation(info="<html> -<p> - This simple transfer model calculates the heat flow based on the temperature differnce with a constant product of heat transfer coefficient times heat transfer area. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> <i>Q</i><sub>in</sub> = <i><code>α</code> A</i> (<i>T</i><sub>in</sub> - <i>T</i><sub>out</sub>) </p> - <p>where <i><code>α</code> A</i> is a constant product of heat transfer coefficient times heat transfer area. </p> -</p> -<h4>Assumptions and limitations</h4> - <p> - In general, the heat transfer coefficient depends on fluid properties and geometry. Thus, a constant coefficient is only an approximation. - </p> -<h4>Author Information</h4> -<p> - <ul> - <li> - December 06, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end ConstantAlphaA; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Partial/PartialHeatTransfer.mo b/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Partial/PartialHeatTransfer.mo deleted file mode 100644 index d63339b11b252c4f9f7628240bb82c2e51d8fdd8..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Partial/PartialHeatTransfer.mo +++ /dev/null @@ -1,28 +0,0 @@ -within SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial; -partial model PartialHeatTransfer - - Modelica.SIunits.ThermalConductance alphaA "Heat transfer coeeficient multiplied with heat transfer area"; - - constant Boolean computeTransportProperties = false; - - annotation (Icon(graphics={ - Bitmap(extent={{-100,-100},{100,100}}, - imageSource= - "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAGIVJREFUeNrsXdlyG0eWzQJ3ihahZWTZLQ+hmNUTPUE4Wu8Ev0DQF4h6mVfRXyDoCxp6nRdBX2DyC0S+s0NQdEfM2NE9Ar1bGwFxAVdg8oC32BCJqsoCKisX5IlIgZJAElV1T557bm4ec0gcG4zN8pc8bzlqWfo7O/d1XFR5q5/7ukateoexhrv7ycJztyARIuS7CFFQ/LHWfMIQadbdk3IESYsQc0SAQhcpTECVGsizxkmz6Z6mI0hSCgEyFOk1Z8ml1YgsK0QYl5o5gsRSiWIXMYYBKz5hnLo4ggQpxRK1/JDfDqRiZSJLwxFkuIlxl0ghTSkmeRvhbZxa97/FwQlv+/T1IbXuf5OoLBVOlFVHkOFKoXy1SMxTXKLAH+96HU/pmnzC7He97ibvWSpElk1HEDuJMc9flokYA2GMCOGTYlLTa/aJ4r8eJfNjQZQyJ8pLRxA7iLHAX0psgPGJDJHhE3odM/ReHBFRtum1NdiPg6kv2T7O4jliBKvETBcxbIRPlJ3B1MVqoniOGB8rBUiBktb0kHmzPXZastrpX1msJIpnETHmiBixPcYUb5eJGA6nRPnAW7N/j1Kyxcx7FhBjlsx3Ka5agBRZgz1FGp6lTmTpQ1VKZOYbjiDqyIFxDAxq5US/Z5S3q+QtRhwHhHBCXuU9b8fxvrWGzsvkcRTPUGLMETGKcYhxxWLDnaax34pPlBUiyqYjiHxyPCT5zooSI+uIIYUo9XhEqZM3eeIIIs9roCcqiHoMpFIzLpalYodSrxgeZQ3Kb4o38QwhB7xGRVQ1ZkkxMi5+U0GLFCVGxENNlkzwJp7mxJildGpZ5P0TpBqjLmaV4JjU5ED8W8qUdjUcQfoz4kipIqefj5C0TLkY1QJNkogTsbdXKeXadASRkFKhXHuZuYUtuqHNTsdPBGcVa5tyeRqS4xETGPTzVWPcxaLWOIynJki3HjuCBJPjKROYKjJBRtyZcHNMfEPcm2DNyQNHkItmfC3Kb+DDojo16WLOSGBdyjalXwK+pKCDefc0IIeQGR8hr+EqVGbjmLzJiRhJlJt3TzE55kk5Qs04fMaMS6msSrl2yJ8ImPeCytWLnu7kQOl22sWUlcAalKbmJPF0JYdHxHBVKrtxSERpa0oST1dyzDA3HX1YcEIpl44k8XQkh1urMZwk2dWQJJ5O5MhQWuVGxYcTbUq3WhqRxEuJHCjlVqPIMeXI4UhCxl2AJPk0SsBeCuSIHAQEOSYdORy6SLIfTZJUBhPTGHcLJQdIMUE3pe1iw4EwQSQJiYk8xdZXxipI1Nwq/PJxpxwOIUpyGN1xSp27NSKRHJiVG7rQyZHDIQpIvyOmpeT/i//x35I2rPMkkQPrOVaicjtHDgdRJRHYHKIoYz2JJ4EckRWrEUcOhz5IEqEkUipbXsLkiKxYecxNOnToD61oP5J4ZSvpKlaJCawhb7ln7SAHeYrBr7VTEBHf4eCQEhLzI15C5EBqVWOC+1bZiKn5eTaSzbJPCoXO36fz+c7fw3BSr7O9avXstYmvG+5E5gQAP5JLItVKiiDP2QAnOJmGkdlZli0W2RQnAQgBMiSFg1qNba+tsR3e6isrjjD9A+e/LyonCO2VW7b9bo/PzXVIcW1pKVFCRHaFnCR+S4MsMwsLZyoo85qaL1OZa7g86F7A3oDkiCzpmo5r9+93SCE7aKJwzNOwd5UKe10us8NNeXP0vnzxQmoHgOv4Sy6XljIOXPodtOJatpEcSKE+e/SI/f7VK5bjQamaHMAo9zOfLi+z/+Qp2NzTpx1Fk6GSstURBE8xbcwOmt30TRCqWhVtI8eNhw/Z73kQfl4qsQne0+mI61zRvuSGHiRONJqK8h8nVDBlFClW00uxqGqF1CpnCzGQe3/Be7c0/UUSQPWrxgmTRE4vO716y8mx+UDJnnA1SrViS1e/CrJsCzmQTt364x/Zv62tGUcOAJ/5PxJQkzTSKwXq4SPHBE8IGFhByJjXbCAHxi7gMUwkRi+gPPw3nib1k+MjtYSCygLK13+5fVv1LcrFNez9KIgVJd3Zu3fZvxqqGkFAMQHeBMSPC1TqZJtzDVCSqiBcPRbY6WREo4HSbU6d3EsHSqnfcbKI+hKkV6iOyUQ1m9Vl0BOTGYXXjmRkM1A3wG/YTA4AJWGoo6iSyK5eaTYjIFYMCxOE1KNgcuBg/ABjCcOAOCSRnV6BIBqhQLGcuIIYrR4wodclB4KJJJFdvUK6pxlBYsWyEEFMVw94ji/KZTaM8EkSNPKexrwrDSdcCqtIJmnG6Qa/lDvMAEn+iQcqxnzS9h+YlawphGI6sopFW4ZWTQwMBASmjYxms8zhtDf/2717H/3bH9pydyPTqHrVC/moLUxFFMRYV4te05HjY7WAF/OBsaAhTK9ixXYmQj2QuBrpbDH1QodZuLoBXsw37Wn4D82xRDHet4IYSQ4EAGbjOgQrK9JP2QTZ1td/CMe4lQQZdlMeBUzjvyV55jJmGctc2KWcIDSHPmdiamXT/CpZkD0mZIh6dPrTsPUiGZvUA7X+G0MyUq47DPAfQrHuBagHCuZ10x4KppLoOlqOEWWMCSD16NW7Iu2RsUuKKvzJM25z2WyvBVVBBDFup5I0ZqT225NiJV1jdTXWtXRKslwNdV32G5Vefbe4aNrHXuIEeSaaYhmXXulmzBEkf+bBjYG5OOQAYG5fP3nSWWD0AycJ1Mc0ghiIZSEPQnVhozQeZV1dxjwQzAhq9KBJVHE6ROFEMymnN5Qg+V5jIr0UxLidSnQx5lhWioVKCOokgdFoKNEPhhQgdtbXmaEoihCkYNIVIV/XwZjDfP8PN9cydwwE8WqaT9k3VD0CYz9zLr2aNU1BrmlCDihHGvOO3j17pjVJcC8MRpE4EKggBdOuSDVB4DkQsGlOytOZJIYryAUOZEz2H5iNqroMmtSmbf2Q5K2GU2p2zCdI0RoFSWOrzDD8Vi7HLuEmCexSqFNKgyKFBcc19FYQKnHlHEHEg+EXDWYM65RqNc32Hz5y3eXejKnqgfRK5WIolFx16C2R3v2myXr7PTsI8hEXjCWISvWAEVWZWp0HlEyH0XYLDHooQYwaPVc5cv6zZouxoGQ6bO3ZtEdBzrjgdXmQtimfXuXERE02Yb4ArBDMK1QRXe9Lv7hD3MgQORZM+vAq1eO1pvtrQUVUln0tUg/WzYmMienVjEKCvNN4Oa/KCY17lhHE54SRBFG1oEj3bWxQOFBl1i0y6D0JknMEsSMIVKlI0z4FyXUTpGDKp+7ncBgbUhhRqJjqAdWyYAT9PDqcyJyfvag7xhXNvUKVxoRtbFSonIXq4Rv12YzzH3bl2CDxQcolcAv9x5kPyZjmP0YUTS8xqZdM+7MearhZRlI+xDiCqFIQk8qYaX/WA8sJ4rY/t0xB0iaIwWvQo5A1zoOoGkU3qUpzkuJYiGlbEvXjQRwsM6Fp9ui2VrB8uBTLYWi82VCkWCpgoglN6zOfuBTLwcQyZlqfeW8IUixjEHSUscNwFAQcQaJ6RTNOLHLq6gji4DAcnZYjiIODI4iDgyOIg0PiGA37T8/dn7P74O6FvTHSdgri4JCwgujaa2JgSsWUd6cgdt+Xti0KYvvAlINTEON6LCiWaT2lZ/HzcAoSAhW7doxkzZvwnNbmeip3mUlLQTDbLO/y7mBgJxV3L4I7D9PvTUgVqwoFMSqp31WgIOOKj3mL/XlTnNQ5mrV6OVE9E8YqT8OmyqQjlfA0vSfnW5qEniJ/ZnKLGgcxakL/voIDM/1AMAVpftYRuxUkPMXSlfEq1kGb1FOmqSCTFihIVIpVi2lc1KuIAoJcUnjkQj9B6/xZIia9NhpEEJ0rWfuKFASnOLUM2P5nKmWCeHaSo0OQUA+iq4rsKtqG57Lic9mF1GN+PnVfMGnwWEg7yoPcYaxhWiXrgBt1FdUspFm659MqUkFfRWyrYIEbfpl3zTQfokJFoCBIs3SGCoJM5s3dOSokxjsB5hOkZpKCoO0pmnLyCSeJrvcE5FWRBpqgrH0oSK2bID19SEtj5m8rOu0pu7Sk7T1R5ZHGDK5khcR4NZIgOqvI8eamki1n0FteWljQ8p7MKiIvPAjUyyb/IUwQnVVkR5GKXC+VtKxeqRyrMdGHtMIN+voZQaiSFZhm6doDNBSdWa6jilxdXlZeHDBNQaLSq24FCVSRE40v8PDlS3akaGe/G+WyNvdhmpN1VrE3mjaQICcxCRJY6tU5zVKlIkgprjx8qMU90CHlmzAsxWoJlHiFCKJ7mvVBEUGAazwwx+bmlF4/SDqtwTwxlMBV34uE0qveBOE+ZJMFjIcca9wToJqlyqwjKD7nvzujaPBwghtzpHq6YNqgCZ0hMV0jLlxQkEAVOda8N6grDBKkWir8CMqqtzQ7Gs4kH3IsoB69CBLYFR9p3Bs019eVmXXgMjfInz59mtrvyxA5dFusNGWIgkTE8koYQQK7pBPNe4T3io2qT5K0lENHU4wRdRN8yImg/7hAEBoPWTFNQYDtZ8+UqohPkpvffCPNk8BzzPFr1LliZEI1KySWV87Pbs9EMchH2wAV2dKg3DlTLLIvqlU2leBAIlTj6qNHnZ+r+xrwSxpP5vTVQ6S86+PCYrANxuaCqlnjMGKa9w7/+OqVNpPnmjwVAmmbA5xb/sn9++wKysmGTAiEin9/+7a2n2+Pt8Pg/851V7B6EoRI8oL12EwOb9Z9D4vpu3fZTUVl3yAc8J5/u1Jh+5wwhwK7suAa0BNPY/2JgbuGfM/JfKzp0Wz1YAWpcnJ8FakgRBAMEfesnV4iJdEZnz1/rm1FBSshDzlhWvQKjPKAQstwMkzkzT+2/g33YvCEugHKsRv830ucIM9ECTLLArYDwi4PlzV/QOPczP7O8vO7dcYuV/DX9+5p97k+sNDxj2yv5ec9d1YMq2bhF7Q0f0BIY7Y0nJI+LJjUUL1b4eRYCdqbIWx390rQf+wz/UdKt8tldmz5Gd4D5eISOxD4pinNlgPsh3/kwFgPJAhn1CoLqGYdML03dOj0GI0Ge6vx8liVQLGg/vix1A5kWqMtktoUswGoUazHI0gYs9pkeHRXkYP1dfZBo8l8WnQc9Xqn4/CIKDIJok0chHfolbDr6IsgwB4zY1Ja/euvz6pFDoxtLS+z1ubm6R7HEsvhqMqNa7IjfjP8o5b7JggNmlSCTM++IUHxhvdmLXe2IdupVNhuV/l1X/JsYB3M+n54UakStnFiJEE2Ihi2a4iKoMd8P+R+BCpa5+rx0a7m3KfJJMklSuVUtt0I9diIuAaRMwox9LsWpCJNQwKkubrK3g0pSaCer3lv3u6x8bbMNGscG36neNrVhWsLV481iu2BCQKUTFeRTi7K04tdhUt0VZHjDVIdTo6e5U/J03JmFKrIbp8xLUSQc9KzboOKdEzqgwdDQxKfHEch879OePoptdyrSLUF1GM9INb7UpBQxm0zvffxvVDZGgKSdMq5nBzHnByRg2iWVbPaFJODqkcgQQIYFagi+EB7hgUQSPLB0ukoPjmOBM9z3JPcWVxKeVO7PRa55mNdMOYDJysGYYGFLMv9B3Y6mdEkTGG9hUVqclStsi2e1hzHPOz0xqtXnd5eFmF/vXIllevHfKs34W8p9CIIcGfAFMtXkcBoahgYUDDub/J5K+ZtIVXy06rY90FiJ4Fp/OiI0kBEDFaCyMFEFWQj+nsCVxwC6CemDAwub3aWZXmQTBpwzFqvHnqbp4t7T570/TNQjr0hsZM4WFtj7xcXpRvzrfC3QCJDV3LdGVBBGP2CwOT9A9N/OnxPH9VosK1799gWJ8iJQWpyyAPvLVfAQcgBoJp1JHFKzgRXNpljIi2KvQhjHnuZY6bPz1MOUpETqiCYeuLQwepqJ+B2eI+s8/QUkLjBvQZ6ZX9u1cDXLnlM5NK5kfxElzew0O18aixizpVQirUR73vvspCN5q6j1zA8p8f2PdP8oaJlNFkbDmKAvE0JS1pH5+fZdYkq0hmXyeV6jugPlL7x9jb8LcibV0V/3p2ECAJ8Q7/8Yk7L26cDSJRu/mQCmyhwoowpWjMOA44efl/yWu8rz59L/fkg99EAu7z0Sq1+C1cPdOKx1v8mSRAklehyenavk6QkNgF5NMgyydMb2WSBvzggYpxoukuIakA5QmaVI0fOx/UeSRIEeBiW311lpzuh2Agoyxg3nyAKXkdwVl+fYwlInY55eoMGYiTZy9oKzLV6H/4WjFDGrl70JMjGYJ8VulwIMjlItcaG6MFBZXyiZHqQBmRoUaUMXzt1iI8jSq0iRsz7rivfSZggs1Qp6JlqjVnkRxzUw/cdR+GpFXqlxqAESWpmCD7IEgvZ+Podbzfcs3VIAO9Y5GbqSyyhiR1JduqrYV6kyQJ2onNwiIE6E1pjvprU70sqxepOtdZYj319faCqNeOes0Mf2GGR4x1V8sIDq8dHHmQj2esILf1Csm4y/ff3ddAL2Gbq52hxiV3SjSKJjNnpm2F+BAbrVyLJhHvuDgI4oJhh0b4j8XKgrMIScsBSWBXiNTNzUqNDuhCMlVKSvuOCB9mQd31Pidk9gTTrM3Y6LcXB4TwwfeQXFnrgDVDh7YGM33+HyR+aeEB+JDCv/MUpiUOAcgiQoyqLHGcKsiH/WiMrW1CSz52SOHQpx89i5CgwyQtZ0xjcxgUUWcgwiF+hcEri0BIjR51iSvoq77T2WNgktkNJskEk+Ym33zklGWrl+EmMHAUmoWKlSkF8vKQLC1WSH1joWQ4OluKAIl6QHC/T+lxp79LzMkpJjqkXucXcOMkwkeOn6BQ7dXKkrSDCSoIb9SOLXITvYAHwjL/XlBwqFERYSfwpzVCUay6OrMQ7akxTcqhSEGEl8W+igPw6GIQWPVPdyaGaID5JMD4SupXGbpd591wzuh3Qs9yNjo0qxcZLlQGqwyI/vwRcjTJyuLEN1wEbiwYTrlL6g4DK1yJnNLp3X7GIE0f9mcB+yuV6ZEOOwKNn9qtYqlyhWNCiL9RtmTjm1ZSi3oSFMzVm3pELw4g9elY7Ym8vMclzq+IijblY/eAu9SSR2xlis2wcu+BG3/UCRsVxDMGW2NthxpeYpCnrNhIEwMrEFRYyydGHv2vKZReXWgBjGxG7jpz3G0Ud/IYJKVYv8x656TAexI8k5YcuPpXhkJ7Bj+LkKOtixk1UkL5SLkYp1zWXdqWaTr1jkSc7GZFSxSKIp9EHbZ+uK1lhATs49pLGm+RRHOQBHkOwOuVjDSmVp1HFvm1oinWerA3vdCvJZSawxZa/ruA7erMrtyZ8UjDd2xjrePAty3iGnkHDWZkw9dCxffnixRMy7kKnvSAXRg3+W/GKikOEYnxL9/RI/Ns6xRYebE90jasgmHYoLTup19kf2m2Yunt/8ry7ZPRyokR53VXxch5F3GPErEz5gGdfzhjgNaxRkG62c6KskpqURC/Yr3j9LxNa2jn0Vamf6V79GJ8ceCZ53gmtmpAyGu9BfOysrX30d06SBm+PSUUqoj+nRZUXpAv/R6mD8xanbYvuybd0j2LOpMYzyHFiPB6xYOrcKDOkihUFSrse8LSrQr1XQfR7d6mht5ylytew7R+8Q8RosL6XFqDnKo3GPIdc9yqWcR5k95yC9CAKHtAiJ8pCXKK0KEjQxogsM/RqIxpEjEb89MkKYgzkQdqayv+J4NHMIApvi+zvKxdjAQHzllzmn3l7xU6P+zLZsxzSNbyia6rRNR71T4zCrUePFnlnsm5ySmmVguy/jLd+pktR5tnpGMpS3N/pH1Lvr5EfJ2WZ6nrVEU1SCP81IXIjhS3z+9p5EG/LZWYzjPQgzWqVTcU8YZYeKDxKiUiyxATKw2E9cTd8oox3vaZ1xMMhtWbX606yv6JGxKiQ1zvDJH8O3jASpK2zivRBkHNmHlWvxzSOAqIUkzC5vYISZBk5Rxj/3+LghP39ZCWfEN3/JgkrRIrAcYzxPk/1tcake5oSJAnQg1/lRJklkiAFS/Tw86Z58YKbi7xpBSX0qDeDIJ6l5OjEf9hkxTGm50DJ5Pw8++eESHIenCxzRJZCEspiCFbIdK+cT6FE8Feu5nG9oS5oRRQpQs8HGdXYxf/71hYbyWal/g5SlkIXYXKWEKLmEwKvIkoRhu+LRba9auZskmNqvRB5BJvOPgTjIZeLcjt4CpxVar66FKjlk07HJKdNVSLFWj8qEaroXEFMJUhkihWmIEivdN0f9+rDh+ymghLjT0tLrPHsWbfHWOgiS47FGJiUhDVSiA4pqMwtvbPaXFw0kiAHLHjmwB0mcASbrjX+sbk59i+1mhLligqG5ungu08YtGyX2mQHUB4Eff3c1zWfEJ/dv9/4vFJJ/Z4c8ufw19u3jSRIWBEFBPl/AQYA7UjMdA8AKdMAAAAASUVORK5CYII=", - fileName="modelica://TIL/Images/Alpha.png")}), Documentation(info="<html> -<p> - This partial model is the basis for the heat transfer correlation models. <br> -</p> - -<h4>Author Information</h4> -<p> - <ul> - <li> - December 06, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); - -end PartialHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Partial/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Partial/package.mo deleted file mode 100644 index f992a6fabb76baaba9424330040ea9aa030ffc8a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Partial/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.HeatTransfer.HeatTransferPhenomena; -package Partial - extends SorpLib.Internals.ClassTypes.PartialPackage; - - -end Partial; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Partial/package.order b/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Partial/package.order deleted file mode 100644 index f1ce3c2067e8c1d1edd455954ca07a4b7f1c2fe5..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Partial/package.order +++ /dev/null @@ -1 +0,0 @@ -PartialHeatTransfer diff --git a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Records/HeatTransferSilicaGel_Lanzerath2015.mo b/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Records/HeatTransferSilicaGel_Lanzerath2015.mo deleted file mode 100644 index ad0ab2f9adf7070f673c9d7455c015ff32780891..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Records/HeatTransferSilicaGel_Lanzerath2015.mo +++ /dev/null @@ -1,25 +0,0 @@ -within SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Records; -model HeatTransferSilicaGel_Lanzerath2015 "Heat transfer coefficient heat exchanger to adsorbent (Silica gel) (Lanzerath2015)" - extends SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlpha(final constantAlpha=686.7, final heatTransferArea=Modelica.Constants.pi*0.02086*7.355); - - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false)), - Documentation(info="<html> -<p> - The heat transfer coefficient in this record was determined by Lanzerath et. al. (2015) for silica gel 123 particles. -</p> -<h4>References</h4> -<ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end HeatTransferSilicaGel_Lanzerath2015; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Records/HeatTransferZeolith13X_Lanzerath2015.mo b/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Records/HeatTransferZeolith13X_Lanzerath2015.mo deleted file mode 100644 index 04d6d6703a733c1e45e6052757e778979823b345..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Records/HeatTransferZeolith13X_Lanzerath2015.mo +++ /dev/null @@ -1,26 +0,0 @@ -within SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Records; -model HeatTransferZeolith13X_Lanzerath2015 - "Heat transfer coefficient heat exchanger to adsorbent (Silica gel) (Lanzerath2015)" - extends SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlpha(final constantAlpha=294.6, final heatTransferArea=Modelica.Constants.pi*0.02086*7.355); - - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false)), - Documentation(info="<html> -<p> - The heat transfer coefficient in this record was determined by Lanzerath et. al. (2015) for zeolite 13 X particles. -</p> -<h4>References</h4> -<ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end HeatTransferZeolith13X_Lanzerath2015; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Records/package.order b/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Records/package.order deleted file mode 100644 index 14a2e44875631bdb77dd1efa80c8fc77c07ddbc5..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/Records/package.order +++ /dev/null @@ -1,2 +0,0 @@ -HeatTransferSilicaGel_Lanzerath2015 -HeatTransferZeolith13X_Lanzerath2015 diff --git a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/package.mo b/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/package.mo deleted file mode 100644 index 686303853cb07dd2f53d9c85eead8f0da754e602..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/package.mo +++ /dev/null @@ -1,7 +0,0 @@ -within SorpLib.Components.HeatTransfer; -package HeatTransferPhenomena -extends SorpLib.Internals.ClassTypes.ModelPackage; - - - -end HeatTransferPhenomena; diff --git a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/package.order b/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/package.order deleted file mode 100644 index e8a95d587e76fb0107d66c82261e4999757a8af7..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/HeatTransferPhenomena/package.order +++ /dev/null @@ -1,3 +0,0 @@ -ConstantAlpha -ConstantAlphaA -Partial diff --git a/SorpLib/Components/HeatTransfer/OpenAdsorberHeatTransfer.mo b/SorpLib/Components/HeatTransfer/OpenAdsorberHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..86e086f720a6e6e5d406618264d983a8ab5dbebc --- /dev/null +++ b/SorpLib/Components/HeatTransfer/OpenAdsorberHeatTransfer.mo @@ -0,0 +1,113 @@ +within SorpLib.Components.HeatTransfer; +model OpenAdsorberHeatTransfer + "Model calculating a heat transfer describing heat transfer between gas and sorbent/casing within open adsorbers" + extends BaseClasses.PartialHeatTransfer( + final exponetTemperature=1, + redeclare replaceable model HeatTransferCoefficient = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.OpenAdsorber.ConstantAlpha + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialOpenAdsorberHeatTransferCoefficient( + fluidProperties=fluidProperties, + m_hyd_xMinus=m_hyd_xMinus, + m_hyd_xPlus=m_hyd_xPlus, + geometry=geometry)); + + // + // Definition of parameters + // + replaceable parameter SorpLib.Components.HeatTransfer.Records.GeometryOpenAdsorber geometry + constrainedby SorpLib.Components.HeatTransfer.Records.GeometryOpenAdsorber + "Geometry of the open adsorber" + annotation(Dialog(tab = "General", group = "Heat Transfer Coefficient", + enable=false)); + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the sorbent)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Modelica.Units.SI.MassFlowRate m_hyd_xMinus + "Hydraulic mass flow rate at design inlet" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Modelica.Units.SI.MassFlowRate m_hyd_xPlus + "Hydraulic mass flow rate at design outlet" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The heat transfer model is used to describe the heat transfer between the gas +and sorbent/casing within open adsorbers. Thus, the closed adsorber heat transfer +model represents a thermal resistance between two models. Depending on the attached +temperatures (i.e., attached potential) and the chosen transport phenomena, this +model determines the heat flow rate between the connected models. +<br/><br/> +The model has two heat ports, which sizes can be defined via a parameter. The +scalable heat ports enable the connection of various models. For example, this +enables to connect a discretized model to a lumped model, or two different +disretized models. +</p> + +<h4>Main equations</h4> +<p> +The model has steady-state energy balance: +</p> +<pre> + 0 = ∑ (hp_a.Q_flow) + ∑ (hp_b.Q_flow); +</pre> +<p> +The heat flow rate <i>Q_flow</i> is proportional to the driving temperature +difference <i>ΔT = hp_a.T - hp_b.T</i> and the production of heat transfer +coefficient and area <i>αA</i>, which can be formulated as thermal resistance +<i>R<sub>openAdsorber</sub></i>. This product can be given as an input or calculated +using models describing heat transfer coefficient correlations. +</p> +<pre> + hp_a.Q_flow = αA * ΔT = 1 / R<sub>openAdsorber</sub> * (hp_a.T - hp_b.T); +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> + <li> + The number of ports a and b must be an even integer multiple of each other. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The open adsorber heat transfer is typically used to describe the heat transfer +between the gas and sorbent/casing within open adsorbers. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useAlphaAInput</i>: + Defines if the product of heat transfer coefficient and area is given via + an input or calculated using an approproate correlation model for the heat + transfer coefficient. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 23, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Text( + extent={{-60,20},{60,-20}}, + lineColor={0,0,0}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={238,46,47}, + textString="Q_flow = 1/R_openAdsorber * DT")})); +end OpenAdsorberHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/PoolBoilingHeatTransfer.mo b/SorpLib/Components/HeatTransfer/PoolBoilingHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..450247846ceea15acac902333c9dc4879dbb5a98 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/PoolBoilingHeatTransfer.mo @@ -0,0 +1,111 @@ +within SorpLib.Components.HeatTransfer; +model PoolBoilingHeatTransfer + "Model calculating a heat transfer describing pool boiling" + extends BaseClasses.PartialHeatTransfer( + final exponetTemperature=1, + redeclare replaceable model HeatTransferCoefficient = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolBoiling.ConstantAlpha + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolBoilingHeatTransferCoefficient( + fluidProperties=fluidProperties, + f_relativeFillingLevel=f_relativeFillingLevel, + geometry=geometry)); + + // + // Definition of parameters + // + replaceable parameter SorpLib.Components.HeatTransfer.Records.GeometryTube geometry + constrainedby SorpLib.Components.HeatTransfer.Records.GeometryTube + "Geometry of the heat exchanger tubes providing the heat flow rate for pool + boiling" + annotation(Dialog(tab = "General", group = "Heat Transfer Coefficient", + enable=false)); + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the volume)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Real f_relativeFillingLevel(min=0, max=1, final unit="1") + "Relative filling level of the evaporator" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The heat transfer model is used to describe pool boiling by connection a phase +seperator volume with a heat source/sink, such as a heat exchanger tube. Thus, +the pool boiling heat transfer model represents a thermal resistance betweed +two models. Depending on the attached temperatures (i.e., attached potential) +and the chosen transport phenomena, this model determines the heat flow rate +between the connected models. +<br/><br/> +The model has two heat ports, which sizes can be defined via a parameter. The +scalable heat ports enable the connection of various models. For example, this +enables to connect a discretized model to a lumped model, or two different +disretized models. +</p> + +<h4>Main equations</h4> +<p> +The model has steady-state energy balance: +</p> +<pre> + 0 = ∑ (hp_a.Q_flow) + ∑ (hp_b.Q_flow); +</pre> +<p> +The heat flow rate <i>Q_flow</i> is proportional to the driving temperature +difference <i>ΔT = hp_a.T - hp_b.T</i> and the production of heat transfer +coefficient and area <i>αA</i>, which can be formulated as thermal resistance +<i>R<sub>boiling</sub></i>. This product can be given as an input or calculated using +models describing heat transfer coefficient correlations. +</p> +<pre> + hp_a.Q_flow = αA * ΔT = 1 / R<sub>boiling</sub> * (hp_a.T - hp_b.T); +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> + <li> + The number of ports a and b must be an even integer multiple of each other. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The pool boiling heat transfer is typically used to desribe the heat transfer +within an evaporator. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useAlphaAInput</i>: + Defines if the product of heat transfer coefficient and area is given via + an input or calculated using an approproate correlation model for the heat + transfer coefficient. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 17, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Text( + extent={{-60,20},{60,-20}}, + lineColor={0,0,0}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={238,46,47}, + textString="Q_flow = 1/R_boiling * DT")})); +end PoolBoilingHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/PoolCondensationHeatTransfer.mo b/SorpLib/Components/HeatTransfer/PoolCondensationHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..9685e0160bfdbdbcd4fc15e0a618a9c2b2eecd55 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/PoolCondensationHeatTransfer.mo @@ -0,0 +1,111 @@ +within SorpLib.Components.HeatTransfer; +model PoolCondensationHeatTransfer + "Model calculating a heat transfer describing (pool) condensation" + extends BaseClasses.PartialHeatTransfer( + final exponetTemperature=1, + redeclare replaceable model HeatTransferCoefficient = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.PoolCondensation.ConstantAlpha + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialPoolCondensationHeatTransferCoefficient( + fluidProperties=fluidProperties, + f_relativeFillingLevel=f_relativeFillingLevel, + geometry=geometry)); + + // + // Definition of parameters + // + replaceable parameter SorpLib.Components.HeatTransfer.Records.GeometryTube geometry + constrainedby SorpLib.Components.HeatTransfer.Records.GeometryTube + "Geometry of the heat exchanger tubes providing the heat flow rate for (pool) + condensation" + annotation(Dialog(tab = "General", group = "Heat Transfer Coefficient", + enable=false)); + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the volume)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Real f_relativeFillingLevel(min=0, max=1, final unit="1") + "Relative filling level of the condenser" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The heat transfer model is used to describe (pool) condensation by connection a phase +seperator volume with a heat source/sink, such as a heat exchanger tube. Thus, +the pool condensation heat transfer model represents a thermal resistance betweed +two models. Depending on the attached temperatures (i.e., attached potential) +and the chosen transport phenomena, this model determines the heat flow rate +between the connected models. +<br/><br/> +The model has two heat ports, which sizes can be defined via a parameter. The +scalable heat ports enable the connection of various models. For example, this +enables to connect a discretized model to a lumped model, or two different +disretized models. +</p> + +<h4>Main equations</h4> +<p> +The model has steady-state energy balance: +</p> +<pre> + 0 = ∑ (hp_a.Q_flow) + ∑ (hp_b.Q_flow); +</pre> +<p> +The heat flow rate <i>Q_flow</i> is proportional to the driving temperature +difference <i>ΔT = hp_a.T - hp_b.T</i> and the production of heat transfer +coefficient and area <i>αA</i>, which can be formulated as thermal resistance +<i>R<sub>condensation</sub></i>. This product can be given as an input or calculated using +models describing heat transfer coefficient correlations. +</p> +<pre> + hp_a.Q_flow = αA * ΔT = 1 / R<sub>condensation</sub> * (hp_a.T - hp_b.T); +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> + <li> + The number of ports a and b must be an even integer multiple of each other. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The (pool) condensation heat transfer is typically used to desribe the heat transfer +within a condenser. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useAlphaAInput</i>: + Defines if the product of heat transfer coefficient and area is given via + an input or calculated using an approproate correlation model for the heat + transfer coefficient. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 18, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Text( + extent={{-60,20},{60,-20}}, + lineColor={0,0,0}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={238,46,47}, + textString="Q_flow = 1/R_condensation * DT")})); +end PoolCondensationHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/RadiationHeatTransfer.mo b/SorpLib/Components/HeatTransfer/RadiationHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..360f1044d078f753645b0963c76535809a0531f5 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/RadiationHeatTransfer.mo @@ -0,0 +1,87 @@ +within SorpLib.Components.HeatTransfer; +model RadiationHeatTransfer + "Model calculating a radiation heat transfer" + extends BaseClasses.PartialHeatTransfer( + final exponetTemperature=4, + redeclare replaceable model HeatTransferCoefficient = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Radiation.ConstantResistance + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialRadiationHeatTransferCoefficient); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The heat transfer model is used to thermally connect models which can exchange +heat due to thermal radiation. Thus, the radiation heat transfer model represents +a thermal resistance betweed two models. Depending on the attached temperatures (i.e., +attached potential) and the chosen transport phenomena, this model determines the +heat flow rate between the connected models. +<br/><br/> +The model has two heat ports, which sizes can be defined via a parameter. The +scalable heat ports enable the connection of various models. For example, this +enables to connect a discretized model to a lumped model, or two different +disretized models. +</p> + +<h4>Main equations</h4> +<p> +The model has steady-state energy balance: +</p> +<pre> + 0 = ∑ (hp_a.Q_flow) + ∑ (hp_b.Q_flow); +</pre> +<p> +The heat flow rate <i>Q_flow</i> is proportional to the driving temperature +difference <i>ΔT = hp_a.T<sup>4</sup> - hp_b.T<sup>4</sup></i> and the production +of heat transfer coefficient and area <i>αA</i>, which can be formulated as +thermal resistance <i>R<sub>σ</sub></i>. This product can be given as an input +or calculated using models describing heat transfer coefficient correlations. +</p> +<pre> + hp_a.Q_flow = αA * ΔT = 1 / R<sub>σ</sub> * (hp_a.T<sup>4</sup> - hp_b.T<sup>4</sup>); +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> + <li> + The number of ports a and b must be an even integer multiple of each other. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The conductive heat transfer is typically used to desribe the heat transfer between +two components. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useAlphaAInput</i>: + Defines if the product of heat transfer coefficient and area is given via + an input or calculated using an approproate correlation model for the heat + transfer coefficient. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 16, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Text( + extent={{-60,20},{60,-20}}, + lineColor={0,0,0}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={238,46,47}, + textString="Q_flow = 1/R_sigma * DT")})); +end RadiationHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/Records/FluidProperties.mo b/SorpLib/Components/HeatTransfer/Records/FluidProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..02ed664343f57b967a056b0d08fbc265c5ffede1 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Records/FluidProperties.mo @@ -0,0 +1,38 @@ +within SorpLib.Components.HeatTransfer.Records; +record FluidProperties + "This record contains fluid properties required for heat transfer coefficients" + extends Modelica.Icons.Record; + + // + // Definition of variables describing fluid properties + // + Modelica.Units.SI.Pressure p + "Pressure"; + Modelica.Units.SI.Temperature T + "Temperature"; + Modelica.Units.SI.Density rho + "Density"; + + Modelica.Units.SI.SpecificHeatCapacity cp + "Isobaric specific heat capacity"; + Modelica.Units.SI.DynamicViscosity eta + "Dynamic viscosity"; + Modelica.Units.SI.ThermalConductivity lambda + "Thermal conductivity"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains fluid properties required for heat transfer coefficients. +</p> +</html>", revisions="<html> +<ul> + <li> + January 15, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end FluidProperties; diff --git a/SorpLib/Components/HeatTransfer/Records/GeometryClosedAdsorber.mo b/SorpLib/Components/HeatTransfer/Records/GeometryClosedAdsorber.mo new file mode 100644 index 0000000000000000000000000000000000000000..5a195e5fcb7f0b10aa1a69dc27735c4606c6f663 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Records/GeometryClosedAdsorber.mo @@ -0,0 +1,22 @@ +within SorpLib.Components.HeatTransfer.Records; +record GeometryClosedAdsorber + "This record contains the geometry required for heat transfer coefficients of closed adsorbers" + extends SorpLib.Components.HeatExchanger.Records.GeometryClosedAdsorber; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters required by models calculating the heat +transfer coefficients of closed adsorbers. +</p> +</html>", revisions="<html> +<ul> + <li> + January 22, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryClosedAdsorber; diff --git a/SorpLib/Components/HeatTransfer/Records/GeometryOpenAdsorber.mo b/SorpLib/Components/HeatTransfer/Records/GeometryOpenAdsorber.mo new file mode 100644 index 0000000000000000000000000000000000000000..e5ccba3a07d34f5a18bd398850b9059126659559 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Records/GeometryOpenAdsorber.mo @@ -0,0 +1,222 @@ +within SorpLib.Components.HeatTransfer.Records; +record GeometryOpenAdsorber + "This record contains the geometry required for heat transfer coefficients of open adsorbers" + extends Modelica.Icons.Record; + + // + // Definition of parameters regarding the disretization + // + parameter Integer no_volumes(min=1) = 1 + "Number of discretization volumes in flow direction" + annotation (Dialog(tab="General", group="Discretization", enable=false)); + + // + // Definition of parameters regarding the geometry of the casing + // + parameter Modelica.Units.SI.Length l_cas = 1 + "Length of the casing" + annotation (Dialog(tab="Casing", group="General")); + + parameter Modelica.Units.SI.Diameter d_inner_cas = 0.15 + "Inner diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_outer_cas = 0.16 + "Outer diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + parameter Modelica.Units.SI.Thickness t_wall_cas= + (d_outer_cas - d_inner_cas) / 2 + "Wall thickness of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + + parameter Modelica.Units.SI.Area A_crossInner_cas= + Modelica.Constants.pi/4 * d_inner_cas^2 + "Inner cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_crossOuter_cas= + Modelica.Constants.pi/4 * d_outer_cas^2 + "Outer cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_crossWall_cas= + A_crossOuter_cas - A_crossInner_cas + "Wall cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferInner_cas= + Modelica.Constants.pi * d_inner_cas * l_cas + "Inner heat transfer area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferOuter_cas= + Modelica.Constants.pi * d_outer_cas * l_cas + "Outer heat transfer area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + + parameter Modelica.Units.SI.Volume V_inner_cas= + Modelica.Constants.pi/4 * d_inner_cas * l_cas + "Inner volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_outer_cas= + Modelica.Constants.pi/4 * d_outer_cas * l_cas + "Outer volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_wall_cas= + V_outer_cas - V_inner_cas + "Wall volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_free_cas= + V_inner_cas - V_inner_hx - V_outer_hx - V_sorbent_hx + "Free volume (i.e., gas/vapor volume) of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + + // + // Definition of parameters regarding the general geometry of the heat exchanger + // + parameter Integer no_hydraulicParallelTubes(min=1) = 1 + "Number of hydraulically parallel tubes" + annotation (Dialog(tab="Heat Exchanger", group="General")); + + parameter Modelica.Units.SI.Length l_hx = 0 + "Length of the tube" + annotation (Dialog(tab="Heat Exchanger", group="General")); + + parameter Modelica.Units.SI.Length roughness_hx = 0 + "Absolute roughness of the tube" + annotation (Dialog(tab="Heat Exchanger", group="General")); + + // + // Definition of parameters regarding diameters of the heat exchanger + // + parameter Modelica.Units.SI.Diameter d_inner_hx = 0 + "Inner diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_outer_hx = 0 + "Outer diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + + parameter Modelica.Units.SI.Diameter d_hydInner_hx = d_inner_hx + "Hydraulic inner diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_hydOuter_hx = d_outer_hx + "Hydraulic outer diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + + parameter Modelica.Units.SI.Thickness t_wall_hx= + (d_outer_hx - d_inner_hx) / 2 + "Wall thickness of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + + // + // Definition of parameters regarding areas of the heat exchanger + // + parameter Modelica.Units.SI.Area A_crossInner_hx= + Modelica.Constants.pi/4 * d_inner_hx^2 + "Inner cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_crossOuter_hx= + Modelica.Constants.pi/4 * d_outer_hx^2 + "Outer cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_crossWall_hx= + A_crossOuter_hx - A_crossInner_hx + "Wall cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + + parameter Modelica.Units.SI.Area A_hydCrossInner_hx = A_crossInner_hx + "Hydraulic inner cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossOuter_hx = A_crossOuter_hx + "Hydraulic outer cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossWall_hx= + A_hydCrossOuter_hx - A_hydCrossInner_hx + "Hydraulic wall cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + + parameter Modelica.Units.SI.Area A_heatTransferInner_hx= + Modelica.Constants.pi * d_inner_hx * l_hx + "Total inner heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferOuter_hx= + Modelica.Constants.pi * d_outer_hx * l_hx + "Total outer heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + + parameter Real f_finAreaRatioInner_hx(min=0, max=1) = 0 + "Ratio of total inner fin area to total inner heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Real f_finAreaRatioOuter_hx(min=0, max=1) = 0 + "Ratio of total outer fin area to total outer heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + + // + // Definition of parameters regarding volumes of the heat exchanger + // + parameter Modelica.Units.SI.Volume V_inner_hx = A_crossInner_hx * l_hx + "Total inner volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_outer_hx = A_crossOuter_hx * l_hx + "Total outer volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_wall_hx = V_outer_hx - V_inner_hx + "Total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_sorbent_hx= + 2.5 * V_wall_hx + "Available volume for sorbent particles of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + + parameter Real f_finVolumeRatioInner_hx(min=0, max=1) = 0 + "Ratio of total inner fin volume to total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Real f_finVolumeRatioOuter_hx(min=0, max=1) = 0 + "Ratio of total outer fin volume to total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + + // + // Definition of parameters regarding the sorbent gemeotry + // + parameter Real no_particles = (1-psi_particles) * V_inner_cas / V_particle + "Number of particles" + annotation (Dialog(tab="Sorbent", group="General")); + parameter Real psi_particles(unit="1") = 1 - 0.74 + "Void fraction of the adsorber (i.e., ratio of the free fluid volume to + the total inner volume)" + annotation (Dialog(tab="Sorbent", group="General")); + + parameter Modelica.Units.SI.Diameter d_particle = 0.7 / 1000 + "Average diameter of the adsorbent particles" + annotation (Dialog(tab="Sorbent", group="Diameters")); + + parameter Modelica.Units.SI.Area A_cross_particle= + Modelica.Constants.pi/4 * d_particle^2 + "Average cross-sectional area of the particle" + annotation (Dialog(tab="Sorbent", group="Areas")); + parameter Modelica.Units.SI.Area A_surface_particle= + Modelica.Constants.pi * d_particle^2 + "Average suraface area of the particle" + annotation (Dialog(tab="Sorbent", group="Areas")); + + parameter Modelica.Units.SI.Volume V_particle= + Modelica.Constants.pi/6 * d_particle^3 + "Average volume of the particle" + annotation (Dialog(tab="Sorbent", group="Volumes")); + parameter Modelica.Units.SI.Volume V_particles= + no_particles * V_particle + "Average volume of all particles" + annotation (Dialog(tab="Sorbent", group="Volumes")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters required by models calculating the heat +transfer coefficients at the inside or outside of open adsorbers. +</p> +</html>", revisions="<html> +<ul> + <li> + January 23, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryOpenAdsorber; diff --git a/SorpLib/Components/HeatTransfer/Records/GeometryTube.mo b/SorpLib/Components/HeatTransfer/Records/GeometryTube.mo new file mode 100644 index 0000000000000000000000000000000000000000..91d6f5e493bf30e506a8f17e4afee021572b73ef --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Records/GeometryTube.mo @@ -0,0 +1,22 @@ +within SorpLib.Components.HeatTransfer.Records; +record GeometryTube + "This record contains the geometry required for heat transfer coefficients of tubes" + extends SorpLib.Components.Tubes.Records.GeometryTube; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters required by models calculating the heat +transfer coefficients at the inside or outside of tubes. +</p> +</html>", revisions="<html> +<ul> + <li> + January 17, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryTube; diff --git a/SorpLib/Components/HeatTransfer/Records/package.mo b/SorpLib/Components/HeatTransfer/Records/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d839bb4b9e878c94aa2b2fca33889412e7835613 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Records/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.HeatTransfer; +package Records "Package containing records" + extends Modelica.Icons.RecordsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains definitions of records. These records are used to cluster +variables and tidy up the model output. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Records; diff --git a/SorpLib/Components/HeatTransfer/Records/package.order b/SorpLib/Components/HeatTransfer/Records/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e3da0908d7f39e8eb868e67a3a8d07e4c37a8ba6 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Records/package.order @@ -0,0 +1,4 @@ +FluidProperties +GeometryTube +GeometryClosedAdsorber +GeometryOpenAdsorber diff --git a/SorpLib/Components/HeatTransfer/Tester/Test_ClosedAdsorberHeatTransfer.mo b/SorpLib/Components/HeatTransfer/Tester/Test_ClosedAdsorberHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..c04ef116e1f166d7deb91cff594d2c48a9a9239f --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Tester/Test_ClosedAdsorberHeatTransfer.mo @@ -0,0 +1,121 @@ +within SorpLib.Components.HeatTransfer.Tester; +model Test_ClosedAdsorberHeatTransfer + "Tester for the heat transfer between sorbent and wall in closed adsorbers" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Thermal.HeatSource heatSource( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=true, + use_QFlowInput=false) + "Heat source for fluid volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,60}))); + + // + // Definition of heat transfer models + // + SorpLib.Components.HeatTransfer.ClosedAdsorberHeatTransfer heatTransfer( + redeclare model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.ClosedAdsorber.LinearAlphaA ( + constantAlphaA=500, b=2), fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=adsorbateVolume.adsorbateProperties.p, + T=adsorbateVolume.adsorbateProperties.T, + rho=1/adsorbateVolume.workingPair.medium_sorbent.state_variables.v, + cp=adsorbateVolume.workingPair.medium_sorbent.additional_variables.c, + eta=0, + lambda=adsorbateVolume.workingPair.medium_sorbent.additional_variables.lambda)) + "Heat transfer model" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,40}))); + + // + // Definition of liquid volume models + // + Basics.Volumes.AdsorbateVolumes.AdsorbatePureVLEVolume adsorbateVolume( + T_initial=373.15, + useHeatPorts=false, + useHeatPortsX=false, + geometry(V=Modelica.Constants.pi/4*0.1^2*1), + redeclare model PureWorkingPairModel = + Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl, + limitLowerPressure=true, + limitLowerPressureAdsorptive=true), + x_initial=0.05, + redeclare final package Medium = Medium) + "Model of an adsorbate volume" + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={0,0}))); + + // + // Definition of thermal boundaries + // +protected + Modelica.Blocks.Sources.Sine input_T( + amplitude=50, + f=1/250, + offset=273.15 + 75) "Input for temperature" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={0,80}))); + +equation + // + // Connections + // + connect(heatSource.port, heatTransfer.hp_b[1]) annotation (Line( + points={{0,60},{0,48}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer.hp_a[1], adsorbateVolume.hp_sorption) annotation (Line( + points={{0,32},{0,28},{3.2,28},{3.2,15.2}}, + color={238,46,47}, + thickness=1)); + + connect(input_T.y, heatSource.T_input) annotation (Line(points={{0,69},{0,64}, + {5.2,64},{5.2,61}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the heat transfer between sorbent and wall within closed +adsorbers. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 22, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_ClosedAdsorberHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/Tester/Test_ConductionHeatTransfer.mo b/SorpLib/Components/HeatTransfer/Tester/Test_ConductionHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..6bdd671df2c644c7f8e0c243fe9f194849531f73 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Tester/Test_ConductionHeatTransfer.mo @@ -0,0 +1,354 @@ +within SorpLib.Components.HeatTransfer.Tester; +model Test_ConductionHeatTransfer + "Tester for the conduction heat transfer" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Modelica.Units.SI.Pressure p = 1e5 + "Constant pressure" + annotation (Dialog(tab="General", group="Case Study")); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Thermal.HeatSource hs_a1(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,30},{-50,50}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b1(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,30},{50,50}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_a2(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,10},{-50,30}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b2(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,10},{50,30}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_a3(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b3(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_a4(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,-30},{-50,-10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b4(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,-30},{50,-10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_a5(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,-50},{-50,-30}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b5(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,-50},{50,-30}}))); + + // + // Definition of heat transfer models + // + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_a1(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantResistance, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall1.solidProperties.p, + T=wall1.solidProperties.T, + rho=1/wall1.solidProperties.v, + cp=wall1.solidProperties.c, + eta=0, + lambda=wall1.solidProperties.lambda)) + "Heat transfer at heat source a" + annotation (Placement(transformation(extent={{-40,30},{-20,50}}))); + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_b1(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantResistance, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall1.solidProperties.p, + T=wall1.solidProperties.T, + rho=1/wall1.solidProperties.v, + cp=wall1.solidProperties.c, + eta=0, + lambda=wall1.solidProperties.lambda)) + "Heat transfer at heat source b" + annotation (Placement(transformation(extent={{20,30},{40,50}}))); + + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_a2(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantPlainWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall2.solidProperties.p, + T=wall2.solidProperties.T, + rho=1/wall2.solidProperties.v, + cp=wall2.solidProperties.c, + eta=0, + lambda=wall2.solidProperties.lambda)) + "Heat transfer at heat source a" + annotation (Placement(transformation(extent={{-40,10},{-20,30}}))); + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_b2(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantPlainWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall2.solidProperties.p, + T=wall2.solidProperties.T, + rho=1/wall2.solidProperties.v, + cp=wall2.solidProperties.c, + eta=0, + lambda=wall2.solidProperties.lambda)) + "Heat transfer at heat source b" + annotation (Placement(transformation(extent={{20,10},{40,30}}))); + + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_a3(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantCylindricalWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall3.solidProperties.p, + T=wall3.solidProperties.T, + rho=1/wall3.solidProperties.v, + cp=wall3.solidProperties.c, + eta=0, + lambda=wall3.solidProperties.lambda)) + "Heat transfer at heat source a" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_b3(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantCylindricalWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall3.solidProperties.p, + T=wall3.solidProperties.T, + rho=1/wall3.solidProperties.v, + cp=wall3.solidProperties.c, + eta=0, + lambda=wall3.solidProperties.lambda)) + "Heat transfer at heat source b" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_a4(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.PlainWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall4.solidProperties.p, + T=wall4.solidProperties.T, + rho=1/wall4.solidProperties.v, + cp=wall4.solidProperties.c, + eta=0, + lambda=wall4.solidProperties.lambda)) + "Heat transfer at heat source a" + annotation (Placement(transformation(extent={{-40,-30},{-20,-10}}))); + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_b4(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.PlainWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall4.solidProperties.p, + T=wall4.solidProperties.T, + rho=1/wall4.solidProperties.v, + cp=wall4.solidProperties.c, + eta=0, + lambda=wall4.solidProperties.lambda)) + "Heat transfer at heat source b" + annotation (Placement(transformation(extent={{20,-30},{40,-10}}))); + + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_a5(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.CylindricalWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall5.solidProperties.p, + T=wall5.solidProperties.T, + rho=1/wall5.solidProperties.v, + cp=wall5.solidProperties.c, + eta=0, + lambda=wall5.solidProperties.lambda)) + "Heat transfer at heat source a" + annotation (Placement(transformation(extent={{-40,-50},{-20,-30}}))); + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_b5(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.CylindricalWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall5.solidProperties.p, + T=wall5.solidProperties.T, + rho=1/wall5.solidProperties.v, + cp=wall5.solidProperties.c, + eta=0, + lambda=wall5.solidProperties.lambda)) + "Heat transfer at heat source b" + annotation (Placement(transformation(extent={{20,-50},{40,-30}}))); + + // + // Definition of wall models + // + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume wall1( + solidMedium(approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.GeneralizedFunction), + T_initial=298.15, + p=p) "Wall model" + annotation (Placement(transformation(extent={{-10,30},{10,50}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume wall2( + solidMedium(approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.GeneralizedFunction), + T_initial=298.15, + p=p) "Wall model" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume wall3( + solidMedium(approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.GeneralizedFunction), + T_initial=298.15, + p=p) "Wall model" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume wall4( + solidMedium(approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.GeneralizedFunction), + T_initial=298.15, + p=p) "Wall model" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume wall5( + solidMedium(approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.GeneralizedFunction), + T_initial=298.15, + p=p) "Wall model" + annotation (Placement(transformation(extent={{-10,-50},{10,-30}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_T_a( + amplitude=50, + f=1/250, + offset=273.15 + 50) + "Input signal for temperature at sources a" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + + Modelica.Blocks.Sources.Trapezoid input_T_b( + amplitude=100, + rising=50, + width=100, + falling=50, + period=250, + offset=273.15) + "Input signal for temperature at sources b" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(hs_a1.port, ht_a1.hp_a[1]) annotation (Line( + points={{-60,40},{-38,40}}, + color={238,46,47}, + thickness=1)); + connect(ht_a1.hp_b[1], wall1.hp_xMinus) annotation (Line( + points={{-22,40},{-6,40}}, + color={238,46,47}, + thickness=1)); + connect(wall1.hp_xPlus, ht_b1.hp_a[1]) annotation (Line( + points={{6,40},{22,40}}, + color={238,46,47}, + thickness=1)); + connect(ht_b1.hp_b[1], hs_b1.port) annotation (Line( + points={{38,40},{60,40}}, + color={238,46,47}, + thickness=1)); + connect(hs_a2.port, ht_a2.hp_a[1]) annotation (Line( + points={{-60,20},{-38,20}}, + color={238,46,47}, + thickness=1)); + connect(ht_a2.hp_b[1], wall2.hp_xMinus) annotation (Line( + points={{-22,20},{-6,20}}, + color={238,46,47}, + thickness=1)); + connect(wall2.hp_xPlus, ht_b2.hp_a[1]) annotation (Line( + points={{6,20},{22,20}}, + color={238,46,47}, + thickness=1)); + connect(ht_b2.hp_b[1], hs_b2.port) annotation (Line( + points={{38,20},{60,20}}, + color={238,46,47}, + thickness=1)); + connect(hs_a3.port, ht_a3.hp_a[1]) annotation (Line( + points={{-60,0},{-38,0}}, + color={238,46,47}, + thickness=1)); + connect(ht_a3.hp_b[1], wall3.hp_xMinus) annotation (Line( + points={{-22,0},{-6,0}}, + color={238,46,47}, + thickness=1)); + connect(wall3.hp_xPlus, ht_b3.hp_a[1]) annotation (Line( + points={{6,0},{22,0}}, + color={238,46,47}, + thickness=1)); + connect(ht_b3.hp_b[1], hs_b3.port) annotation (Line( + points={{38,0},{60,0}}, + color={238,46,47}, + thickness=1)); + connect(hs_a4.port, ht_a4.hp_a[1]) annotation (Line( + points={{-60,-20},{-38,-20}}, + color={238,46,47}, + thickness=1)); + connect(ht_a4.hp_b[1], wall4.hp_xMinus) annotation (Line( + points={{-22,-20},{-6,-20}}, + color={238,46,47}, + thickness=1)); + connect(wall4.hp_xPlus, ht_b4.hp_a[1]) annotation (Line( + points={{6,-20},{22,-20}}, + color={238,46,47}, + thickness=1)); + connect(ht_b4.hp_b[1], hs_b4.port) annotation (Line( + points={{38,-20},{60,-20}}, + color={238,46,47}, + thickness=1)); + connect(hs_a5.port, ht_a5.hp_a[1]) annotation (Line( + points={{-60,-40},{-38,-40}}, + color={238,46,47}, + thickness=1)); + connect(ht_a5.hp_b[1], wall5.hp_xMinus) annotation (Line( + points={{-22,-40},{-6,-40}}, + color={238,46,47}, + thickness=1)); + connect(wall5.hp_xPlus, ht_b5.hp_a[1]) annotation (Line( + points={{6,-40},{22,-40}}, + color={238,46,47}, + thickness=1)); + connect(ht_b5.hp_b[1], hs_b5.port) annotation (Line( + points={{38,-40},{60,-40}}, + color={238,46,47}, + thickness=1)); + + connect(input_T_a.y, hs_a1.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,45.2},{-61,45.2}}, color={0,0,127})); + connect(input_T_b.y, hs_b1.T_input) annotation (Line(points={{79,0},{70,0},{70, + 45.2},{61,45.2}}, color={0,0,127})); + connect(input_T_a.y, hs_a2.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,25.2},{-61,25.2}}, color={0,0,127})); + connect(input_T_a.y, hs_a3.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,5.2},{-61,5.2}}, color={0,0,127})); + connect(input_T_a.y, hs_a4.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,-14.8},{-61,-14.8}}, color={0,0,127})); + connect(input_T_a.y, hs_a5.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,-34.8},{-61,-34.8}}, color={0,0,127})); + connect(input_T_b.y, hs_b2.T_input) annotation (Line(points={{79,0},{70,0},{70, + 25.2},{61,25.2}}, color={0,0,127})); + connect(input_T_b.y, hs_b3.T_input) annotation (Line(points={{79,0},{70,0},{70, + 5.2},{61,5.2}}, color={0,0,127})); + connect(input_T_b.y, hs_b4.T_input) annotation (Line(points={{79,0},{70,0},{70, + -14.8},{61,-14.8}}, color={0,0,127})); + connect(input_T_b.y, hs_b5.T_input) annotation (Line(points={{79,0},{70,0},{70, + -34.8},{61,-34.8}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the conduction heat transfer. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 15, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_ConductionHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/Tester/Test_GenericHeatTransfer.mo b/SorpLib/Components/HeatTransfer/Tester/Test_GenericHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..ba2edc132e0d60a39e7f49b68141cfd40cda9568 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Tester/Test_GenericHeatTransfer.mo @@ -0,0 +1,184 @@ +within SorpLib.Components.HeatTransfer.Tester; +model Test_GenericHeatTransfer + "Tester for the generic heat transfer" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Thermal.HeatSource hs_a1(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,30},{-50,50}}))); + + SorpLib.Basics.Sources.Thermal.HeatSource hs_b1(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,30},{50,50}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_a2(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,10},{-50,30}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b2(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,10},{50,30}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_a3(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b3(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_a4(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,-30},{-50,-10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b4(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,-30},{50,-10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_a5(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,-50},{-50,-30}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b5(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,-50},{50,-30}}))); + + // + // Definition of heat transfer models + // + SorpLib.Components.HeatTransfer.GenericHeatTransfer heatTransfer_1( + redeclare model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Generic.ConstantAlpha ( + constantAlpha=25, A=1)) + "Heat transfer model 1" + annotation (Placement(transformation(extent={{-10,30},{10,50}}))); + SorpLib.Components.HeatTransfer.GenericHeatTransfer heatTransfer_2(redeclare + model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Generic.ConstantAlphaA ( + constantAlphaA=25)) + "Heat transfer model 2" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + SorpLib.Components.HeatTransfer.GenericHeatTransfer heatTransfer_3(redeclare + model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Generic.LinearAlphaA ( + constantAlphaA=25, b=0.1)) + "Heat transfer model 3" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + SorpLib.Components.HeatTransfer.GenericHeatTransfer heatTransfer_4(redeclare + model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Generic.ExponentialAlphaA ( + constantAlphaA=25, + b=0.5, + c=1/273.15)) + "Heat transfer model 4" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + SorpLib.Components.HeatTransfer.GenericHeatTransfer heatTransfer_5(redeclare + model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Generic.PolynomialAlphaA ( + constantAlphaA=25, + b=0.5, + c=1/3)) + "Heat transfer model 5" + annotation (Placement(transformation(extent={{-10,-50},{10,-30}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_T_a( + amplitude=50, + f=1/250, + offset=273.15 + 50) + "Input signal for temperature at sources a" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + + Modelica.Blocks.Sources.Trapezoid input_T_b( + amplitude=100, + rising=50, + width=100, + falling=50, + period=250, + offset=273.15) + "Input signal for temperature at sources b" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(hs_a1.port, heatTransfer_1.hp_a[1]) annotation (Line( + points={{-60,40},{-8,40}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_1.hp_b[1], hs_b1.port) annotation (Line( + points={{8,40},{60,40}}, + color={238,46,47}, + thickness=1)); + connect(hs_a2.port, heatTransfer_2.hp_a[1]) annotation (Line( + points={{-60,20},{-8,20}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_2.hp_b[1], hs_b2.port) annotation (Line( + points={{8,20},{60,20}}, + color={238,46,47}, + thickness=1)); + connect(hs_a3.port, heatTransfer_3.hp_a[1]) annotation (Line( + points={{-60,0},{-8,0}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_3.hp_b[1], hs_b3.port) annotation (Line( + points={{8,0},{60,0}}, + color={238,46,47}, + thickness=1)); + connect(hs_a4.port, heatTransfer_4.hp_a[1]) annotation (Line( + points={{-60,-20},{-8,-20}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_4.hp_b[1], hs_b4.port) annotation (Line( + points={{8,-20},{60,-20}}, + color={238,46,47}, + thickness=1)); + connect(hs_a5.port, heatTransfer_5.hp_a[1]) annotation (Line( + points={{-60,-40},{-8,-40}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_5.hp_b[1], hs_b5.port) annotation (Line( + points={{8,-40},{60,-40}}, + color={238,46,47}, + thickness=1)); + + connect(input_T_a.y, hs_a1.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,45.2},{-61,45.2}}, color={0,0,127})); + connect(input_T_b.y, hs_b1.T_input) annotation (Line(points={{79,0},{70,0},{70, + 45.2},{61,45.2}}, color={0,0,127})); + connect(input_T_a.y, hs_a2.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,25.2},{-61,25.2}}, color={0,0,127})); + connect(input_T_a.y, hs_a3.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,5.2},{-61,5.2}}, color={0,0,127})); + connect(input_T_a.y, hs_a4.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,-14.8},{-61,-14.8}}, color={0,0,127})); + connect(input_T_a.y, hs_a5.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,-34.8},{-61,-34.8}}, color={0,0,127})); + connect(input_T_b.y, hs_b2.T_input) annotation (Line(points={{79,0},{70,0},{70, + 25.2},{61,25.2}}, color={0,0,127})); + connect(input_T_b.y, hs_b3.T_input) annotation (Line(points={{79,0},{70,0},{70, + 5.2},{61,5.2}}, color={0,0,127})); + connect(input_T_b.y, hs_b4.T_input) annotation (Line(points={{79,0},{70,0},{70, + -14.8},{61,-14.8}}, color={0,0,127})); + connect(input_T_b.y, hs_b5.T_input) annotation (Line(points={{79,0},{70,0},{70, + -34.8},{61,-34.8}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the generic heat transfer. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 12, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GenericHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/Tester/Test_OpenAdsorberHeatTransfer.mo b/SorpLib/Components/HeatTransfer/Tester/Test_OpenAdsorberHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..3fe572ec59f7e8cc96ad349ebb524bbcfdd7c8b7 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Tester/Test_OpenAdsorberHeatTransfer.mo @@ -0,0 +1,183 @@ +within SorpLib.Components.HeatTransfer.Tester; +model Test_OpenAdsorberHeatTransfer + "Tester for the heat transfer between gas and sorbent/casing in open adsorbers" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture + "Medium model" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_inlet( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=323.15, + redeclare final package Medium = Medium) + "Inlet fluid source" + annotation (Placement(transformation(extent={{-50,-10},{-30,10}}))); + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_outlet( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + T_fixed=373.15, + redeclare final package Medium = Medium) + "Outlet fluid source" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); + + // + // Definition of heat transfer models + // + SorpLib.Components.HeatTransfer.OpenAdsorberHeatTransfer heatTransfer_gasCasing( + redeclare model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.OpenAdsorber.CasingGasKast, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=gasVolume.fluidProperties.p, + T=gasVolume.fluidProperties.T, + rho=1/gasVolume.fluidProperties.v, + cp=gasVolume.fluidProperties.cp, + eta=gasVolume.fluidProperties.eta, + lambda=gasVolume.fluidProperties.lambda), + m_hyd_xMinus=gasVolume.fluidProperties.mc_flow_xMinus, + m_hyd_xPlus=gasVolume.fluidProperties.mc_flow_xPlus) + "Heat transfer model between gas and casing" annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,32}))); + + SorpLib.Components.HeatTransfer.OpenAdsorberHeatTransfer heatTransfer_gasSorbent( + redeclare model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.OpenAdsorber.CasingSorbentKast, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=gasVolume.fluidProperties.p, + T=gasVolume.fluidProperties.T, + rho=1/gasVolume.fluidProperties.v, + cp=gasVolume.fluidProperties.cp, + eta=gasVolume.fluidProperties.eta, + lambda=gasVolume.fluidProperties.lambda), + m_hyd_xMinus=gasVolume.fluidProperties.mc_flow_xMinus, + m_hyd_xPlus=gasVolume.fluidProperties.mc_flow_xPlus) + "Heat transfer model between gas and sorbent" annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,-32}))); + + // + // Definition of volume models + // + SorpLib.Basics.Volumes.AdsorbateVolumes.AdsorbatePureGasVolume adsorbateVolume( + T_initial=323.15, + useHeatPorts=false, + useHeatPortsX=false, + geometry(V=(1-heatTransfer_gasSorbent.geometry.psi_particles)*heatTransfer_gasSorbent.geometry.V_inner_cas), + redeclare model PureWorkingPairModel = + Media.WorkingPairs.PureComponents.H2O.Zeolith13X_Toth_WangDouglasLeVan2010_Gas, + x_initial=0.05) + "Model of an adsorbate volume" + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={0,-70}))); + + SorpLib.Basics.Volumes.FluidVolumes.GasVaporMixtureVolume gasVolume( + geometry(V=heatTransfer_gasSorbent.geometry.V_free_cas), + calculateAdditionalProperties=true, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFreeInitial, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1, + redeclare final package Medium = Medium) + "Model of the gas volume" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}))); + + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume wallVolume( + p = gasVolume.fluidProperties.p, + T_initial=323.15, + useHeatPortsX=false, + useHeatPortsY=true, + geometry(V=heatTransfer_gasSorbent.geometry.V_wall_cas)) + "Model of the wall volume" + annotation (Placement( + transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={0,70}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_mFlow( + amplitude=1, + f=1/250, + startTime=250) "Input for mass flow rate" annotation (Placement( + transformation( + extent={{10,10},{-10,-10}}, + rotation=180, + origin={-70,0}))); + +equation + // + // Connections + // + connect(fs_inlet.port, gasVolume.cfp_xMinus[1]) annotation (Line( + points={{-40,0},{-30,0},{-30,3.6},{-8.4,3.6}}, + color={244,125,35}, + thickness=1)); + connect(fs_outlet.port, gasVolume.cfp_xPlus[1]) annotation (Line( + points={{40,0},{30,0},{30,3.6},{15.6,3.6}}, + color={244,125,35}, + thickness=1)); + + connect(wallVolume.hp_yMinus, heatTransfer_gasCasing.hp_b[1]) annotation ( + Line( + points={{0,58},{0,40}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_gasCasing.hp_a[1], gasVolume.hp_yPlus) annotation (Line( + points={{0,24},{0,12}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_gasSorbent.hp_a[1], gasVolume.hp_sorption) annotation ( + Line( + points={{0,-24},{0,-20},{3.2,-20},{3.2,-8.8}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_gasSorbent.hp_b[1], adsorbateVolume.hp_sorption) + annotation (Line( + points={{0,-40},{0,-44},{3.2,-44},{3.2,-54.8}}, + color={238,46,47}, + thickness=1)); + + connect(input_mFlow.y, fs_inlet.m_flow_input) annotation (Line(points={{-59,0}, + {-50,0},{-50,2},{-41.2,2}}, color={0,0,127})); + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the heat transfer between gas and sorbent/casing within +open adsorbers. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 23, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_OpenAdsorberHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/Tester/Test_PoolBoilingHeatTransfer.mo b/SorpLib/Components/HeatTransfer/Tester/Test_PoolBoilingHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..104919e3c8e99826015d397582bd6e6683ae2a8c --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Tester/Test_PoolBoilingHeatTransfer.mo @@ -0,0 +1,173 @@ +within SorpLib.Components.HeatTransfer.Tester; +model Test_PoolBoilingHeatTransfer + "Tester for the pool boiling heat transfer" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the VLE liquid" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource liquidInlet( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_mFlowInput=true, + m_flow_fixed=-0.001, + h_fixed=0.5e6, + redeclare package Medium = Medium) + "Liquid inlet for phase seprator volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-40}))); + SorpLib.Basics.Sources.Fluids.VLESource vaporInlet( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_mFlowInput=true, + m_flow_fixed=1e-3, + h_fixed=1e-6, + redeclare package Medium = Medium) + "Vapor inlet for phase separator" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={0,40}))); + + SorpLib.Basics.Sources.Thermal.HeatSource heatSource( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=true, + use_QFlowInput=false) + "Heat source for phase seperator volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={60,0}))); + + // + // Definition of heat transfer models + // + SorpLib.Components.HeatTransfer.PoolBoilingHeatTransfer heatTransfer( + redeclare model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.PoolBoiling.LinearAlphaA_fRel, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=phaseSeparator.p, + T=phaseSeparator.T, + rho=phaseSeparator.rho, + cp=phaseSeparator.phaseSepratorProperties.cp, + eta=phaseSeparator.phaseSepratorProperties.eta, + lambda=phaseSeparator.phaseSepratorProperties.lambda), + f_relativeFillingLevel=phaseSeparator.l_liq_rel) "Heat transfer model" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); + + // + // Definition of VLE models + // + SorpLib.Basics.Volumes.PhaseSeparatorVolumes.PhaseSeparatorVolume + phaseSeparator( + T_initial=293.15, + rho_initial=500, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + calculateAdditionalProperties=true, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1) "Model of a phase seperator volume" annotation ( + Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=90, + origin={0,0}))); + + // + // Definition of fluid boundaries + // +protected + Modelica.Blocks.Sources.Trapezoid input_liquidPort( + amplitude=-0.0001, + rising=250, + width=400, + falling=250, + period=950, + startTime=50) + "Input for liquid port boundary" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-30,-70}))); + Modelica.Blocks.Sources.Ramp input_vaporPort( + height=0.0001, + duration=250, + startTime=500) + "Input for vapor Port" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-30,70}))); + + // + // Definition of thermal boundaries + // + Modelica.Blocks.Sources.Ramp input_T( + height=50, + duration=1500, + offset=273.15 + 25, + startTime=500) "Input for temperature" annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=0, + origin={80,0}))); + +equation + // + // Connections + // + connect(liquidInlet.port, phaseSeparator.cfp_xMinus[1]) annotation (Line( + points={{0,-40},{0,-8.4},{-3.6,-8.4}}, + color={0,140,72}, + thickness=1)); + connect(vaporInlet.port, phaseSeparator.cfp_xPlus[1]) annotation (Line( + points={{0,40},{0,15.6},{-3.6,15.6}}, + color={0,140,72}, + thickness=1)); + connect(heatSource.port, heatTransfer.hp_b[1]) annotation (Line( + points={{60,0},{48,0}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer.hp_a[1], phaseSeparator.hp_yMinus) annotation (Line( + points={{32,0},{12,0}}, + color={238,46,47}, + thickness=1)); + + connect(input_liquidPort.y, liquidInlet.m_flow_input) + annotation (Line(points={{-19,-70},{-2,-70},{-2,-41.2}}, color={0,0,127})); + connect(input_vaporPort.y,vaporInlet. m_flow_input) + annotation (Line(points={{-19,70},{-2,70},{-2,41.2}}, color={0,0,127})); + connect(input_T.y, heatSource.T_input) annotation (Line(points={{69,0},{66,0}, + {66,-5.2},{61,-5.2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the pool boiling heat transfer. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 17, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_PoolBoilingHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/Tester/Test_PoolCondensationHeatTransfer.mo b/SorpLib/Components/HeatTransfer/Tester/Test_PoolCondensationHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..18ca44ac7a607f68230c933754b647187a27824e --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Tester/Test_PoolCondensationHeatTransfer.mo @@ -0,0 +1,173 @@ +within SorpLib.Components.HeatTransfer.Tester; +model Test_PoolCondensationHeatTransfer + "Tester for the pool condensation heat transfer" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the VLE liquid" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource liquidInlet( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_mFlowInput=true, + m_flow_fixed=-0.001, + h_fixed=0.5e6, + redeclare package Medium = Medium) + "Liquid inlet for phase seprator volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-40}))); + SorpLib.Basics.Sources.Fluids.VLESource vaporInlet( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.SpecificEnthalpy, + use_mFlowInput=true, + m_flow_fixed=1e-3, + h_fixed=1e-6, + redeclare package Medium = Medium) + "Vapor inlet for phase separator" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={0,40}))); + + SorpLib.Basics.Sources.Thermal.HeatSource heatSource( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=true, + use_QFlowInput=false) + "Heat source for phase seprator volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={60,0}))); + + // + // Definition of heat transfer models + // + SorpLib.Components.HeatTransfer.PoolCondensationHeatTransfer heatTransfer( + redeclare model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.PoolCondensation.LinearAlphaA_fRel, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=phaseSeparator.p, + T=phaseSeparator.T, + rho=phaseSeparator.rho, + cp=phaseSeparator.phaseSepratorProperties.cp, + eta=phaseSeparator.phaseSepratorProperties.eta, + lambda=phaseSeparator.phaseSepratorProperties.lambda), + f_relativeFillingLevel=phaseSeparator.l_liq_rel) "Heat transfer model" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); + + // + // Definition of VLE models + // + SorpLib.Basics.Volumes.PhaseSeparatorVolumes.PhaseSeparatorVolume + phaseSeparator( + T_initial=348.15, + rho_initial=500, + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + calculateAdditionalProperties=true, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare final package Medium = Medium, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1) "Model of a phase seperator volume" annotation ( + Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=90, + origin={0,0}))); + + // + // Definition of fluid boundaries + // +protected + Modelica.Blocks.Sources.Trapezoid input_liquidPort( + amplitude=-0.0001, + rising=250, + width=400, + falling=250, + period=950, + startTime=50) + "Input for liquid port boundary" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-30,-70}))); + Modelica.Blocks.Sources.Ramp input_vaporPort( + height=0.0001, + duration=250, + startTime=500) + "Input for vapor Port" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-30,70}))); + + // + // Definition of thermal boundaries + // + Modelica.Blocks.Sources.Ramp input_T( + height=-50, + duration=1500, + offset=273.15 + 75, + startTime=500) "Input for temperature" annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=0, + origin={80,0}))); + +equation + // + // Connections + // + connect(liquidInlet.port, phaseSeparator.cfp_xMinus[1]) annotation (Line( + points={{0,-40},{0,-8.4},{-3.6,-8.4}}, + color={0,140,72}, + thickness=1)); + connect(vaporInlet.port, phaseSeparator.cfp_xPlus[1]) annotation (Line( + points={{0,40},{0,15.6},{-3.6,15.6}}, + color={0,140,72}, + thickness=1)); + connect(heatSource.port, heatTransfer.hp_b[1]) annotation (Line( + points={{60,0},{48,0}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer.hp_a[1], phaseSeparator.hp_yMinus) annotation (Line( + points={{32,0},{12,0}}, + color={238,46,47}, + thickness=1)); + + connect(input_liquidPort.y, liquidInlet.m_flow_input) + annotation (Line(points={{-19,-70},{-2,-70},{-2,-41.2}}, color={0,0,127})); + connect(input_vaporPort.y,vaporInlet. m_flow_input) + annotation (Line(points={{-19,70},{-2,70},{-2,41.2}}, color={0,0,127})); + connect(input_T.y, heatSource.T_input) annotation (Line(points={{69,0},{66,0}, + {66,-5.2},{61,-5.2}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the pool condensation heat transfer. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 18, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_PoolCondensationHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/Tester/Test_RadiationHeatTransfer.mo b/SorpLib/Components/HeatTransfer/Tester/Test_RadiationHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..39adc73f33c17741223787a9b5a4068958de1c23 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Tester/Test_RadiationHeatTransfer.mo @@ -0,0 +1,242 @@ +within SorpLib.Components.HeatTransfer.Tester; +model Test_RadiationHeatTransfer "Tester for the radiation heat transfer" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Modelica.Units.SI.Pressure p = 1e5 + "Constant pressure" + annotation (Dialog(tab="General", group="Case Study")); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Thermal.HeatSource hs_a1(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,10},{-50,30}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b1(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,10},{50,30}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_a2(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b2(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_a3(use_TInput=true) + "Heat source a" + annotation (Placement(transformation(extent={{-70,-30},{-50,-10}}))); + SorpLib.Basics.Sources.Thermal.HeatSource hs_b3(use_TInput=true) + "Heat source b" + annotation (Placement(transformation(extent={{70,-30},{50,-10}}))); + + // + // Definition of heat transfer models + // + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_a1(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantResistance, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall1.solidProperties.p, + T=wall1.solidProperties.T, + rho=1/wall1.solidProperties.v, + cp=wall1.solidProperties.c, + eta=0, + lambda=wall1.solidProperties.lambda)) + "Heat transfer at heat source a" + annotation (Placement(transformation(extent={{-40,10},{-20,30}}))); + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_b1(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantResistance, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall1.solidProperties.p, + T=wall1.solidProperties.T, + rho=1/wall1.solidProperties.v, + cp=wall1.solidProperties.c, + eta=0, + lambda=wall1.solidProperties.lambda)) + "Heat transfer at heat source b" + annotation (Placement(transformation(extent={{20,10},{40,30}}))); + + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_a2(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantPlainWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall2.solidProperties.p, + T=wall2.solidProperties.T, + rho=1/wall2.solidProperties.v, + cp=wall2.solidProperties.c, + eta=0, + lambda=wall2.solidProperties.lambda)) + "Heat transfer at heat source a" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_b2(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantPlainWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall2.solidProperties.p, + T=wall2.solidProperties.T, + rho=1/wall2.solidProperties.v, + cp=wall2.solidProperties.c, + eta=0, + lambda=wall2.solidProperties.lambda)) + "Heat transfer at heat source b" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_a3(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantCylindricalWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall3.solidProperties.p, + T=wall3.solidProperties.T, + rho=1/wall3.solidProperties.v, + cp=wall3.solidProperties.c, + eta=0, + lambda=wall3.solidProperties.lambda)) + "Heat transfer at heat source a" + annotation (Placement(transformation(extent={{-40,-30},{-20,-10}}))); + SorpLib.Components.HeatTransfer.ConductionHeatTransfer ht_b3(redeclare model + HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.Conduction.ConstantCylindricalWall, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wall3.solidProperties.p, + T=wall3.solidProperties.T, + rho=1/wall3.solidProperties.v, + cp=wall3.solidProperties.c, + eta=0, + lambda=wall3.solidProperties.lambda)) + "Heat transfer at heat source b" + annotation (Placement(transformation(extent={{20,-30},{40,-10}}))); + + // + // Definition of wall models + // + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume wall1( + solidMedium(approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.GeneralizedFunction), + T_initial=298.15, + p=p) "Wall model" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume wall2( + solidMedium(approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.GeneralizedFunction), + T_initial=298.15, + p=p) "Wall model" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + SorpLib.Basics.Volumes.SolidVolumes.SolidVolume wall3( + solidMedium(approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.GeneralizedFunction), + T_initial=298.15, + p=p) "Wall model" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_T_a( + amplitude=50, + f=1/250, + offset=273.15 + 50) + "Input signal for temperature at sources a" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + + Modelica.Blocks.Sources.Trapezoid input_T_b( + amplitude=100, + rising=50, + width=100, + falling=50, + period=250, + offset=273.15) + "Input signal for temperature at sources b" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + +equation + // + // Connections + // + connect(hs_a1.port, ht_a1.hp_a[1]) annotation (Line( + points={{-60,20},{-38,20}}, + color={238,46,47}, + thickness=1)); + connect(ht_a1.hp_b[1], wall1.hp_xMinus) annotation (Line( + points={{-22,20},{-6,20}}, + color={238,46,47}, + thickness=1)); + connect(wall1.hp_xPlus, ht_b1.hp_a[1]) annotation (Line( + points={{6,20},{22,20}}, + color={238,46,47}, + thickness=1)); + connect(ht_b1.hp_b[1], hs_b1.port) annotation (Line( + points={{38,20},{60,20}}, + color={238,46,47}, + thickness=1)); + connect(hs_a2.port, ht_a2.hp_a[1]) annotation (Line( + points={{-60,0},{-38,0}}, + color={238,46,47}, + thickness=1)); + connect(ht_a2.hp_b[1], wall2.hp_xMinus) annotation (Line( + points={{-22,0},{-6,0}}, + color={238,46,47}, + thickness=1)); + connect(wall2.hp_xPlus, ht_b2.hp_a[1]) annotation (Line( + points={{6,0},{22,0}}, + color={238,46,47}, + thickness=1)); + connect(ht_b2.hp_b[1], hs_b2.port) annotation (Line( + points={{38,0},{60,0}}, + color={238,46,47}, + thickness=1)); + connect(hs_a3.port, ht_a3.hp_a[1]) annotation (Line( + points={{-60,-20},{-38,-20}}, + color={238,46,47}, + thickness=1)); + connect(ht_a3.hp_b[1], wall3.hp_xMinus) annotation (Line( + points={{-22,-20},{-6,-20}}, + color={238,46,47}, + thickness=1)); + connect(wall3.hp_xPlus, ht_b3.hp_a[1]) annotation (Line( + points={{6,-20},{22,-20}}, + color={238,46,47}, + thickness=1)); + connect(ht_b3.hp_b[1], hs_b3.port) annotation (Line( + points={{38,-20},{60,-20}}, + color={238,46,47}, + thickness=1)); + + connect(input_T_a.y, hs_a1.T_input) annotation (Line(points={{-79,0},{-70,0}, + {-70,25.2},{-61,25.2}},color={0,0,127})); + connect(input_T_b.y, hs_b1.T_input) annotation (Line(points={{79,0},{70,0},{ + 70,25.2},{61,25.2}}, + color={0,0,127})); + connect(input_T_a.y, hs_a2.T_input) annotation (Line(points={{-79,0},{-70,0}, + {-70,5.2},{-61,5.2}}, color={0,0,127})); + connect(input_T_a.y, hs_a3.T_input) annotation (Line(points={{-79,0},{-70,0}, + {-70,-14.8},{-61,-14.8}}, + color={0,0,127})); + connect(input_T_b.y, hs_b2.T_input) annotation (Line(points={{79,0},{70,0},{ + 70,5.2},{61,5.2}},color={0,0,127})); + connect(input_T_b.y, hs_b3.T_input) annotation (Line(points={{79,0},{70,0},{ + 70,-14.8},{61,-14.8}}, + color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the radiation heat transfer. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 16, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_RadiationHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/Tester/Test_TubeInsideHeatTransfer.mo b/SorpLib/Components/HeatTransfer/Tester/Test_TubeInsideHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..c6ec2cec9b14962cf5bb8ff308fddfee3c1c6c94 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Tester/Test_TubeInsideHeatTransfer.mo @@ -0,0 +1,164 @@ +within SorpLib.Components.HeatTransfer.Tester; +model Test_TubeInsideHeatTransfer + "Tester for the convective heat transfer within tubes" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource outlet( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=false, + T_fixed=298.15, + redeclare package Medium = Medium) + "Outlet of the liquid volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={50,0}))); + SorpLib.Basics.Sources.Fluids.LiquidSource inlet( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + T_fixed=323.15, + redeclare package Medium = Medium) + "Inlet of liquid volume" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=180, + origin={-50,0}))); + + SorpLib.Basics.Sources.Thermal.HeatSource heatSource( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=true, + use_QFlowInput=false) + "Heat source for fluid volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,60}))); + + // + // Definition of heat transfer models + // + SorpLib.Components.HeatTransfer.TubeInsideHeatTransfer heatTransfer( + redeclare model HeatTransferCoefficient = + HeatTransferCoefficientCorrelations.TubeInside.Schmidt, + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=liquidVolume.fluidProperties.p, + T=liquidVolume.fluidProperties.T, + rho=1/liquidVolume.fluidProperties.v, + cp=liquidVolume.fluidProperties.cp, + eta=liquidVolume.fluidProperties.eta, + lambda=liquidVolume.fluidProperties.lambda), + m_hyd_xMinus=liquidVolume.fluidProperties.mc_flow_xMinus, + m_hyd_xPlus=liquidVolume.fluidProperties.mc_flow_xPlus) + "Heat transfer model" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,40}))); + + // + // Definition of liquid volume models + // + SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume liquidVolume( + T_initial=348.15, + geometry(V=Modelica.Constants.pi/4*0.01^2*1), + type_energyBalance=SorpLib.Choices.BalanceEquations.TransientFixedInitial, + calculateAdditionalProperties=true, + type_overallMassBalance=SorpLib.Choices.BalanceEquations.SteadyStateFreeInitial, + redeclare final package Medium = Medium, + nPorts_cfp_xMinus=1, + nPorts_cfp_xPlus=1) + "Model of a liquid volume" + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={0,0}))); + + // + // Definition of fluid boundaries + // +protected + Modelica.Blocks.Sources.Sine input_mFlow_inlet( + amplitude=10, + f=1/250, + startTime=50) + "Input for mass flow rate at inlet port" + annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-80,0}))); + + // + // Definition of thermal boundaries + // + Modelica.Blocks.Sources.Ramp input_T( + height=-75, + duration=1500, + offset=273.15 + 75, + startTime=500) + "Input for temperature" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={0,80}))); + +equation + // + // Connections + // + connect(inlet.port, liquidVolume.cfp_xMinus[1]) annotation (Line( + points={{-50,0},{-40,0},{-40,3.6},{-8.4,3.6}}, + color={28,108,200}, + thickness=1)); + connect(outlet.port, liquidVolume.cfp_xPlus[1]) annotation (Line( + points={{50,0},{40,0},{40,3.6},{15.6,3.6}}, + color={28,108,200}, + thickness=1)); + connect(heatSource.port, heatTransfer.hp_b[1]) annotation (Line( + points={{0,60},{0,48}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer.hp_a[1], liquidVolume.hp_yPlus) annotation (Line( + points={{0,32},{0,12}}, + color={238,46,47}, + thickness=1)); + + connect(input_mFlow_inlet.y, inlet.m_flow_input) annotation (Line(points={{-69, + 0},{-60,0},{-60,-2},{-51.2,-2}}, color={0,0,127})); + connect(input_T.y, heatSource.T_input) annotation (Line(points={{0,69},{0,64}, + {5.2,64},{5.2,61}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the convective heat transfer within tubes. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 19, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_TubeInsideHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/Tester/package.mo b/SorpLib/Components/HeatTransfer/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..3ae82b54a5c1d00de7268c58b7cda38a9d52f4a2 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.HeatTransfer; +package Tester "Models to test and varify heat transfer models" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented heat transfer +models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructering the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/HeatTransfer/Tester/package.order b/SorpLib/Components/HeatTransfer/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..b5330fa4676edf6244e402e146b2e80857c9d6f0 --- /dev/null +++ b/SorpLib/Components/HeatTransfer/Tester/package.order @@ -0,0 +1,8 @@ +Test_GenericHeatTransfer +Test_ConductionHeatTransfer +Test_RadiationHeatTransfer +Test_PoolBoilingHeatTransfer +Test_PoolCondensationHeatTransfer +Test_TubeInsideHeatTransfer +Test_ClosedAdsorberHeatTransfer +Test_OpenAdsorberHeatTransfer diff --git a/SorpLib/Components/HeatTransfer/Testers/TestHeatTransfer1.mo b/SorpLib/Components/HeatTransfer/Testers/TestHeatTransfer1.mo deleted file mode 100644 index 49cde3489938c333d9923ddabaabc13a3791b8fa..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/Testers/TestHeatTransfer1.mo +++ /dev/null @@ -1,27 +0,0 @@ -within SorpLib.Components.HeatTransfer.Testers; -model TestHeatTransfer1 - - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary - annotation (Placement(transformation(extent={{-44,-6},{-36,6}}))); - TIL.OtherComponents.Thermal.MultiPortHeatBoundary multiPortHeatBoundary(nPorts=10, TFixed= - 373.15) - annotation (Placement(transformation(extent={{36,-6},{44,6}}))); - HeatTransfer heatTransfer(n=10, - useAlphaAInput=false, - redeclare model HeatTransfer = HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=100)) - annotation (Placement(transformation(extent={{-8,-4},{8,4}}, - rotation=0, - origin={0,0}))); -equation - connect(heatBoundary.heatPort, heatTransfer.heatPortA) annotation (Line( - points={{-40,0},{-8,0}}, - color={204,0,0}, - thickness=0.5)); - connect(multiPortHeatBoundary.heatPorts, heatTransfer.heatPortB[1:10]) - annotation (Line( - points={{40,0},{8,0},{8,0.9}}, - color={204,0,0}, - thickness=0.5)); - annotation (experiment(StopTime=500, Interval=1)); -end TestHeatTransfer1; diff --git a/SorpLib/Components/HeatTransfer/Testers/TestHeatTransfer2.mo b/SorpLib/Components/HeatTransfer/Testers/TestHeatTransfer2.mo deleted file mode 100644 index 1c47b8e773a52a88bf428fb3584b8cc3dff18f47..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/Testers/TestHeatTransfer2.mo +++ /dev/null @@ -1,35 +0,0 @@ -within SorpLib.Components.HeatTransfer.Testers; -model TestHeatTransfer2 - - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary - annotation (Placement(transformation(extent={{-44,-6},{-36,6}}))); - TIL.OtherComponents.Thermal.MultiPortHeatBoundary multiPortHeatBoundary(nPorts=10, TFixed= - 373.15) - annotation (Placement(transformation(extent={{36,-6},{44,6}}))); - HeatTransfer heatTransfer( - useAlphaAInput=true, - redeclare model HeatTransfer = HeatTransferPhenomena.ConstantAlpha, - n=10) - annotation (Placement(transformation(extent={{-8,-4},{8,4}}))); - Modelica.Blocks.Sources.Step step( - height=200, - offset=100, - startTime=150) - annotation (Placement(transformation(extent={{-6,-6},{6,6}}, - rotation=270, - origin={0,18}))); -equation - connect(heatBoundary.heatPort, heatTransfer.heatPortA) annotation (Line( - points={{-40,0},{-8,0}}, - color={204,0,0}, - thickness=0.5)); - connect(step.y, heatTransfer.alphaAInput) - annotation (Line(points={{0,11.4},{0,6},{0,3.6}}, - color={0,0,127})); - connect(heatTransfer.heatPortB[1:10], multiPortHeatBoundary.heatPorts) - annotation (Line( - points={{8,0.9},{8,0},{40,0}}, - color={204,0,0}, - thickness=0.5)); - annotation (experiment(StopTime=500, Interval=1)); -end TestHeatTransfer2; diff --git a/SorpLib/Components/HeatTransfer/Testers/package.mo b/SorpLib/Components/HeatTransfer/Testers/package.mo deleted file mode 100644 index 6bc6bd7123d5a5ee9088c0ae47ad48919e6410fa..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/Testers/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.HeatTransfer; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - -end Testers; diff --git a/SorpLib/Components/HeatTransfer/Testers/package.order b/SorpLib/Components/HeatTransfer/Testers/package.order deleted file mode 100644 index 92d5c5d79653be68790119573a51365642450f31..0000000000000000000000000000000000000000 --- a/SorpLib/Components/HeatTransfer/Testers/package.order +++ /dev/null @@ -1,2 +0,0 @@ -TestHeatTransfer1 -TestHeatTransfer2 diff --git a/SorpLib/Components/HeatTransfer/TubeInsideHeatTransfer.mo b/SorpLib/Components/HeatTransfer/TubeInsideHeatTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..135f914be67e160372d9251f46ff3d9d9132ceeb --- /dev/null +++ b/SorpLib/Components/HeatTransfer/TubeInsideHeatTransfer.mo @@ -0,0 +1,115 @@ +within SorpLib.Components.HeatTransfer; +model TubeInsideHeatTransfer + "Model calculating a heat transfer describing convective heat transfer within tubes" + extends BaseClasses.PartialHeatTransfer( + final exponetTemperature=1, + redeclare replaceable model HeatTransferCoefficient = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.ConstantAlpha + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialTubeInsideHeatTransferCoefficient( + fluidProperties=fluidProperties, + m_hyd_xMinus=m_hyd_xMinus, + m_hyd_xPlus=m_hyd_xPlus, + geometry=geometry)); + + // + // Definition of parameters + // + replaceable parameter SorpLib.Components.HeatTransfer.Records.GeometryTube geometry + constrainedby SorpLib.Components.HeatTransfer.Records.GeometryTube + "Geometry of the tube" + annotation(Dialog(tab = "General", group = "Heat Transfer Coefficient", + enable=false)); + + // + // Definitions of inputs + // + input SorpLib.Components.HeatTransfer.Records.FluidProperties fluidProperties + "Fluid properties (i.e., fluid properties of the fluid volume)" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Modelica.Units.SI.MassFlowRate m_hyd_xMinus + "Hydraulic mass flow rate at design inlet" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + input Modelica.Units.SI.MassFlowRate m_hyd_xPlus + "Hydraulic mass flow rate at design outlet" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The heat transfer model is used to describe convective heat transfer within a tube, +which is the heat transfer between the heat transfer fluid and tube wall. Thus, +the pool condensation heat transfer model represents a thermal resistance betweed +two models. Depending on the attached temperatures (i.e., attached potential) +and the chosen transport phenomena, this model determines the heat flow rate +between the connected models. +<br/><br/> +The model has two heat ports, which sizes can be defined via a parameter. The +scalable heat ports enable the connection of various models. For example, this +enables to connect a discretized model to a lumped model, or two different +disretized models. +</p> + +<h4>Main equations</h4> +<p> +The model has steady-state energy balance: +</p> +<pre> + 0 = ∑ (hp_a.Q_flow) + ∑ (hp_b.Q_flow); +</pre> +<p> +The heat flow rate <i>Q_flow</i> is proportional to the driving temperature +difference <i>ΔT = hp_a.T - hp_b.T</i> and the production of heat transfer +coefficient and area <i>αA</i>, which can be formulated as thermal resistance +<i>R<sub>tubeInside</sub></i>. This product can be given as an input or calculated using +models describing heat transfer coefficient correlations. +</p> +<pre> + hp_a.Q_flow = αA * ΔT = 1 / R<sub>tubeInside</sub> * (hp_a.T - hp_b.T); +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> + <li> + The number of ports a and b must be an even integer multiple of each other. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The (pool) condensation heat transfer is typically used to desribe the heat transfer +within tubes, covering laminar and turbulent flow regimes. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useAlphaAInput</i>: + Defines if the product of heat transfer coefficient and area is given via + an input or calculated using an approproate correlation model for the heat + transfer coefficient. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 19, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Text( + extent={{-60,20},{60,-20}}, + lineColor={0,0,0}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={238,46,47}, + textString="Q_flow = 1/R_tubeInside * DT")})); +end TubeInsideHeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/package.mo b/SorpLib/Components/HeatTransfer/package.mo index 76a80639f605bf3ff8cadf57e63933febc991008..378162945a06bd94a1e8985bd461f55161bcdd2e 100644 --- a/SorpLib/Components/HeatTransfer/package.mo +++ b/SorpLib/Components/HeatTransfer/package.mo @@ -1,7 +1,54 @@ within SorpLib.Components; -package HeatTransfer -extends SorpLib.Internals.ClassTypes.ComponentPackage; - - +package HeatTransfer "Models and correlations to calculate heat transfers" + extends SorpLib.Icons.HeatTransfersPackage; + annotation (Documentation(info="<html> +<p> +This package includes various heat transfer models to calculate the heat transfer +between different components: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.GenericHeatTransfer\">GenericHeatTransfer</a>: + Calculates a gneric heat transfer between components. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.ConductionHeatTransfer\">ConductionHeatTransfer</a>: + Calculates conductive heat transfer within volume models. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.RadiationHeatTransfer\">RadiationHeatTransfer</a>: + Calculates radiation heat transfer between components. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.PoolBoilingHeatTransfer\">PoolBoilingHeatTransfer</a>: + Calculates pool boiling heat transfer within evaporators. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.PoolCondensationHeatTransfer\">PoolCondensationHeatTransfer</a>: + Calculates (pool) condensation heat transfer within condensers. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.TubeInsideHeatTransfer\">TubeInsideHeatTransfer</a>: + Calculates convective heat transfer within tubes. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.ClosedAdsorberHeatTransfer\">ClosedAdsorberHeatTransfer</a>: + Calculates the heat transfer between sorbent and heat exchanger within closed + adsorbers. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.HeatTransfer.OpenAdsorberHeatTransfer\">OpenAdsorberHeatTransfer</a>: + Calculates the heat transfer between gas and sorbent/casing within closed + adsorbers. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); end HeatTransfer; diff --git a/SorpLib/Components/HeatTransfer/package.order b/SorpLib/Components/HeatTransfer/package.order index 724e8582256d88f07d5880cab25b1e8adc5d6ec6..1580af194069c0e5de49d48a9a800ab835d493bf 100644 --- a/SorpLib/Components/HeatTransfer/package.order +++ b/SorpLib/Components/HeatTransfer/package.order @@ -1,3 +1,12 @@ -HeatTransfer -HeatTransferPhenomena -Testers +BaseClasses +Records +HeatTransferCoefficientCorrelations +GenericHeatTransfer +ConductionHeatTransfer +RadiationHeatTransfer +PoolBoilingHeatTransfer +PoolCondensationHeatTransfer +TubeInsideHeatTransfer +ClosedAdsorberHeatTransfer +OpenAdsorberHeatTransfer +Tester diff --git a/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransfer.mo b/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..2c5c67ac0530144334fb2a982a1926f5bfea7497 --- /dev/null +++ b/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransfer.mo @@ -0,0 +1,351 @@ +within SorpLib.Components.MassTransfer.BaseClasses; +partial model PartialMassTransfer + "Base model for all mass transfer models" + + // + // Definition of parameters describing the kind of valve + // + parameter Boolean canBeActivated = false + "= true, if mass transfer can be activated or deactiavted" + annotation (Dialog(tab="General",group="Calculation Setup"), + Evaluate = true, + HideResult=true); + parameter Boolean isFlapValve = false + "= true, if mass transfer behaves like a flap valve" + annotation (Dialog(tab="General",group="Calculation Setup"), + Evaluate = true, + HideResult=true); + parameter Boolean isFlowAB = true + "= true, if flow direction is from port a->b; otherwise, flow direction is + from port b->a" + annotation (Dialog(tab="General",group="Calculation Setup", + enable = isFlapValve), + Evaluate = true, + HideResult=true); + parameter Modelica.Units.SI.PressureDifference offset_dp = 0 + "Optional offset for pressure difference (i.e., dp + offset_dp) to accout for, + e.g., hydostatic pressure differences when controlling flap valve status" + annotation (Dialog(tab="General",group="Calculation Setup", + enable = isFlapValve)); + + // + // Definition of parameters regarding the mass transfer coefficient + // + parameter Boolean useBetaInput = false + " = true, if beta is given by input; otherwise, beta is calculated by + selected model" + annotation (Dialog(tab="General", group="Mass Transfer Coefficient"), + Evaluate = true, + HideResult=true); + parameter Boolean calculateFluidProperties = false + "= true, to calculate instreaming fluid properties at port a and b" + annotation (Dialog(tab="General", group="Mass Transfer Coefficient", + enable = not useBetaInput), + Evaluate = true, + HideResult=true); + parameter SorpLib.Choices.MassTransferFluidProperties fluidPropertyPosition= + SorpLib.Choices.MassTransferFluidProperties.AverageInstreaming + "Defines the calculation approach of fluid properties if needed" + annotation (Dialog(tab="General", group="Mass Transfer Coefficient", + enable = not useBetaInput), + Evaluate = true, + HideResult=true); + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="Medium", group="Fluid"), + Evaluate=true, + HideResult=true); + + // + // Definition or initialisation parameters + // + parameter Modelica.Units.SI.MassFlowRate m_flow_start = 1e-4 + "Start value for mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter Boolean limitPressureForCalculations = true + "= true, if pressure is limited while fluid property calculations" + annotation (Dialog(tab = "Advanced", group = "Limiter", + enable=calculateFluidProperties), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Modelica.Units.SI.Pressure p_min = 1000 + "Minimal pressure for fluid property calculation" + annotation (Dialog(tab = "Advanced", group = "Limiter", + enable=calculateFluidProperties and limitPressureForCalculations), + Evaluate=true, + HideResult = true); + + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Boolean avoid_events_activating = avoid_events + "= true, if events are avoid by using noEvent()-operator for activating/deactivating + the mass transfer" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput activated_input(final unit="1") if + canBeActivated + " > 0.75, if mass transfer is activated; < 0.25, if mass transfer is decactivated; + otherwise, smooth transiton regime" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, + rotation=90,origin={10,-60}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={10,-60}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealOutput activated_fixed(final unit="1") = 1 if + not canBeActivated + "Needed for connecting to conditional connector"; + + Modelica.Blocks.Interfaces.RealInput activated_internal(final unit="1") + "Needed for connecting to conditional connector"; + + // + // Definition of variables + // +public + Modelica.Units.SI.PressureDifference dp + "Pressure difference between port a and b"; + +equation + // + // Connectors + // + connect(activated_internal, activated_input); + connect(activated_internal, activated_fixed); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all mass transfers. It defines +fundamental parameters and variables required by all mass transfers. Models +that inherit properties from this partial model have to add a mass transfer +coefficient model. In this context, records may be added that contain geometry +and fluid property data. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Pressure difference <i>dp</i> between port a and b. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revision and added documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Major revisions (e.g., object-oriented approach) after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>"), Icon(graphics={ + Ellipse( + extent={{80,62},{-40,-58}}, + lineColor={0,0,0}, + fillColor={175,175,175}, + fillPattern=FillPattern.Solid), + Polygon( + points={{-12,56},{-8,48},{-8,40},{-6,34},{-2,28},{6,18},{20,16},{52,16}, + {50,10},{40,10},{18,12},{16,8},{24,4},{40,2},{46,-2},{48,-8},{46,-18}, + {42,-24},{38,-32},{28,-36},{18,-38},{12,-38},{2,-34},{4,-30},{10,-34}, + {18,-34},{26,-32},{32,-26},{38,-20},{40,-12},{38,-6},{32,-4},{26,-2}, + {22,0},{16,2},{12,6},{14,0},{20,-6},{26,-14},{20,-14},{16,-6},{10, + 0},{8,4},{10,10},{6,14},{0,18},{-4,20},{-4,16},{-6,12},{-4,10},{-4, + 4},{-4,2},{-4,0},{-2,-2},{0,-4},{4,-10},{-4,-4},{-4,-8},{-4,-10},{ + -4,-18},{-10,-24},{-8,-8},{-6,-2},{-10,0},{-24,2},{-30,6},{-28,8}, + {-16,4},{-8,2},{-8,8},{-10,12},{-14,14},{-22,22},{-28,32},{-22,28}, + {-10,16},{-8,22},{-10,28},{-14,34},{-10,42},{-12,56}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + smooth=Smooth.Bezier), + Text( + extent={{-40,80},{-20,60}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.None, + textString="D", + textStyle={TextStyle.Italic}), + Line( + points={{-24,66},{-18,62},{-12,54}}, + color={0,140,72}, + smooth=Smooth.Bezier, + arrow={Arrow.None,Arrow.Filled}, + thickness=0.5), + Line( + points={{-10,52},{-10,44},{-6,30},{4,18},{14,10},{20,2},{34,-2},{44,-10}, + {40,-22},{28,-34},{12,-36},{4,-32}}, + color={0,140,72}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.None,Arrow.Filled}), + Ellipse( + extent={{-12,54},{-10,52}}, + lineColor={0,140,72}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{4,-30},{6,-32}}, + lineColor={0,140,72}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-68,52},{-60,60}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-60,40},{-52,48}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-74,32},{-66,40}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-60,20},{-52,28}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-72,12},{-64,20}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-60,2},{-52,10}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-84,20},{-76,28}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-84,44},{-76,52}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-56,62},{-48,70}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-80,64},{-72,72}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,74},{-58,82}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-82,0},{-74,8}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,-6},{-62,2}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-56,-18},{-48,-10}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-74,-22},{-66,-14}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-86,-34},{-78,-26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-64,-34},{-56,-26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-48,-40},{-40,-32}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-76,-50},{-68,-42}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-60,-52},{-52,-44}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-86,-64},{-78,-56}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid)})); +end PartialMassTransfer; diff --git a/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransferCoefficient.mo b/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransferCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..fef5ebbb19b1df63dc6801085589624a34b39e54 --- /dev/null +++ b/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransferCoefficient.mo @@ -0,0 +1,66 @@ +within SorpLib.Components.MassTransfer.BaseClasses; +partial model PartialMassTransferCoefficient + "Base model for all models calculating the mass transfer coefficient" + + // + // Definition of parameters regarding the mass transfer coefficient + // + parameter Boolean computeTransportProperties = false + "= true, if fluid transport properties are required and must be calculated" + annotation (Dialog(tab = "General", group = "Mass Transfer"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of outputs + // + Modelica.Blocks.Interfaces.RealOutput beta + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Icon(graphics={Ellipse( + extent={{100,100},{-100,-100}}, + lineColor={0,0,0}, + fillColor={0,255,255}, + fillPattern=FillPattern.Solid)}), + Documentation(revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor adaptations and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the mass transfer +coefficient <i>β</i>. It defines fundamental parameters and variables required +by all mass transfer coefficient models. Models that inherit properties from this +partial model have to add an equation for calculating the mass transfer coefficient. +In this context, records may be added that containg geometry and fluid property data. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Meat transfer coefficient <i>beta</i>. + </li> +</ul> +</html>")); +end PartialMassTransferCoefficient; diff --git a/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransferCoefficientClosedAdsorberDP.mo b/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransferCoefficientClosedAdsorberDP.mo new file mode 100644 index 0000000000000000000000000000000000000000..0e7e5ba1152fbb20325102ad8db06216b63696f1 --- /dev/null +++ b/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransferCoefficientClosedAdsorberDP.mo @@ -0,0 +1,68 @@ +within SorpLib.Components.MassTransfer.BaseClasses; +partial model PartialMassTransferCoefficientClosedAdsorberDP + "Base model for all models calculating the pressure-driven mass transfer coefficient of closed adsorbers" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficient( + beta(unit="m.s")); + + // + // Definition of inputs + // + replaceable parameter SorpLib.Components.MassTransfer.Records.GeometryClosedAdsorber geometry + constrainedby + SorpLib.Components.MassTransfer.Records.GeometryClosedAdsorber + "Geometry of the closed adsorber" + annotation (Dialog(tab="General", group="Mass Transfer", enable=false)); + + // + // Definition of inputs + // + input SorpLib.Components.MassTransfer.Records.FluidProperties fluidProperties + "Fluid properties that may be needed for calculations" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Annotations + // + annotation (Icon(graphics={Ellipse( + extent={{100,100},{-100,-100}}, + lineColor={0,0,0}, + fillColor={0,255,255}, + fillPattern=FillPattern.Solid), Text( + extent={{-80,80},{80,-80}}, + lineColor={0,0,0}, + fillColor={0,255,255}, + fillPattern=FillPattern.Solid, + textString="DP")}), Documentation(revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor adaptations and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the presure-driven +mass transfer coefficient <i>β</i>. It defines fundamental parameters and +variables required by all mass transfer coefficient models. Models that inherit +properties from this partial model have to add an equation for calculating the mass +transfer coefficient. In this context, records may be added that containg geometry +and fluid property data. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Meat transfer coefficient <i>beta</i>. + </li> +</ul> +</html>")); +end PartialMassTransferCoefficientClosedAdsorberDP; diff --git a/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransferCoefficientClosedAdsorberDX.mo b/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransferCoefficientClosedAdsorberDX.mo new file mode 100644 index 0000000000000000000000000000000000000000..b7f8b99c9b017501ea01c85a36ae70972af9e90e --- /dev/null +++ b/SorpLib/Components/MassTransfer/BaseClasses/PartialMassTransferCoefficientClosedAdsorberDX.mo @@ -0,0 +1,68 @@ +within SorpLib.Components.MassTransfer.BaseClasses; +partial model PartialMassTransferCoefficientClosedAdsorberDX + "Base model for all models calculating the loading-driven mass transfer coefficient" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficient( + beta(unit="kg/s")); + + // + // Definition of inputs + // + replaceable parameter SorpLib.Components.MassTransfer.Records.GeometryClosedAdsorber geometry + constrainedby + SorpLib.Components.MassTransfer.Records.GeometryClosedAdsorber + "Geometry of the closed adsorber" + annotation (Dialog(tab="General", group="Mass Transfer", enable=false)); + + // + // Definition of inputs + // + input SorpLib.Components.MassTransfer.Records.FluidProperties fluidProperties + "Fluid properties that may be needed for calculations" + annotation (Dialog(tab="General", group="Inputs", enable=false)); + + // + // Annotations + // + annotation (Icon(graphics={Ellipse( + extent={{100,100},{-100,-100}}, + lineColor={0,0,0}, + fillColor={0,255,255}, + fillPattern=FillPattern.Solid), Text( + extent={{-80,80},{80,-80}}, + lineColor={0,0,0}, + fillColor={0,255,255}, + fillPattern=FillPattern.Solid, + textString="DX")}), Documentation(revisions="<html> +<ul> + <li> + January 25, 2024, by Mirko Engelpracht:<br/> + Minor adaptations and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the base model for all models calculating the loading-driven +mass transfer coefficient <i>β</i>. It defines fundamental parameters and +variables required by all mass transfer coefficient models. Models that inherit +properties from this partial model have to add an equation for calculating the mass +transfer coefficient. In this context, records may be added that containg geometry +and fluid property data. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Meat transfer coefficient <i>beta</i>. + </li> +</ul> +</html>")); +end PartialMassTransferCoefficientClosedAdsorberDX; diff --git a/SorpLib/Components/MassTransfer/BaseClasses/PartialPureMassTransfer.mo b/SorpLib/Components/MassTransfer/BaseClasses/PartialPureMassTransfer.mo new file mode 100644 index 0000000000000000000000000000000000000000..1d02abdec32f7f191d7617107f89636b4681104c --- /dev/null +++ b/SorpLib/Components/MassTransfer/BaseClasses/PartialPureMassTransfer.mo @@ -0,0 +1,434 @@ +within SorpLib.Components.MassTransfer.BaseClasses; +partial model PartialPureMassTransfer + "Base model for all mass transfer models describing pure component adsorption" + extends SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransfer; + + // + // Definition of parameters regarding the mass transfer coefficient + // + replaceable model MassTransferCoefficient = + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficient + constrainedby + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficient + "Model calculating the mass transfer coefficient" + annotation (Dialog(tab="General", group="Mass Transfer Coefficient", + enable=not useBetaInput), + choicesAllMatching=true, + HideResult=true, + Evaluate=true); + + // + // Definition or advanced parameters + // + parameter Modelica.Units.SI.MassFlowRate m_flow_small = 1e-4 + "Regularization mass flow rate" + annotation (Dialog(tab="Advanced", group="Numerics")); + parameter Integer noDiff = 2 + "Specification how often transition functions can be differentiated" + annotation(Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput beta_input if useBetaInput + "Mass transport coefficient given by input" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, + rotation=90,origin={30,-60}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={30,-60}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealOutput dummyT(final unit="K") = 0 if + not calculateFluidProperties + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealOutput dummyD(final unit="kg/m3") = 0 if + not calculateFluidProperties + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealOutput dummyEta(final unit="Pa.s") = 0 if + not calculateFluidProperties + "Needed for connecting to conditional connector"; + + Modelica.Blocks.Interfaces.RealInput beta_internal + "Needed for connecting to conditional connector"; + + Modelica.Blocks.Interfaces.RealInput T_adsorbate_internal(final unit="K") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput T_adsorptiveA_internal(final unit="K") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput T_adsorptiveB_internal(final unit="K") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput d_adsorptiveA_internal(final unit="kg/m3") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput d_adsorptiveB_internal(final unit="kg/m3") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput eta_adsorptiveA_internal(final unit="Pa.s") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput eta_adsorptiveB_internal(final unit="Pa.s") + "Needed for connecting to conditional connector"; + + // + // Definition of ports + // +public + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=m_flow_start)) + "Fluid port a" + annotation (Placement(transformation(extent={{-88,-10},{-68,10}}), + iconTransformation(extent={{-88,-10},{-68,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-m_flow_start)) + "Fluid ports b" + annotation (Placement(transformation(extent={{70,-10},{90,10}}), + iconTransformation(extent={{70,-10},{90,10}})), + choicesAllMatching=true); + + // + // Definition of models + // + MassTransferCoefficient massTransferCoefficient if not useBetaInput + "Model calculating the mass transfer coefficient"; + + // + // Definition of variables + // + Real drivingForce + "Driving force for mass transfer: Either dp or dx"; + Real drivingForce_status + "Status of mass transfer according to driving force and flap valve + behaivior: > 0.75, if mass transfer is activated; < 0.25, if mass transfer is + decactivated; otherwise, smooth transiton regime"; + + Real activated = activated_internal * drivingForce_status + "Current status of mass transfer accounting for driving force and external + signal: > 0.75, if mass transfer is activated; < 0.25, if mass transfer is + decactivated; otherwise, smooth transiton regime"; + +protected + Real drivingForce_internal + "Internal value of driving force: Required to pass either pressure or + loading difference in extended models"; + + SorpLib.Components.MassTransfer.Records.FluidProperties fluidProperties + "Fluid properties if needed for transport phenomena"; + +equation + // + // Assertions + // + assert(no_components == 1, + "Mass transfer model is only valid for pure component adsorption!", + level = AssertionLevel.error); + + // + // Connectors + // + connect(beta_internal, beta_input); + connect(beta_internal, massTransferCoefficient.beta); + + connect(T_adsorbate_internal, dummyT); + connect(T_adsorptiveA_internal, dummyT); + connect(T_adsorptiveB_internal, dummyT); + connect(d_adsorptiveA_internal, dummyD); + connect(d_adsorptiveB_internal, dummyD); + connect(eta_adsorptiveA_internal, dummyEta); + connect(eta_adsorptiveB_internal, dummyEta); + + // + // Momentum balance + // + dp = port_a.p - port_b.p + "Pressure drop dp required for flap valve behaiviour and/or pressure driven + mass transfer"; + + // + // Mass balance + // + 0 = port_a.m_flow + port_b.m_flow + "Trivial equation: No change of mass"; + + port_a.Xi_outflow = inStream(port_b.Xi_outflow) + "Trivial equation: No change of transported substances"; + port_b.Xi_outflow = inStream(port_a.Xi_outflow) + "Trivial equation: No change of transported substances"; + + if avoid_events_activating then + port_a.m_flow = (1 - SorpLib.Numerics.smoothTransition_noEvent( + x=activated, + transitionPoint=0.5, + transitionLength=0.25, + noDiff=noDiff)) * beta_internal * drivingForce + "Mass flow rate depends on status of mass transfer"; + + else + port_a.m_flow = (1 - SorpLib.Numerics.smoothTransition( + x=activated, + transitionPoint=0.5, + transitionLength=0.25, + noDiff=noDiff)) * beta_internal * drivingForce + "Mass flow rate depends on status of mass transfer"; + + end if; + + // + // Energy balance + // + port_a.h_outflow = inStream(port_b.h_outflow) + "Trivial equation: No change of energy"; + port_b.h_outflow = inStream(port_a.h_outflow) + "Trivial equation: No change of energy"; + + // + // Limit driving force and determine status of driving force + // + if isFlapValve then + // + // Flap valve: Driving force depends on flow direction + // + drivingForce = if isFlowAB then max(drivingForce_internal, 0) + else min(drivingForce_internal, 0) + "Flow from a->b: Values at port a must be greater than at port b; flow + from b->a: vice versa"; + + if isFlowAB then + if avoid_events then + drivingForce_status = (1 - SorpLib.Numerics.smoothTransition_noEvent( + x=dp + offset_dp, + transitionPoint=0, + transitionLength=5, + noDiff=noDiff)) + "Flow from a->b: Values at port a must be greater than at port b"; + + else + drivingForce_status = (1 - SorpLib.Numerics.smoothTransition( + x=dp + offset_dp, + transitionPoint=0, + transitionLength=5, + noDiff=noDiff)) + "Flow from a->b: Values at port a must be greater than at port b"; + + end if; + + else + if avoid_events then + drivingForce_status = SorpLib.Numerics.smoothTransition_noEvent( + x=dp + offset_dp, + transitionPoint=0, + transitionLength=5, + noDiff=noDiff) + "Flow from b->a: Values at port b must be greater than at port a"; + + else + drivingForce_status = SorpLib.Numerics.smoothTransition( + x=dp + offset_dp, + transitionPoint=0, + transitionLength=5, + noDiff=noDiff) + "Flow from b->a: Values at port b must be greater than at port a"; + + end if; + end if; + + else + // + // No flap valve behaiviour: Use driving force as given and set status to 1 + // + drivingForce = drivingForce_internal + "Driving force depends on kind of mass tranfer: Pressure- or loading-driven + mass transfer"; + drivingForce_status = 1 + "No flap valve behaiviour: Mass transfer is always activated w.r.t. driving + force"; + + end if; + + // + // Calculate fluid properties if required for mass transport phenomena + // + if calculateFluidProperties and not useBetaInput then + // + // Calculate fluid properties + // + fluidProperties.T_adsorbate = T_adsorbate_internal + "Temperature at the adsorbate state"; + + if fluidPropertyPosition== + SorpLib.Choices.MassTransferFluidProperties.PortAInlet then + fluidProperties.p_adsorptive = port_a.p + "Pressure at the adsorptive state"; + fluidProperties.T_adsorptive = T_adsorptiveA_internal + "Temperature at the adsorptive state"; + fluidProperties.d_adsorptive = d_adsorptiveA_internal + "Density at the adsorptive state"; + fluidProperties.eta_adsorptive = eta_adsorptiveA_internal + "Dynamic viscosity at the adsorptive state"; + + elseif fluidPropertyPosition== + SorpLib.Choices.MassTransferFluidProperties.PortBInlet then + fluidProperties.p_adsorptive = port_b.p + "Pressure at the adsorptive state"; + fluidProperties.T_adsorptive = T_adsorptiveB_internal + "Temperature at the adsorptive state"; + fluidProperties.d_adsorptive = d_adsorptiveB_internal + "Density at the adsorptive state"; + fluidProperties.eta_adsorptive = eta_adsorptiveB_internal + "Dynamic viscosity at the adsorptive state"; + + elseif fluidPropertyPosition== + SorpLib.Choices.MassTransferFluidProperties.ActualInlet then + if avoid_events then + fluidProperties.p_adsorptive = SorpLib.Numerics.regStep_noEvent( + x=port_a.m_flow, + y1=port_a.p, + y2=port_b.p, + x_small=m_flow_small) + "Pressure at the adsorptive state"; + fluidProperties.T_adsorptive = SorpLib.Numerics.regStep_noEvent( + x=port_a.m_flow, + y1=T_adsorptiveA_internal, + y2=T_adsorptiveB_internal, + x_small=m_flow_small) + "Temperature at the adsorptive state"; + fluidProperties.d_adsorptive = SorpLib.Numerics.regStep_noEvent( + x=port_a.m_flow, + y1=d_adsorptiveA_internal, + y2=d_adsorptiveB_internal, + x_small=m_flow_small) + "Density at the adsorptive state"; + fluidProperties.eta_adsorptive = SorpLib.Numerics.regStep_noEvent( + x=port_a.m_flow, + y1=eta_adsorptiveA_internal, + y2=eta_adsorptiveB_internal, + x_small=m_flow_small) + "Dynamic viscosity at the adsorptive state"; + + else + fluidProperties.p_adsorptive = SorpLib.Numerics.regStep( + x=port_a.m_flow, + y1=port_a.p, + y2=port_b.p, + x_small=m_flow_small) + "Pressure at the adsorptive state"; + fluidProperties.T_adsorptive = SorpLib.Numerics.regStep( + x=port_a.m_flow, + y1=T_adsorptiveA_internal, + y2=T_adsorptiveB_internal, + x_small=m_flow_small) + "Temperature at the adsorptive state"; + fluidProperties.d_adsorptive = SorpLib.Numerics.regStep( + x=port_a.m_flow, + y1=d_adsorptiveA_internal, + y2=d_adsorptiveB_internal, + x_small=m_flow_small) + "Density at the adsorptive state"; + fluidProperties.eta_adsorptive = SorpLib.Numerics.regStep( + x=port_a.m_flow, + y1=eta_adsorptiveA_internal, + y2=eta_adsorptiveB_internal, + x_small=m_flow_small) + "Dynamic viscosity at the adsorptive state"; + + end if; + + else + fluidProperties.p_adsorptive = + (port_a.p+port_b.p)/2 + "Pressure at the adsorptive state"; + fluidProperties.T_adsorptive = + (T_adsorptiveA_internal+T_adsorptiveB_internal)/2 + "Temperature at the adsorptive state"; + fluidProperties.d_adsorptive = + (d_adsorptiveA_internal+d_adsorptiveB_internal)/2 + "Density at the adsorptive state"; + fluidProperties.eta_adsorptive = + (eta_adsorptiveA_internal+eta_adsorptiveB_internal)/2 + "Dynamic viscosity at the adsorptive state"; + + end if; + + else + // + // Fluid properties are not needed: Set dummy values + // + fluidProperties.T_adsorbate = 0 + "Pressure at the adsorbate state"; + fluidProperties.p_adsorptive = 0 + "Pressure at the adsorptive state"; + fluidProperties.T_adsorptive = 0 + "Temperature at the adsorptive state"; + fluidProperties.d_adsorptive = 0 + "Density at the adsorptive state"; + fluidProperties.eta_adsorptive = 0 + "Dynamic viscosity at the adsorptive state"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all mass transfers of pure component +adsorption. It defines fundamental parameters and variables required by all mass +transfers. Models that inherit properties from this partial model have to redeclare +the fluid ports. Moreover, these models must redeclare and constrain the model +calculating the mass transfer coefficient and area. In this context, records may +be added that containg geometry and fluid property data. Furtheremore, the driving +force must be defined. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Driving force <i>drivingForce_internal</i>. + </li> + <li> + Temperature at adsorbate state <i>T_adsorbate_internal</i>. + </li> + <li> + Instreaming adsorptive temperature at port a <i>T_adsorptiveA_internal</i>. + </li> + <li> + Instreaming adsorptive temperature at port b <i>T_adsorptiveA_internal</i>. + </li> + <li> + Instreaming adsorptive density at port a <i>d_adsorptiveA_internal</i>. + </li> + <li> + Instreaming adsorptive density at port b <i>d_adsorptiveB_internal</i>. + </li> + <li> + Instreaming adsorptive dynamic viscosity at port a <i>eta_adsorptiveB_internal</i>. + </li> + <li> + Instreaming adsorptive dynamic viscosity at port b <i>eta_adsorptiveA_internal</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Major revisions (e.g., object-oriented approach) after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end PartialPureMassTransfer; diff --git a/SorpLib/Components/MassTransfer/BaseClasses/PartialPureMassTransferDP.mo b/SorpLib/Components/MassTransfer/BaseClasses/PartialPureMassTransferDP.mo new file mode 100644 index 0000000000000000000000000000000000000000..aade14c6770cc92a4563ff244e0f90ea5b280ee3 --- /dev/null +++ b/SorpLib/Components/MassTransfer/BaseClasses/PartialPureMassTransferDP.mo @@ -0,0 +1,73 @@ +within SorpLib.Components.MassTransfer.BaseClasses; +partial model PartialPureMassTransferDP + "Base model for all pressure-driven mass transfer models describing pure component adsorption" + extends SorpLib.Components.MassTransfer.BaseClasses.PartialPureMassTransfer; + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealOutput T_adsorbate_calc(final unit="K") = 0 if + calculateFluidProperties + "Needed for connecting to conditional connector: Value is not needed"; + +equation + // + // Connectors + // + connect(T_adsorbate_internal, T_adsorbate_calc); + + // + // Set driving potential + // + drivingForce_internal = port_a.p - port_b.p + "Pressure driven mass flow rate"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all pressure-driven mass transfers of +pure component adsorption. It defines fundamental parameters and variables required +by all mass transfers. Models that inherit properties from this partial model have +to redeclare the fluid ports. Moreover, these models must redeclare and constrain +the model calculating the mass transfer coefficient and area. In this context, records +may be added that containg geometry and fluid property data. Furtheremore, the driving +force must be defined. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Instreaming adsorptive temperature at port a <i>T_adsorptiveA_internal</i>. + </li> + <li> + Instreaming adsorptive temperature at port b <i>T_adsorptiveA_internal</i>. + </li> + <li> + Instreaming adsorptive density at port a <i>d_adsorptiveA_internal</i>. + </li> + <li> + Instreaming adsorptive density at port b <i>d_adsorptiveB_internal</i>. + </li> + <li> + Instreaming adsorptive dynamic viscosity at port a <i>eta_adsorptiveB_internal</i>. + </li> + <li> + Instreaming adsorptive dynamic viscosity at port b <i>eta_adsorptiveA_internal</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureMassTransferDP; diff --git a/SorpLib/Components/MassTransfer/BaseClasses/PartialPureMassTransferDX.mo b/SorpLib/Components/MassTransfer/BaseClasses/PartialPureMassTransferDX.mo new file mode 100644 index 0000000000000000000000000000000000000000..c89645c25a181bb1ce88767799175465b28c7efb --- /dev/null +++ b/SorpLib/Components/MassTransfer/BaseClasses/PartialPureMassTransferDX.mo @@ -0,0 +1,119 @@ +within SorpLib.Components.MassTransfer.BaseClasses; +partial model PartialPureMassTransferDX + "Base model for all loading-driven mass transfer models describing pure component adsorption" + extends SorpLib.Components.MassTransfer.BaseClasses.PartialPureMassTransfer; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake x_adsorpt_input + "Actual adsorpt loading (i.e., loading at pot b)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt_input + "Actual adsorpt temperature (i.e., temperature at port b)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of parameters regarding the medium + // + replaceable model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + constrainedby + SorpLib.Media.WorkingPairs.BaseClasses.PartialPureWorkingPairs( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + calcCaloricProperties=false, + calcEntropicProperties=false, + calcDerivativesIsotherm=false, + calcDerivativesMassEnergyBalance=false, + calcDerivativesEntropyBalance=false) + "Working pair model" + annotation (Dialog(tab="Medium", group="Working Pair"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealOutput T_adsorbate_calc(final unit="K")= + T_adsorpt_input if calculateFluidProperties + "Needed for connecting to conditional connector"; + + // + // Instantiation of models + // +public + WorkingPair workingPair_a_theoretical( + final p_adsorpt=port_a.p, + final T_adsorpt=T_adsorpt_input, + final x_adsorpt=x_adsorpt_theoretical) + "Working pair model to calculate equilibrium properties at port a"; + + // + // Definition of variables + // + SorpLib.Units.Uptake x_adsorpt_theoretical + "Theoretical equilibrium loading of adsorbate at port a (i.e., + vapor/gas phase)"; + +equation + // + // Connectors + // + connect(T_adsorbate_internal, T_adsorbate_calc); + + // + // Set driving potential + // + drivingForce_internal = x_adsorpt_theoretical - x_adsorpt_input + "Loading driven mass flow rate"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all pressure-driven mass transfers of +pure component adsorption. It defines fundamental parameters and variables required +by all mass transfers. Models that inherit properties from this partial model have +to redeclare the fluid ports. Moreover, these models must redeclare and constrain +the model calculating the mass transfer coefficient and area as well as the working +pair In this context, records may be added that containg geometry and fluid property +data. Furtheremore, the driving force must be defined. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Instreaming adsorptive temperature at port a <i>T_adsorptiveA_internal</i>. + </li> + <li> + Instreaming adsorptive temperature at port b <i>T_adsorptiveA_internal</i>. + </li> + <li> + Instreaming adsorptive density at port a <i>d_adsorptiveA_internal</i>. + </li> + <li> + Instreaming adsorptive density at port b <i>d_adsorptiveB_internal</i>. + </li> + <li> + Instreaming adsorptive dynamic viscosity at port a <i>eta_adsorptiveB_internal</i>. + </li> + <li> + Instreaming adsorptive dynamic viscosity at port b <i>eta_adsorptiveA_internal</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 25, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureMassTransferDX; diff --git a/SorpLib/Components/MassTransfer/BaseClasses/package.mo b/SorpLib/Components/MassTransfer/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..57dc508b6ca3bb959bff1517f4a4d032d83afcd5 --- /dev/null +++ b/SorpLib/Components/MassTransfer/BaseClasses/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Components.MassTransfer; +package BaseClasses "Base models and functions for all mass transfers" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial mass transfer and mass transfer coefficient models, +containing fundamental definitions of parameters and variables. The content of +this package is only of interest when adding new mass transfer and mass transfer +coefficient models to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Components/MassTransfer/BaseClasses/package.order b/SorpLib/Components/MassTransfer/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..4b00c32fea382fed7234ca44359ad79398c5c838 --- /dev/null +++ b/SorpLib/Components/MassTransfer/BaseClasses/package.order @@ -0,0 +1,7 @@ +PartialMassTransfer +PartialPureMassTransfer +PartialPureMassTransferDP +PartialPureMassTransferDX +PartialMassTransferCoefficient +PartialMassTransferCoefficientClosedAdsorberDP +PartialMassTransferCoefficientClosedAdsorberDX diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/ConstantCoefficient.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/ConstantCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..81621ec2508965d3e2b5d8885a1dd4d479946fb6 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/ConstantCoefficient.mo @@ -0,0 +1,68 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven; +model ConstantCoefficient + "Generic mass transfer correlation with constant mass transfer coefficient" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDX( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real constantCoefficient(final unit="kg/s")= 1e-7 + "Constant mass transfer coefficient for loading-driven mass transfer" + annotation (Dialog(tab="General", group="Mass Transfer")); + +equation + beta = geometry.no_hydraulicParallelTubes * constantCoefficient / + geometry.no_sorbentVolumes + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of mass transfer coefficient and +area assuming a constant mass transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +assuming a constant mass transfer coefficient <i>β</i> and area <i>A</i>: +</p> +<pre> + βA = no<sub>parallel flows</sub> * βA / no<sub>sorbent volumes</sub> = const.; +</pre> +<p> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This simple mass transfer correlation model is typically used if the mass transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 25, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end ConstantCoefficient; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/ConstantSpecificCoefficient.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/ConstantSpecificCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..eebcc38adbaa4402a36af6b159d96f78d7f0f238 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/ConstantSpecificCoefficient.mo @@ -0,0 +1,71 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven; +model ConstantSpecificCoefficient + "Generic mass transfer correlation with constant product of specific mass transfer coefficient and area" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDX( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real constantSpecificCoefficient(final unit="kg/(s.m2)")= 1e-7 + "Constant specific mass transfer coefficient for loading-driven mass transfer" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Area A = 1 + "Mass transfer area" + annotation (Dialog(tab="General", group="Mass Transfer")); + +equation + beta = geometry.no_hydraulicParallelTubes * constantSpecificCoefficient * A / + geometry.no_sorbentVolumes + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of mass transfer coefficient and +area assuming a constant mass transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +assuming a constant mass transfer coefficient <i>β</i> and area <i>A</i>: +</p> +<pre> + βA = no<sub>parallel flows</sub> * β * A / no<sub>sorbent volumes</sub> = const.; +</pre> +<p> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This simple mass transfer correlation model is typically used if the mass transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 25, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end ConstantSpecificCoefficient; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/Glueckauf.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/Glueckauf.mo new file mode 100644 index 0000000000000000000000000000000000000000..01ef19edbadb28f33ec9b4d1322acfc01920173a --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/Glueckauf.mo @@ -0,0 +1,84 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven; +model Glueckauf + "Mass transfer correlation describing mass transfer according to Glueckauf" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDX( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.Radius r_sorbent = geometry.d_particle/2 + "Radius of sorbent material" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Mass m_sorbent = 2.5 + "Mass of dry sorbent material" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Real D(unit="m2/s") = 1e-10 + "Diffusion coefficient" + annotation (Dialog(tab="General", group="Mass Transfer")); + +equation + beta = geometry.no_hydraulicParallelTubes / geometry.no_sorbentVolumes * + 15 * m_sorbent * D / r_sorbent^2 + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model calculates the product of mass transfer coefficient and +area according to Glueckauf. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +according to: +</p> +<pre> + βA = no<sub>parallel flows</sub> / no<sub>sorbent volumes</sub> * 15 * D / r<sub>particle</sub>^2 * m<sub>sorbent</sub>; +</pre> +<p> +Herein, <i>D</i> is the diffusion coefficient, <i>r<sub>particle</sub></i> is the +radius of the particle, and <i>m<sub>sorbent</sub></i> is the sorbent mass. +<br/><br/> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This mass transfer correlation model is typically used to describe the mass transfer +within closed adsorbers. +</p> + +<h4>References</h4> +<ul> + <li> + Glueckauf, E. (1955). Theory of Chromatography. Part 10: Formulae for Diffusion into Spheres and their Application to Chromatography. Transactions of the Faraday Society, 51(11), 1540-1551. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 25, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end Glueckauf; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/GlueckaufArrhenius.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/GlueckaufArrhenius.mo new file mode 100644 index 0000000000000000000000000000000000000000..2ee17ad8df19ab3ec68e7323c66b259af222212e --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/GlueckaufArrhenius.mo @@ -0,0 +1,95 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven; +model GlueckaufArrhenius + "Mass transfer correlation describing mass transfer according to Glueckauf with a temperature depandancy" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDX( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.Radius r_sorbent = geometry.d_particle/2 + "Radius of sorbent material" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Mass m_sorbent = 2.5 + "Mass of dry sorbent material" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Real D(unit="m2/s") = 1e-10 + "Diffusion coefficient" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.SpecificEnergy E_activation = 2.33e6 + "Activation energy" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.MolarMass M_adsorptive = 0.001801528 + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Mass Transfer")); + +equation + beta = geometry.no_hydraulicParallelTubes / geometry.no_sorbentVolumes * + 15 * m_sorbent * D / r_sorbent^2 * exp(-E_activation / + ((Modelica.Constants.R/M_adsorptive) * fluidProperties.T_adsorbate)) + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model calculates the product of mass transfer coefficient and +area according to Glueckauf. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +according to: +</p> +<pre> + βA = no<sub>parallel flows</sub> / no<sub>sorbent volumes</sub> * 15 * D / r<sub>particle</sub>^2 * m<sub>sorbent</sub> * <strong>exp</strong>(-E<sub>activation</sub> / (R / M<sub>adsorptive</sub> * T<sub>adsorbate</sub>)); +</pre> +<p> +Herein, <i>D</i> is the diffusion coefficient, <i>r<sub>particle</sub></i> is the +radius of the particle, and <i>m<sub>sorbent</sub></i> is the sorbent mass, +<i>E<sub>activation</sub></i> is the activation energy, <i>M<sub>adsorptive</sub></i> +is the molar mass of the adsorptive, <i>T<sub>adsorbate</sub></i> is the adsorbate +temperature. +<br/><br/> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This mass transfer correlation model is typically used to describe the mass transfer +within closed adsorbers. +</p> + +<h4>References</h4> +<ul> + <li> + Glueckauf, E. (1955). Theory of Chromatography. Part 10: Formulae for Diffusion into Spheres and their Application to Chromatography. Transactions of the Faraday Society, 51(11), 1540-1551. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 25, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end GlueckaufArrhenius; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/package.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..bded4e1bc9f5ffa541d151e792f3f6842b2f9f45 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/package.mo @@ -0,0 +1,38 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber; +package LoadingDriven "Correlations for loading-driven mass transfer coefficients describing the mass transfer within closed adsorbers" +extends Modelica.Icons.FunctionsPackage; + + + annotation (Documentation(info="<html> +<p> +This package contains correlations for mass transfer coefficients describing +the loading-driven mass transfer within closed adsorbers: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven.ConstantCoefficient\">ConstantCoefficient</a>: + Generic mass transfer correlation with constant mass transfer coefficient. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven.ConstantSpecificCoefficient\">ConstantSpecificCoefficient</a>: + Generic mass transfer correlation with constant product of specific mass + transfer coefficient and area + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven.Glueckauf\">Glueckauf</a>: + Mass transfer correlation according to Glueckauf. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven.GlueckaufArrhenius\">GlueckaufArrhenius</a>: + Mass transfer correlation according to Glueckauf with temperature dependancy. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end LoadingDriven; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/package.order b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e6ea8b118db57c703b14f26f47a1dfe443dc21b5 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/LoadingDriven/package.order @@ -0,0 +1,4 @@ +ConstantCoefficient +ConstantSpecificCoefficient +Glueckauf +GlueckaufArrhenius diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/ConstantCoefficient.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/ConstantCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..6a3c55f609efdaec012924435e6d2a3f75ec2dd7 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/ConstantCoefficient.mo @@ -0,0 +1,68 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven; +model ConstantCoefficient + "Generic mass transfer correlation with constant mass transfer coefficient" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real constantCoefficient(final unit="m.s")= 1e-7 + "Constant mass transfer coefficient for pressure-driven mass transfer" + annotation (Dialog(tab="General", group="Mass Transfer")); + +equation + beta = geometry.no_hydraulicParallelTubes * constantCoefficient / + geometry.no_sorbentVolumes + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of mass transfer coefficient and +area assuming a constant mass transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +assuming a constant mass transfer coefficient <i>β</i> and area <i>A</i>: +</p> +<pre> + βA = no<sub>parallel flows</sub> * βA / no<sub>sorbent volumes</sub> = const.; +</pre> +<p> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This simple mass transfer correlation model is typically used if the mass transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end ConstantCoefficient; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/ConstantSpecificCoefficient.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/ConstantSpecificCoefficient.mo new file mode 100644 index 0000000000000000000000000000000000000000..1000eb35d38cde851e1f09cc5c698c41c60f3f8c --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/ConstantSpecificCoefficient.mo @@ -0,0 +1,71 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven; +model ConstantSpecificCoefficient + "Generic mass transfer correlation with constant product of specific mass transfer coefficient and area" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + final computeTransportProperties=false, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real constantSpecificCoefficient(final unit="m.s/m2")= 1e-7 + "Constant specific mass transfer coefficient for pressure-driven mass transfer" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Area A = 1 + "Mass transfer area" + annotation (Dialog(tab="General", group="Mass Transfer")); + +equation + beta = geometry.no_hydraulicParallelTubes * constantSpecificCoefficient * A / + geometry.no_sorbentVolumes + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This simple transfer model calculates the product of mass transfer coefficient and +area assuming a constant mass transfer coefficient and area. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +assuming a constant mass transfer coefficient <i>β</i> and area <i>A</i>: +</p> +<pre> + βA = no<sub>parallel flows</sub> * β * A / no<sub>sorbent volumes</sub> = const.; +</pre> +<p> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This simple mass transfer correlation model is typically used if the mass transfer +conditions do not greatly change and a very simple models is required. +</p> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end ConstantSpecificCoefficient; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/DarcyPackedBedSpheres.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/DarcyPackedBedSpheres.mo new file mode 100644 index 0000000000000000000000000000000000000000..6ad96d73890dd45a1a8e0ddd008cfd292bb22b37 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/DarcyPackedBedSpheres.mo @@ -0,0 +1,90 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven; +model DarcyPackedBedSpheres + "Mass transfer correlation describing mass transfer through a packed bed for spherical particles" + extends + SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.DarcyPorousMedia( + final permeability = (d_particle^2 * psi_bed^3) / (150 * (1 - psi_bed)^2)); + + // + // Definition of parameters + // + parameter Real psi_bed(final unit="1") = geometry.psi_particles + "Void fraction of the bed" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Diameter d_particle = geometry.d_particle + "Diameter of the particles" + annotation (Dialog(tab="General", group="Mass Transfer")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model calculates the product of mass transfer coefficient and +area describing the convective flow throug porous media according to Darcy's law +for spherical particles. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +according to: +</p> +<pre> + βA = no<sub>parallel flows</sub> / no<sub>sorbent volumes</sub> * Κ / η * A<sub>cross,bed</sub> * ρ * l<sub>bed</sub> / 2; +</pre> +<p> +Herein, <i>Κ</i> is the permeability of the bed, <i>A<sub>cross,bed</sub></i> +is the cross-sectional area of the bed, <i>l<sub>bed</sub></i> is the total length +of the bed, <i>ρ</i> is the densiy of the adsorptive, and <i>η</i> is the +dynamic viscosity of the adsorptive. The permeability <i>Κ</i> is calculated from +the particle diameter <i>d<sub>particle</sub></i> and void fraction of the bed +<i>ψ<sub>bed</sub></i>: +</p> +<pre> + Κ= (d<sub>particle</sub>^2 * ψ<sub>bed</sub>^3) / (150 * (1 - ψ<sub>bed</sub>)^2); +</pre> +<p> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This mass transfer correlation model is typically used to describe the mass transfer +through a packed bed with spherical particles. +</p> + +<h4>References</h4> +<ul> + <li> + DBejan, A. (2013). Convection heat transfer. 4th ed. Hoboken, N.J.: Wiley. ISBN: 1118519760. + </li> + <li> + Ergun, S. (1952). Fluid flow through packed columns. Chem. Eng. Prog., 48(2), 89-94. + </li> + <li> + Darcy, H.P.G. (1856). Les Fontaines Publiques de la villa de Dijon. Paris. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end DarcyPackedBedSpheres; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow.mo new file mode 100644 index 0000000000000000000000000000000000000000..916ed80bdb934cf7ae699dfc9ee76beab981d478 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow.mo @@ -0,0 +1,184 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven; +model DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow + "Mass transfer correlation describing mass transfer through a packed bed followed trough a particle due to Knudsen diffusion and Poiseuille flow" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + final computeTransportProperties=true, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real f_correction_bed = 1 + "Fitting factor for the bed resistance" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Real f_particle = 0.5 * geometry.no_particles * + geometry.V_particle / ((4/3) * Modelica.Constants.pi * (d_pore/2)^3) + "Fitting factor for the particle resistance" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.Length l_bed = 0.025 + "Total length the adsorptive has to flow through the bed" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Area A_bed = 0.5 + "Cross-sectional area of the bed that the adsorptive has to pass" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Real psi_bed(final unit="1") = geometry.psi_particles + "Void fraction of the bed" + annotation (Dialog(tab="General", group="Mass Transfer")); + final parameter Real permeability(final unit="m2")= + (d_particle^2 * psi_bed^3) / (150 * (1 - psi_bed)^2) + "Permeability of the bed" + annotation (Dialog(tab="General", group="Mass Transfer")); + + + parameter Real tortuosity_Knudsen(final unit="m") = 5^1.7 + "Tortuosity for Knudsen diffusion" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Real tortuosity_Poiseuille(final unit="m") = 5^2.6 + "Tortuosity for Poiseuille flow" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.Diameter d_particle = geometry.d_particle + "Diameter of one particle" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Diameter d_pore = 25e-9 + "Average diameter of the pores" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.Area A_pore= + Modelica.Constants.pi/4 * d_pore^2 + "Cross-sectional area of one pore" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.MolarMass M_adsorptive = 0.001801528 + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Mass Transfer")); + + // + // Definition of variables + // + Real R_bed + "Mass transport resistance for the bed (i.e., Darcy's law)"; + Real R_particle + "Mass transport resistance for the particle"; + + Real D_Knudsen + "Diffusion coefficient according to Knudsen diffusin"; + Real D_Poiseuille + "Diffusion coefficient according to Poiseuille flow"; + +equation + // + // Calculate diffusion coefficients + // + R_bed = 1 / (f_correction_bed * (permeability / fluidProperties.eta_adsorptive) * + (2 / l_bed) * A_bed * fluidProperties.d_adsorptive) + "Mass transport resistance for the bed (i.e., Darcy's law)"; + R_particle = 1 / (f_particle * (D_Knudsen + D_Poiseuille)) + "Mass transport resistance for the particle"; + + D_Knudsen = 4/3 * d_pore / tortuosity_Knudsen * A_pore / (d_particle/2) * + sqrt(M_adsorptive / (2 * Modelica.Constants.pi * Modelica.Constants.R * + fluidProperties.T_adsorptive)) + "Diffusion coefficient according to Knudsen diffusin"; + D_Poiseuille = 1/32 * fluidProperties.p_adsorptive * d_pore^2 / + fluidProperties.eta_adsorptive / tortuosity_Poiseuille * A_pore / (d_particle/2) * + M_adsorptive / (Modelica.Constants.R * fluidProperties.T_adsorptive) + "Diffusion coefficient according to Poiseuille flow"; + + // + // Calculate overall mass transfer coefficient + // + beta = geometry.no_hydraulicParallelTubes / geometry.no_sorbentVolumes / + (R_bed + R_particle) + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model calculates the product of mass transfer coefficient and +area describing the mass transfer through a packed bed according to Darcy's law +followed by a mass transfer through a particle due to a combination of Knudsen +diffusion and Poiseuille flow. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> results from a +serial connection of mass transfer through the bed <i>D<sub>bed</sub></i> and the +particle <i>D<sub>particle</sub></i>, with the latter being a parallel connection +of the Knudsen diffusion <i>D<sub>Knudsen</sub></i> and Poiseuille flow +<i>D<sub>Poiseuille</sub></i>: +</p> +<pre> + βA = no<sub>parallel flows</sub> / no<sub>sorbent volumes</sub> * 1 / [1/(f<sub>correction,bed</sub> * D<sub>bed</sub>) + 1 / (f<sub>correction,particle</sub> * (D<sub>Knudsen</sub> + D<sub>Poiseuille</sub>))]; +</pre> +<p> +with: +</p> +<pre> + D<sub>bed</sub> = Κ / η * A<sub>cross,bed</sub> * ρ * l<sub>bed</sub> / 2; + + D<sub>Knudsen</sub> = 4/3 * d<sub>pore</sub> / θ * A<sub>pore</sub> / (d<sub>particle</sub>/2) * <strong>sqrt</strong>(M<sub>adsorptive</sub> / (2 * π * R * T<sub>adsorptive</sub>)); + + D<sub>Poiseuille</sub> = 1/32 * p<sub>adsorptive</sub> * d<sub>pore</sub>^2 / η / θ * A<sub>pore</sub> / (d<sub>particle</sub>/2) * M<sub>adsorptive</sub> / (R * T<sub>adsorptive</sub>); +</pre> +<p> +and: +</p> +<pre> + Κ= (d<sub>particle</sub>^2 * ψ<sub>bed</sub>^3) / (150 * (1 - ψ<sub>bed</sub>)^2); +</pre> +<p> +Herein, <i>f<sub>correction,i</sub></i> is a correction factor, <i>d<sub>pore</sub></i> +is the average pore diameter, <i>A<sub>pore</sub></i> is the average cross-sectional +area of one pore, <i>d<sub>particle</sub></i> is the average particle diameter, +<i>Κ</i> is the permeability of the bed, <i>A<sub>cross,bed</sub></i> +is the cross-sectional area of the bed, <i>l<sub>bed</sub></i> is the total length +of the bed, <i>θ<sub>Knudsen</sub></i> is the tortuosity factor for Knudsen diffucsion, +<i>θ<sub>Poiseuille</sub></i> is the tortuosity factor for Knudsen diffucsion, +<i>M<sub>adsorptive</sub></i> is the molar mass, <i>R</i> is the ideal gas constant, +<i>p<sub>adsorptive</sub></i> is the adsorptive pressure, <i>T<sub>adsorptive</sub></i> +is the adsorptive temperature, <i>ρ</i> is the densiy of the adsorptive, and <i>η</i> +is the dynamic viscosity of the adsorptive +<br/><br/> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This mass transfer correlation model is typically used to describe the mass transfer +through a packed bed according to Darcy's law followed by a mass transfer through a +particle due to a combination of Knudsen diffusion and Poiseuille flow. +</p> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Kast, W. (1998). Adsorption aus der Gasphase: Ingenieurwissenschaftliche Grundlagen und technische Verfahren (in German). VCH Verlagsgesellschaft, Weinheim, Basel, Cambridge, New York. DOI: https://doi.org/10.1002/bbpc.19900940122. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + June 06, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/DarcyPorousMedia.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/DarcyPorousMedia.mo new file mode 100644 index 0000000000000000000000000000000000000000..ef6963b235650b18926376d032935acac13888e3 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/DarcyPorousMedia.mo @@ -0,0 +1,90 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven; +model DarcyPorousMedia + "Mass transfer correlation describing mass transfer through a packed bed" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + final computeTransportProperties=true, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.Length l_bed = 1 + "Total length the adsorptive has to flow through the bed" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Area A_bed = Modelica.Constants.pi/4 * 0.01^2 + "Cross-sectional area of the bed that the adsorptive has to pass" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Real permeability(final unit="m2") = 0.32 + "Permeability of the bed" + annotation (Dialog(tab="General", group="Mass Transfer")); + +equation + beta = geometry.no_hydraulicParallelTubes / geometry.no_sorbentVolumes * + (permeability / fluidProperties.eta_adsorptive) * (2 / l_bed) * A_bed * + fluidProperties.d_adsorptive + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model calculates the product of mass transfer coefficient and +area describing the convective flow throug porous media according to Darcy's law. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +according to: +</p> +<pre> + βA = no<sub>parallel flows</sub> / no<sub>sorbent volumes</sub> * Κ / η * A<sub>cross,bed</sub> * ρ * l<sub>bed</sub> / 2; +</pre> +<p> +Herein, <i>Κ</i> is the permeability of the bed, <i>A<sub>cross,bed</sub></i> +is the cross-sectional area of the bed, <i>l<sub>bed</sub></i> is the total length +of the bed, <i>ρ</i> is the densiy of the adsorptive, and <i>η</i> is the +dynamic viscosity of the adsorptive. +<br/><br/> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This mass transfer correlation model is typically used to describe the mass transfer +through a packed bed. +</p> + +<h4>References</h4> +<ul> + <li> + DBejan, A. (2013). Convection heat transfer. 4th ed. Hoboken, N.J.: Wiley. ISBN: 1118519760. + </li> + <li> + Darcy, H.P.G. (1856). Les Fontaines Publiques de la villa de Dijon. Paris. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end DarcyPorousMedia; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/KnudsenDiffusion.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/KnudsenDiffusion.mo new file mode 100644 index 0000000000000000000000000000000000000000..b07829a8a1b6233c5a4f18f99c3033f6e926cffc --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/KnudsenDiffusion.mo @@ -0,0 +1,104 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven; +model KnudsenDiffusion + "Mass transfer correlation describing mass transfer through a particle due to Knudsen diffusion" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + final computeTransportProperties=true, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real f_correction = 0.5 * geometry.no_particles * + geometry.V_particle / ((4/3) * Modelica.Constants.pi * (d_pore/2)^3) + "Fitting factor to account for a whole bed (i.e., can be considered as number + of porese" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Real tortuosity(final unit="m") = 5^1.7 + "Tortuosity for Knudsen diffusion" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.Diameter d_particle = geometry.d_particle + "Diameter of one particle" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Diameter d_pore = 25e-9 + "Average diameter of the pores" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.Area A_pore= + Modelica.Constants.pi/4 * d_pore^2 + "Cross-sectional area of one pore" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.MolarMass M_adsorptive = 0.001801528 + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Mass Transfer")); + +equation + beta = geometry.no_hydraulicParallelTubes / geometry.no_sorbentVolumes * + f_correction * 4/3 * d_pore / tortuosity * A_pore / (d_particle/2) * + sqrt(M_adsorptive / (2 * Modelica.Constants.pi * Modelica.Constants.R * + fluidProperties.T_adsorptive)) + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model calculates the product of mass transfer coefficient and +area describing the mass transfer through a particle due to Knudsen diffusion. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +according to: +</p> +<pre> + βA = no<sub>parallel flows</sub> / no<sub>sorbent volumes</sub> * f<sub>correction</sub> * 4/3 * d<sub>pore</sub> / θ * A<sub>pore</sub> / (d<sub>particle</sub>/2) * <strong>sqrt</strong>(M<sub>adsorptive</sub> / (2 * π * R * T<sub>adsorptive</sub>)); +</pre> +<p> +Herein, <i>f<sub>correction</sub></i> is a correction factor, <i>d<sub>pore</sub></i> +is the average pore diameter, <i>A<sub>pore</sub></i> is the average cross-sectional +area of one pore, <i>d<sub>particle</sub></i> is the average particle diameter, +<i>θ</i> is the tortuosity factor, <i>M<sub>adsorptive</sub></i> is the molar +mass, <i>R</i> is the ideal gas constant, and <i>T<sub>adsorptive</sub></i> is the +adsorptive temperature. +<br/><br/> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This mass transfer correlation model is typically used to describe the mass transfer +through a particle that is dominated by Knudsen diffusion. +</p> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Kast, W. (1998). Adsorption aus der Gasphase: Ingenieurwissenschaftliche Grundlagen und technische Verfahren (in German). VCH Verlagsgesellschaft, Weinheim, Basel, Cambridge, New York. DOI: https://doi.org/10.1002/bbpc.19900940122. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + June 06, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end KnudsenDiffusion; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/KnudsenDiffusionPoiseuilleFlow.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/KnudsenDiffusionPoiseuilleFlow.mo new file mode 100644 index 0000000000000000000000000000000000000000..b5cc6b8b890c262f044ba7759fa304cddbdc5829 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/KnudsenDiffusionPoiseuilleFlow.mo @@ -0,0 +1,141 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven; +model KnudsenDiffusionPoiseuilleFlow + "Mass transfer correlation describing mass transfer through a particle due to Knudsen diffusion and Poiseuille flow" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + final computeTransportProperties=true, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real f_correction = 0.5 * geometry.no_particles * + geometry.V_particle / ((4/3) * Modelica.Constants.pi * (d_pore/2)^3) + "Fitting factor to account for a whole bed (i.e., can be considered as number + of pores per particle" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Real tortuosity_Knudsen(final unit="m") = 5^1.7 + "Tortuosity for Knudsen diffusion" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Real tortuosity_Poiseuille(final unit="m") = 5^2.6 + "Tortuosity for Poiseuille flow" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.Diameter d_particle = geometry.d_particle + "Diameter of one particle" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Diameter d_pore = 25e-9 + "Average diameter of the pores" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.Area A_pore= + Modelica.Constants.pi/4 * d_pore^2 + "Cross-sectional area of one pore" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.MolarMass M_adsorptive = 0.001801528 + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Mass Transfer")); + + // + // Definition of variables + // + Real D_Knudsen + "Diffusion coefficient according to Knudsen diffusin"; + Real D_Poiseuille + "Diffusion coefficient according to Poiseuille flow"; + +equation + // + // Calculate diffusion coefficients + // + D_Knudsen = 4/3 * d_pore / tortuosity_Knudsen * A_pore / (d_particle/2) * + sqrt(M_adsorptive / (2 * Modelica.Constants.pi * Modelica.Constants.R * + fluidProperties.T_adsorptive)) + "Diffusion coefficient according to Knudsen diffusin"; + D_Poiseuille = 1/32 * fluidProperties.p_adsorptive * d_pore^2 / + fluidProperties.eta_adsorptive / tortuosity_Poiseuille * A_pore / (d_particle/2) * + M_adsorptive / (Modelica.Constants.R * fluidProperties.T_adsorptive) + "Diffusion coefficient according to Poiseuille flow"; + + // + // Calculate overall mass transfer coefficient + // + beta = geometry.no_hydraulicParallelTubes / geometry.no_sorbentVolumes * + f_correction * (D_Knudsen + D_Poiseuille) + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model calculates the product of mass transfer coefficient and +area describing the mass transfer through a particle due to a combination of Knudsen +diffusion and Poiseuille flow. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> results from a +parallel connection of the Knudsen diffusion <i>D<sub>Knudsen</sub></i> and Poiseuille +flow <i>D<sub>Poiseuille</sub></i> to +</p> +<pre> + βA = no<sub>parallel flows</sub> / no<sub>sorbent volumes</sub> * f<sub>correction</sub> * (D<sub>Knudsen</sub> + D<sub>Poiseuille</sub>); +</pre> +<p> +with: +</p> +<pre> + D<sub>Knudsen</sub> = 4/3 * d<sub>pore</sub> / θ * A<sub>pore</sub> / (d<sub>particle</sub>/2) * <strong>sqrt</strong>(M<sub>adsorptive</sub> / (2 * π * R * T<sub>adsorptive</sub>)); + + D<sub>Poiseuille</sub> = 1/32 * p<sub>adsorptive</sub> * d<sub>pore</sub>^2 / η / θ * A<sub>pore</sub> / (d<sub>particle</sub>/2) * M<sub>adsorptive</sub> / (R * T<sub>adsorptive</sub>); +</pre> +<p> +Herein, <i>f<sub>correction</sub></i> is a correction factor, <i>d<sub>pore</sub></i> +is the average pore diameter, <i>A<sub>pore</sub></i> is the average cross-sectional +area of one pore, <i>d<sub>particle</sub></i> is the average particle diameter, +<i>θ<sub>Knudsen</sub></i> is the tortuosity factor for Knudsen diffucsion, +<i>θ<sub>Poiseuille</sub></i> is the tortuosity factor for Knudsen diffucsion, +<i>M<sub>adsorptive</sub></i> is the molar mass, <i>R</i> is the ideal gas constant, +<i>p<sub>adsorptive</sub></i> is the adsorptive pressure, and <i>T<sub>adsorptive</sub></i> +is the adsorptive temperature. +<br/><br/> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This mass transfer correlation model is typically used to describe the mass transfer +through a particle that is dominated by a combination of Knudsen diffusion and +Poiseuille flow. +</p> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Kast, W. (1998). Adsorption aus der Gasphase: Ingenieurwissenschaftliche Grundlagen und technische Verfahren (in German). VCH Verlagsgesellschaft, Weinheim, Basel, Cambridge, New York. DOI: https://doi.org/10.1002/bbpc.19900940122. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + June 06, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end KnudsenDiffusionPoiseuilleFlow; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/LaminarConnections.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/LaminarConnections.mo new file mode 100644 index 0000000000000000000000000000000000000000..4699726027958d9cfe7f1c4376a6bd10335789c6 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/LaminarConnections.mo @@ -0,0 +1,86 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven; +model LaminarConnections + "Mass transfer correlation describing mass transfer through connections for the lamianr flow regime" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + final computeTransportProperties=true, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real zeta_lam(min=1) = 1 + "Additional factor to account for nonideal connections" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.Length l_connection = 0.5 + "Length of the connection" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Diameter d_connection = 0.04 + "Hydraulic diameter of the connection" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Area A_connection= + Modelica.Constants.pi/4 * d_connection^2 + "Inner cross-sectional area of the connection" + annotation (Dialog(tab="General", group="Mass Transfer")); + +equation + beta = A_connection^2 / (8 * Modelica.Constants.pi * l_connection) * + fluidProperties.d_adsorptive / fluidProperties.eta_adsorptive * + 1/zeta_lam + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model calculates the product of mass transfer coefficient and +area describing the mass transport through a connection for the laminar flow +regime. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +according to: +</p> +<pre> + βA = no<sub>parallel flows</sub> / no<sub>sorbent volumes</sub> * A<sub>connection</sub>^2 / (8 * π * l<sub>connection</sub>) * &rho / η * 1/ζ; +</pre> +<p> +Herein, <i>A<sub>connection</sub></i> is the cross-sectional area of the connection, +<i>l<sub>connection</sub></i> is the total length of the connection, <i>ρ</i> is +the densiy of the adsorptive, <i>η</i> is the dynamic viscosity of the adsorptive, +and <i>ζ</i> is a loss factor. +</p> + +<h4>Typical use</h4> +<p> +This mass transfer correlation model is typically used to describe the mass transfer +through connections, such as valves between the evaporator and adsorber. +</p> + +<h4>References</h4> +<ul> + <li> + Lanzerath, F. and Bau, U. and Seiler, J. and Bardow, A. (2015). Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 21(3), 248-257. DOI: https://doi.org/10.1080/10789669.2014.990337. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + Minor revisions after restructuring of the library. + </li> + <li> + November 30, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end LaminarConnections; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/PoiseuilleFlow.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/PoiseuilleFlow.mo new file mode 100644 index 0000000000000000000000000000000000000000..9d0fbc62778a3aa394e1f91be4b7ed8e4e4b5750 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/PoiseuilleFlow.mo @@ -0,0 +1,104 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven; +model PoiseuilleFlow + "Mass transfer correlation describing mass transfer through a particle due to Poiseuille flow" + extends + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + final computeTransportProperties=true, + final avoid_events=false); + + // + // Definition of parameters + // + parameter Real f_correction = 0.5 * geometry.no_particles * + geometry.V_particle / ((4/3) * Modelica.Constants.pi * (d_pore/2)^3) + "Fitting factor to account for a whole bed (i.e., can be considered as number + of pores per particle" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Real tortuosity(final unit="m") = 5^2.6 + "Tortuosity for Poiseuille flow" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.Diameter d_particle = geometry.d_particle + "Diameter of one particle" + annotation (Dialog(tab="General", group="Mass Transfer")); + parameter Modelica.Units.SI.Diameter d_pore = 25e-9 + "Average diameter of the pores" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.Area A_pore= + Modelica.Constants.pi/4 * d_pore^2 + "Cross-sectional area of one pore" + annotation (Dialog(tab="General", group="Mass Transfer")); + + parameter Modelica.Units.SI.MolarMass M_adsorptive = 0.001801528 + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Mass Transfer")); + +equation + beta = geometry.no_hydraulicParallelTubes / geometry.no_sorbentVolumes * + f_correction * 1/32 * fluidProperties.p_adsorptive * d_pore^2 / + fluidProperties.eta_adsorptive / tortuosity * A_pore / (d_particle/2) * + M_adsorptive / (Modelica.Constants.R * fluidProperties.T_adsorptive) + "Mass transfer coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model calculates the product of mass transfer coefficient and +area describing the the mass transfer through a particle due to Poiseuille flow. +</p> + +<h4>Main equations</h4> +<p> +The product of mass transfer coefficient and area <i>βA</i> is calculated +according to: +</p> +<pre> + βA = no<sub>parallel flows</sub> / no<sub>sorbent volumes</sub> * f<sub>correction</sub> * 1/32 * p<sub>adsorptive</sub> * d<sub>pore</sub>^2 / η / θ * A<sub>pore</sub> / (d<sub>particle</sub>/2) * M<sub>adsorptive</sub> / (R * T<sub>adsorptive</sub>); +</pre> +<p> +Herein, <i>f<sub>correction</sub></i> is a correction factor, <i>d<sub>pore</sub></i> +is the average pore diameter, <i>A<sub>pore</sub></i> is the average cross-sectional +area of one pore, <i>d<sub>particle</sub></i> is the average particle diameter, +<i>θ</i> is the tortuosity factor, <i>M<sub>adsorptive</sub></i> is the molar +mass, <i>R</i> is the ideal gas constant, <i>p<sub>adsorptive</sub></i> is the +adsorptive pressure, and <i>T<sub>adsorptive</sub></i> is the adsorptive temperature. +<br/><br/> +The product is enlarged by the number of hydrualic parallel flows +<i>no<sub>parallel flows</sub></i> to account for parallel flows modeled by just +one flow. The area <i>A</i> accounts for the disretization due to the division by +the discretization number of the sorbent volumes. Accordingly, the total product +of mass transfer coefficient and area <i>βA</i> describes on heat exchanger +tube. +</p> + +<h4>Typical use</h4> +<p> +This mass transfer correlation model is typically used to describe the mass transfer +through a particle that is dominated by a Poiseuille flow. +</p> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Kast, W. (1998). Adsorption aus der Gasphase: Ingenieurwissenschaftliche Grundlagen und technische Verfahren (in German). VCH Verlagsgesellschaft, Weinheim, Basel, Cambridge, New York. DOI: https://doi.org/10.1002/bbpc.19900940122. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + June 06, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PoiseuilleFlow; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/package.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e270d3b7962744843de1aef17613cb85406cb2d6 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/package.mo @@ -0,0 +1,65 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber; +package PressureDriven "Correlations for pressure-driven mass transfer coefficients describing the mass transfer within closed adsorbers" +extends Modelica.Icons.FunctionsPackage; + + + annotation (Documentation(info="<html> +<p> +This package contains correlations for mass transfer coefficients describing +the pressure-driven mass transfer within closed adsorbers: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.ConstantCoefficient\">ConstantCoefficient</a>: + Generic mass transfer correlation with constant mass transfer coefficient. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.ConstantSpecificCoefficient\">ConstantSpecificCoefficient</a>: + Generic mass transfer correlation with constant product of specific mass + transfer coefficient and area + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.DarcyPorousMedia\">DarcyPorousMedia</a>: + Mass transfer correlation describing the mass transfer through a packed bed. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.DarcyPackedBedSpheres\">DarcyPackedBedSpheres</a>: + Mass transfer correlation describing the mass transfer through a packed bed. + with spherical particles. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.KnudsenDiffusion\">KnudsenDiffusion</a>: + Mass transfer correlation describing the mass transfer through a particle due + to Knudsen diffusion. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.PoiseuilleFlow\">PoiseuilleFlow</a>: + Mass transfer correlation describing the mass transfer through a particle due + to a Poiseuille flow. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.KnudsenDiffusionPoiseuilleFlow\">KnudsenDiffusionPoiseuilleFlow</a>: + Mass transfer correlation describing the mass transfer through a particle due + to Knudsen diffusion and a Poiseuille flow. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow\">DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow</a>: + Mass transfer correlation describing the mass transfer through a packed bed + with spherical particles and through the particles due to Knudsen diffusion and + a Poiseuille flow. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.LaminarConnections\">LaminarConnections</a>: + Mass transfer correlation describing the mass transfer as laminar flow through + fittings. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PressureDriven; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/package.order b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/package.order new file mode 100644 index 0000000000000000000000000000000000000000..a8898544bb6aff5f873781d40200665796444719 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/PressureDriven/package.order @@ -0,0 +1,9 @@ +ConstantCoefficient +ConstantSpecificCoefficient +DarcyPorousMedia +DarcyPackedBedSpheres +KnudsenDiffusion +PoiseuilleFlow +KnudsenDiffusionPoiseuilleFlow +DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow +LaminarConnections diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/package.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d0380581d288496d598ecd1c3da7434a78574432 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/package.mo @@ -0,0 +1,30 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations; +package ClosedAdsorber "Correlations for mass transfer coefficients describing the mass transfer within closed adsorbers" +extends Modelica.Icons.FunctionsPackage; + + + annotation (Documentation(info="<html> +<p> +This package contains correlations for mass transfer coefficients describing +the mass transfer within closed adsorbers. The correlations are either valid for +pressure- or loading-driven mass transfers: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven\">PressureDriven</a>: + Correlations for pressure-driven mass transfers. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven\">LoadingDriven</a>: + Correlations for loading-driven mass transfers. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ClosedAdsorber; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/package.order b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/package.order new file mode 100644 index 0000000000000000000000000000000000000000..ebeabb2d4bbff6ac6389ed89eec49511378bc9d4 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/ClosedAdsorber/package.order @@ -0,0 +1,2 @@ +PressureDriven +LoadingDriven diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/OpenAdsorber/package.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/OpenAdsorber/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..fba80f4eba48520702f26b0dcb4345642f5bf5e1 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/OpenAdsorber/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations; +package OpenAdsorber "Correlations for mass transfer coefficients describing the mass transfer within open adsorbers" +extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains correlations for mass transfer coefficients describing +the mass transfer between gwithin open adsorbers. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end OpenAdsorber; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/OpenAdsorber/package.order b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/OpenAdsorber/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/package.mo b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9ba726098e70f35d8cdcbd0ec2fff64b833da4c3 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/package.mo @@ -0,0 +1,30 @@ +within SorpLib.Components.MassTransfer; +package MassTransferCoefficientCorrelations "Package containing correlations for mass transfer coefficients" +extends Modelica.Icons.FunctionsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains correlations for mass transfer coefficients that can be used +within mass transfer models. The correlations calculate the mass transfer coefficient +as a function of fluid property data, gemeotry, and flow regime. Correlations for mass +transfer coefficients are implemented for the following components: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber\">ClosedAdsorber</a>: + Correlations for closed adsorbers. + </li> + <li> + <a href=\"Modelica://SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.OpenAdsorber\">OpenAdsorber</a>: + Correlations for open adsorbers. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructering the library. + </li> +</ul> +</html>")); +end MassTransferCoefficientCorrelations; diff --git a/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/package.order b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c9cfef3619c0953cdd34f597cacecab414d9de33 --- /dev/null +++ b/SorpLib/Components/MassTransfer/MassTransferCoefficientCorrelations/package.order @@ -0,0 +1,2 @@ +ClosedAdsorber +OpenAdsorber diff --git a/SorpLib/Components/MassTransfer/MassTransferDiffusion.mo b/SorpLib/Components/MassTransfer/MassTransferDiffusion.mo deleted file mode 100644 index ae54ccba38b1b1ad785d4b07468bc32fc7d3d85a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferDiffusion.mo +++ /dev/null @@ -1,137 +0,0 @@ -within SorpLib.Components.MassTransfer; -model MassTransferDiffusion - extends Partial.PartialMassTransfer(final computeTransportProperties=massTransfer_diffusion_dp.computeTransportProperties or massTransfer_diffusion_dx.computeTransportProperties); - - /************************* VLE models ************************************/ - - TILMedia.VLEFluid_ph vleFluidAds( - p=vlePortB.p, - final vleFluidType=vleFluidType, - computeTransportProperties=false, - computeSurfaceTension=false, - h=inStream(vlePortB.h_outflow), - xi=inStream(vlePortB.xi_outflow)) annotation (Placement(transformation( - extent={{56,-40},{76,-20}}, rotation=0))); - - /********************* AdsorbentAdsorbate ***********************************/ - - replaceable model AdsorbentAdsorbate = - SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater - constrainedby - SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater - annotation (choicesAllMatching=true, Dialog(group="Adsorbent / Adsorbate")); - - AdsorbentAdsorbate adsorbentAdsorbateA(x=xA_eq, T=T) annotation (Placement( - transformation(extent={{-100,-40},{-80,-20}},rotation=0))); - - AdsorbentAdsorbate adsorbentAdsorbateB(x=xB, T=T) annotation (Placement( - transformation(extent={{80,-40},{100,-20}},rotation=0))); - - /***************************** Mass Transfer model **************************/ - - replaceable model MassTransfer_diffusion_dp = - MassTransferPhenomena.ConstantCoefficient_dp - constrainedby MassTransferPhenomena.Partial.PartialMassTransfer_dp - "Mass Transfer Model" annotation (Placement(transformation(extent={{-32,-70}, - {-12,-50}})), choices(choice(redeclare model - MassTransfer_diffusion_dp = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantCoefficient_dp), - choice(redeclare model MassTransfer_diffusion_dp = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantSpecificCoefficient_dp)), - Dialog(enable=inputChoice == "dp", group="Diffusion")); - - MassTransfer_diffusion_dp massTransfer_diffusion_dp - "Mass Transfer model for diffusion resistance"; - - replaceable model MassTransfer_diffusion_dx = - MassTransferPhenomena.ConstantCoefficient_dx - constrainedby MassTransferPhenomena.Partial.PartialMassTransfer_dx - "Mass Transfer Model" annotation (Placement(transformation(extent={{-32,-70}, - {-12,-50}})), choices(choice(redeclare model - MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantCoefficient_dx), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantSpecificCoefficient_dx), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.MassTransferPhenomena.Glueckauf_dx "Glückauf-approach dx"), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.MassTransferPhenomena.GlueckaufArrhenius_dx - "Glückauf-approach with temperature dependance dx"), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_Zeolite13X_des - "Diffusion coefficient and particle diameter for Zeolith 13X desorption (Lanzerath 2015)"), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_Zeolite13X_ads - "Diffusion coefficient and particle diameter for Zeolith 13X adsorption (Lanzerath 2015)"), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_SilicaGel - "Diffusion coefficient and particle diameter for Silica Gel 123 (Lanzerath 2015)"), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.Record.DiffusionCoefficients.SakodaSuzuki1984_SilicaGel - "Diffusion coefficient and particle diameter for Silica-gel Fuji-A-type (Sakoda Suzuki 1984)")), - Dialog(enable=inputChoice == "dx", group="Diffusion")); - - MassTransfer_diffusion_dx massTransfer_diffusion_dx - "Mass Transfer model for diffusion resistance"; - - /****************** General parameters *******************/ - - parameter String inputChoice="dp" "Driving force of diffusion" - annotation (choices(choice="dp", choice="dx")); - - /************************* Additional variables ***************/ -protected - inner Modelica.SIunits.Temperature T "Temperature of adsorbent"; - Real xB "Loading of adsorbent"; - Real xA_eq "Equilibrium loading of adsorbent given portA.p and T"; - -equation - adsorbentAdsorbateB.p = vlePortB.p; - adsorbentAdsorbateA.p = vlePortA.p; - T = vleFluidAds.T; - - if noEvent(valveOpen) and inputChoice == "dp" then - vlePortA.m_flow = massTransfer_diffusion_dp.beta*(vlePortA.p - vlePortB.p); - elseif noEvent(valveOpen) and inputChoice == "dx" then - vlePortA.m_flow = massTransfer_diffusion_dx.beta*(xA_eq - xB); - else - vlePortA.m_flow = 0; - end if; - - annotation (Icon(graphics={Bitmap( - extent={{-80,-60},{82,70}}, - imageSource="iVBORw0KGgoAAAANSUhEUgAAA3kAAAKJCAYAAAAGFeB4AAAAAXNSR0ICQMB9xQAAAAlwSFlzAAAXEgAAFxIBZ5/SUgAAABl0RVh0U29mdHdhcmUATWljcm9zb2Z0IE9mZmljZX/tNXEAALKxSURBVHja7f19iBx5/ueJqW2uu7BPTRmr2eJkQ1nsqbP6OJPsYFH7h0wZy0sdYo9EBrsEBiW3IMo+caSUkrusPU615nw1sKzq1iDXzO8ECdZ6ysIDJa7PUx6qsnK4QVPM9kCC7J9zfnhMwsBQ/cdADQNDzZih0/n+VnyzIyMjn+M5XgEvuvWUmRURGfF9xefpyj/7Z//sCgAAAAAAAGQDdgIAAAAAAACSBwAAAAAAAEgeAAAAAAAAIHkAAAAAAACA5AEAAAAAACB5AAAAAAAAgOQBAAAAAAAAkgcAAAAAAABIHgAAAAAAACB5AAAAAAAASB4AAAAAAAAgeQAAAAAAAIDkAQAAAAAAAJIHAAAAAAAASB4AAAAAAACSBwAAAAAAAEgeAAAAAAAAIHkAAAAAAACA5AEAAAAAACB5AAAAAAAAgOQBAAAAAAAAkgcAAAAAAABIHgAAAAAAACB5AAAAAAAASB4AAAAAAAAgeQAAAAAAAIDkAQAAAAAAAJIHAAAAAAAASB4AAAAAAACSBwAAAAAAAEgeAAAAAAAAIHkAAAAAAACA5AEAAAAAACB5AACxXYiuXGl26QRAq0vDxXaXzS5rXRbY1wAAAIDkAQCEL3gLAQneJBx2KXdZZN8DAAAAkgcAEK7sKdq2H5HsXXTZ67LEvgcAAAAkDwAgXNk7GCNo504appeak6J5OoXs6bUq7HcAAABA8gAAwpO8jTFi1pjgNZQCuu5E6y4mkL0mKZwAAACA5AEAhCN5a2OEbGfK11vqsjuB7CF6AAAAgOQBAMQgeaUZX7fQpY3oAQAAAJIHABCt5JXHiNjiHK+9OMG4hlOOAwAAACB5AADBSd7WCAFrB/D6St88GyN6ZY4FAAAAIHkAAMFI3qgxCvsBvce4lNAzhqcDAAAAkgcAEIyAjUqnrAT4PrUxorfL8QAAAAAkDwBgfvka1QWzGOD7rI6RvDbHAwAAAJA8AID5xKs4Qrougk6hnKAJS4HjAgAAAEgeAMDs0lWOsutld9seI3kVjgsAAAAgeQAAs0tXLcoauQkasBxwXAAAAADJAwCYXbqaQQ9BH/N+i9TlAQAAAJIHABCO4I0TruUYxLLDsQEAAAAkDwBgNtlaHzW3LsT3bYyRy0WODwAAACB5AADTy9Z2HLVxem06bAIAAACSBwAQrWxVQnzfcUPR1zg+AAAAgOQBAEwvW+dxiBaSBwAAAEgeAEDwolUYI1oLIb43kgcAAABIHgBAwKI1agh6M+T3HleTV+QYAQAAAJIHADCdaO1FOQTd896NOEY3AAAAACB5AJBlyRs1q64c43szQgEAAACQPACAKSVrIc4RBt2tzTB0AAAAQPIAAIKTrLURknUewftfjHj/FscIAAAAkDwAgOkkayuOIejOexfHRBH3OUYAAACA5AEATCdao7pbbof83uUxkrfFMQIAAAAkD2BOvvfl0eLNan2z8LS+vVKt7xUenzR6VOv7+v3ufytfVBvL7K9MSN6oIejrIb/33hjJK3GMAAAAAMkDmIEb3z9a6Ipb+fNq/aD7386kfF49bkr4JIbsx1QK3nKcnS0n6Ky5xHECAAAAJA9gSrqSVvr8yfHZNHLnI3vnkj32Z+okbyPGIejjunrSdAUAAACQPIBpuFltFApPTw7nkTsfWoVnR2vs39RI3u4IyarFKJih1wMCAAAAIHmQLcF7XF93om9DZO24vfKkvqsUTklbj2q9pJo8J01zlOyV2c+pkLw4h6AfjpG8VY4RAAAAIHkAE2DE7cnxhZ+cqdHKF18eFSd5HTVecYTPXxa7f8b+TrTgLYyZUVcM8b2Xxghem2MEAAAASB7AJIL3rL7hK2SPTxpK35zlNbtSuGS6cCJ6aZO82Iagj5nNJ3Y5RgAAAIDkAYzB1OD5R/ACmUWmFNAhr19i/ydS8iojJKsR8nu3Rrz3xaRdNa/sdUX1h+F2AAUAAABA8iCROCMSWn3ydSlk5SDfR6me3vRN/ZqZeomUvFiGoGv23Zgo3t5Er/PDK+tXftAVwh9caV55dYXzCwAAAJA8yBdd2apF1Rzli+rRqjeid7N6fMpxSJzkteMYQj7BbLzihJK3aATvh91/88Puz4LoAQAAAJIHeUHRNR/BC7U9vmbmkbaZaMGLZQj6mBRRcTDV6yF6AAAAgORBHvm8Wj/wzrJT+mbY7+udwaexCxyPxEheKerOlk5HzbMxtXhTSxqiBwAAAEge5IohUbxS1t8bxgpX5EPQx7yn2Jz5tRE9AAAAQPIgL2iEQZzRNG8UUb/muCRC8k5HyFYlhPdbGzOTb+5unogeAAAAIHmQC9TwpC+S9qy+EeX7D0TznhxfRJEqCiOFK9Ih6N2toLl7QadpInoAAACA5EHu+N6XR4tewdLvRf05CtXjdr9oHq1xfGKVvLUxwrUQ4HstjuniqfdbD/Tnk+j9zZUGogcAAABIHmQOjUjok6vHJ404PsfKk/qupy5vh+MTq+RtRzEE3YkYno6pwwslstyVu4Uuhz3R+2Gw0UkAAAAAJA/ikrydPrl6Wt+O6XOU+j/HySHHJ1bJa4yQrt2A3kMRvMMxglcJ9ed0i94PrpwjegAAAIDkQRYkrxZnPZ7lZrVRYJRCYgRvXD1eKYD3WB8zKiF0wfOI3r4jehfd/65zHgAAAACSB+mVvMcnjSTUwnlrAz9/cnzG8YlN8tbHyNfyHK+t6F1tzOtfhJWiOfKz/aD7uazo7V0pcy4AAAAAkgfplLxqveWWqy+qjeXYPsuT4wv3Z+H4xCZ5+0EPQXeGnG9OEL1Th83V2H52K3pi7wp1oQAAAIDkQRolr7+rZZyS93n1+BzJi13wlsakah5M8VqK2pXH1Pe5UX3eUuz74IdXKj3Ru0zjZJwHAAAAIHmQIsnzpGt+UT2KJYqiuXjeUQ4cn1gk72CMiDWczpvrzpgFseH83rbz7xtTiF3Hie4lqg5OdXlOIxalb55q5ALnBwAAACB5CUW1Xzer9U11kVyp1veM5Fiq9X39fve/lTgjWpFKnn7m/tEFpTg+h/Z3/+c4bnO+Rip3k9TKBU3bSeFMZKSsK3YFZ7SCInpnV/aurHGuACT6OlZ0PXwqux4+udlxPYial+0RrLmIPUMBAJC8TOJEicqfV+sHHqEZiTo8SvjiGA4eFd75dBLgWGTz2dFaEub15XRhdBih2J07MllKxb7R0PTvZumJbc4ZgMiuTYuOJJVGSNpFxA+ngrgGuj//jutnKzs/7zLHHwDJg3HyUK2X1KlxGrnzkT3VilUyun8q/T9r/SCWz3EZQXXv9xrnbySLqOWQFzSnTgrndpwNVQKQva2e6Cl981/yZB4goGvQmpP+7Ra401muN8VisXPr1i3DvXv3Oo8ePRqgWq123rx5Exh6Pb/3uX//fu+ziDmyHbQ/9pz9s+Hsr0XOHQAkL7eYuWtPTw7nkTsfWnGNGAh1P3mENhbJGxjlEM+8vhwusBY9aUVBkTkJuvLqymovfVP1eoxZAJj0OrPqSp+cuGb3+vXrA8K2s7PTE6x37951/u7v/i51HB4e9n6GV69e9X62Bw8emJ/3xo0bk0pg0xUNrDjXXhpFASB5GRa8x/V1b6dGb72Xk6ZYNmmClmq9pIiSk6Y5SvYytbjzdtiMWmS/+PJoybuPs5wiCym+GCt98wdXDlzpm0rlLLBvAIzMFVyplYrgt0ZJyqeffmqk5s6dO0Zytre3jfhIgtIob0Hz/v17sz8ktto/kl3tr2vXrk0aAbTRv9RmUQAgeeASlq64eeatWdRopSsUxYnEQ41ALoXPXxa7f5aVfWYa0MSYsjlYF3h8yrkMib4o710pu7pvXqhWj1ELkCOZW3KiRltOje3IyJyNxtlUybdv3yJxAUYEnz9/3osCfvLJJ+MifweuDsnLnM8ASF46BO9ZfcNXyB6fNJSWOMtrKsrklaCsiZ4in96fbVIZnhcTxRuU8grnMyT+wvwvuwtd9/D0H1xpafQC+wYyKHUFpxNubVR0TmmGNir3+vVrInIxcXJyYuRPx+Hu3budlZWVcSNsDhxhX+N8B0Dykicqqi3zj+BtBSZC/q9fysL+86aoRhXN80bx1CRH3VA5pyE1F+jLmXqtnuz9zZUG4xYg5VK35kR7Dp1ukL5plg8fPjSphETm0oFqGF++fGnkb0zap63zKzH+AQDJixVnRELLO0w76No5Rbe86Zv6dRZm6pl6xIhrDzV4nSgeZET0Frpit9NL4UT2ID1Ct+Qs5neHdbVUhE7plqqZIzqXvaifxE/dQEdE/FpOFFfR3CLfGwAkL0pBqUUlKH5ikpUasoGGM92fc9Y013GosYq34QtRPMiA7C2a+jyv7JHGCckSu3VH6lrDRhEoSqfOj2r+gQzlhw8fPphUWxvtG1Ljp+juvtMxlUgfAJIXDoqu+QheqDPWvLPlspK26Z/yetwOuj7PCJ7/eIvU70MAR/YWulS6nLk6cbaNAL6i2QFELnXLThTmwDs8XKmXt2/f7jVFQXTAi9Jx1dxF9X1DUjybTnonXTwBkLzgUO2Yd5ZdFNEgr6QoCpaF/Wm6k/oNgw9orIIarfiNqFBtHuczZFT2Nvtq9i6btDSNBCJ8EI7ULbhSMAeidUrLU6SOWjqYtaunpE8PB4jyASB5oTAkilfK+ntHIHqD6a+XEb65mtiY+YVPjs+8r610V9I0IfMX8r0ra12x2++TPSt8qud7xVNwmEvsCs5A7EO/RimKwqhJCumXEHR6p9J6VdOn4fVE+QCQvGBk5Gl9O85omjeKGPV8uchFz4mUThvVM0Lsn55pBI/B55CrC7rq9jRnT8J3OWPPLXwXzrD1TaJ8MKHYbROtg5RE+TSuYY9RDQBI3lgkCH3S8Ky+EeX7D0TznhxfZCki5ZVob62eUizViMb/2DQKTu1ia9hrSIqJ4EHOhU/pnKUrf9Nd+HhTOm0dn/7sv7iyobl87DMYJnZqkEG0DpIa5fOp5Ws76cRFvteA5EEfl90Z+wUrjoiQt0NkULVriRG9ar3sHRsxXNoGa+1GsMN5DOC52L+6suyK8p37St9lymeF9E7EzoqdWuBrQY1YQJJRYx+EDwDJm0g++qTh8Ukjjs/hHeadRXlRs5QR6ZvT0T1OQXfrBMjsxf+HV4pdtroc+kqf0jsvRzRsm6HsP7yyyH5D7ABSLnw67wtcBwDJy6/k7fTJw9P6dkyfo3+I+NOTw6zuc6Vm+nQznVjuGJEAMLf0FUyk7wdXakPSOy+jfZd1fdtOsxdSotMjdovOqAPEDnLDu3fvOg8ePPBr3KLvwRZdOgHJy5/k1eKsx7M4tWeZG6UwCidVtmyE71LefBuqOH9WUSSQcxYgFOlbNBE8dedURM/byOW7iF/LSfPckvix7xInd6tdau4ZdogdIHx9wqexDOtcLwDJy4PkeeUiplo4b22gRgRwfAAgRvErmEYtP7yy66RydoaIX9NEBC87eVLfF73Y+UbtisWiaZ6C2EHeUWfYe/fumQcennROonuA5GVa8jxdG7+oNpZj+yyXM+R6n4XjAwAJE7+iSfO87OJ5OkL8To0cXjZ/oSYmHLkbiNppjp3qk9R+nsU9QD9ff/11Z3t7u3Pjxg2ie4Dk5UPy+rtaxil53u6THB8ASPyN5VVXNhTFu6zvaw6RvnOnvm+LaN9cYucbtdMsMaVjspAHmDu6p4Hry1xvAMnLguR50jWHzWsLG815845y4PgAQCpvNpeNWrac+r0zX/Hr7+ZJU5fRcldwonZ/tgtSdRPUkPKTkxMW7QDBR/cOie4Bkpd2yavW9z3NPkpxfA5FEL1Dwjk+AJCJm4+d2zd8WLtN8dwm0tcnd2tdDtyLTzVRef36NQt0gGiie80uZa5HgOSlEO98upvV+mYssvnsaC0J8/oAAEK/GV128yyZbp5+tX2X6Z01p/FL7qJ8WlQ6i8terZ2idu/fv2cxDhBBdK9arXpn7505jVoWuYYDkpcS1Jq/f3RB/SCWz/G0vu2JKNY4PtnCjozQsV6p1vdMqrBFEeXLc6ASZ10oQKzSp0if5vMNRvr2JXwZFzvV21WcxaRZWKr9+/Pnz+mQCRAT6lC7srLilj01Otqjbg+QvBTgM5/uPBbJGxjlUM/0giZPYqfosIbbTzP0XXMSmQ0IOZa+gknd9DZyUYRPIvgqOwssLRa77Hb5g11IalFJIxWA5KAUaTU48tTtKZV6jWs2IHkJxtthM+pZeVrIexf5kgOOTdrPq3pZ8w6nkbsBNFbjaX1bjXnYp5DLG5fq+X54peJTy3eY5oHs3a3otG7vLRrv3LnTefPmDYtqgISiIeuq2/PI3mkXHswDkpdETOpcjCmbg3WBx6ccl/TSlfaijuFccueN7F3KYon9C7m+iSnCd9m85aJP9lI0i8+Ru14zFTV50KKR2XYA6UH1saqTVb2sZwRDmWs1IHkJ4ubj+rp3Ua2FekRCsOQdgq40PY5Les8l77xDD60uO6Y2T812LF2BMzV53rTdQXbYz4DsXVnsit5/1tW9PzhpnBemicsPk9sUwSt3NFMBSD9q0qK6WU+TFjVN4qEsIHlJwamBijya543iKWJDal5KBU+1dyNSLidtqOKk71ZGpHruc45Arm9m6rp5Gc3bdbBRvbOkNWjxk7tHjx6ZxSGLZIBsoOZIyB4geQnFRFIGF9PlMN9Tg9eJ4mXm/NnyFbKnJ4ezdst0unHuDBM99jvk9mb2w6442Qjev7yy5KRxNlyD1vfiHr3gl5b54MED5A4gf7LXoEELIHkx443mScDUfTOM97pcwPc3fCGKl1LB8844DHjm4ogUUB4IQJ5F79AI3d53NTBOhO/cEcCmuwtnVEPWh8kdaZkAyB6yB0heTJhxCgORteN20PV5RvD8W+qXOA7pQqmV3rRKCZnELOD3KQ6kb3bPVUWDOQ6QU8mrOJG7Xc/vF3qdOCV8e1fWTOTP+X/kDgBilr1DXS+4jgOSFzGmIcbgzLLzoMYqGCnwRgy7qDaP/Z8+VLs5EMELWPDcDyEGI3rHbaK/kFPJW3dSMxs+f7ZgBqhfit6fu3xjh6qHIHdLXWrulur3799H7gBgnOwdMFQdkLzoRa/m2zyjWt+aa5GutDufZhpqt89CPX0oujZYg1ffDvncLJG2CeB02HTX5Ym9K2UzRP2HVzadOr3ve4apm78bkNwtdNlyDzHXKISTkxMWtQAwUvZcoxf+3GWnyyLXdUDy4hQ92wJ/yqiekQH/9EwjeAw+TycDEdnHJ40o3ndgriO1nJBf0TvspWX2D0q3tH1+b+6HIt1t3ZmJZRZqt2/fZs4dAEyMGjApndsV1Tvrssl1HZC8qERPc8uGzis7bivFclhNlKnvq9Yrzlw0/wHX1foBi/N0wmxFgATc1F5dWe4K3qlL9PZNJO8HV2pDpE/8dg65Kzj1NGZhduPGjc7r169ZtALATOjhkB4SecYurHF9ByQvCtGr1stjhlu7a/eak/w9hlpn4ryoxTFX0eKdr6iIMMcFwLnZXQ5G74xgqrpZpVJ12XXPulPKFYtUAAgCPSzSQyPq9QDJixhnOHVtCoEbzuOTRlQRHwhT8vrHXwTVmGeqc9ITzdPvcWwg9ze6y3q8zkh+cOXDFIK3+dFHH31jF1/MugOAsPCp19ulXg+QvCgW1tWjVb9uipPKHSMSMiP9RW/31VhE8/Kccp9nZY4P5Fzw1scKnmXvyt0xcrfmpE5RdwcAkeFTr3fepcI1HpC8CLgcZK40zq7wDS60e+lzzp9ViLBkC3VZ9RzvWp4/B0AibnCX9XkXE0veD66cDZG7RfdIBOruACAOfOr1TrswGxeQPICw8Ha3vFmtx9IRS5HlOLp7AiT2Jnc5VqF05W+u7PUGoo+m5BG8sk3NpO4OAJKAHjJdv37dLXsauUDTPkDyAILGm7Ib1vDz8ZLXWPZ2fOX4ALhueoruXc7OU9fNM59o3rkZnH450LzXNfPOnTsMMweAxKD5eg8fPnSLXkujXLjOA5IHECAmFTeG0Ql+9Enek+MLjg/AiJugBqT/8Eqly3/ZFbxvjeg9uPKV0+Cgc+3aNVIzASCxvH371tuFs0ZjFkDyAAITq/7OmoqoxfVZNAjd/Vk4PgAT3hAfXXncFb3OlX/e5d+40rl37x5dMwEgFVG9arXa+fjjj791DVIvc11H8mbCNhrRcHBTj6SGIpZqfd8ZGl6Jc7ELEJlYeeYhavB9fMLZ3/CH4wMw5kZ4xaRn7pjF0X98mbb54P/8gMUjAKQKNWYpFovuqJ5Szmn0h+RNJnZqKFF4enI4zagAZwFMR0nILAPfiYhn5Fmc+Y3U5AFMLnjrTi2LWRT9o//tPzKS9/G//Nh0sVOjFWrxACBNKKr3ySefWNH7Q5ctrvdI3qjoQNmbBjY1GtT8tL594/tHdACCbEletV5Lwnw677w+1QpyfAB85a5vLIKefr97984skK7959cum7AUL/9MiyXNqEL2ACAt6HrlM26hwPUfyetbNHqbSsyLI4slDgBkRvIu05N75/jKk/puTLJZ7o+i1w84PgADgrdqo3cSOD31di+Obm/fNpL3b37/3+yUSqXeIsn+XdW/sIgEgDSws7Njxr+4onpl7gNI3hW1gf+8enw+QthaXXbMwvLZ0VqPrsCZRe+QoeAudjgIkAnJuzzv+74bMUnevudzkKIB0C94O+7onWpYvIuif7L5TzpXdi9r806/Oe00m80+2VMnO3W0YwEJACmN6u3TgTPHkmdq70akXE7aUMWpEaqMSPXcJ30T0o7OYfPdiLnDpvehTJwNYAASJncFJ13JLHI0X2pYRM40LvhfXEpe6aeljt0khIVCoRfVYzA6AKQJXbNctXrqwLnK/SFnkqen/75C9vTkcNaFq9ONc2eY6HEwIO14B6JHnbJpIug0XQHwE7yye+7dmzdvhi6C7HDhT/97n3Y++S8+MaLX/H2zJ3oXFxedra2t3hNxjVlg8QgAacGnAydZdXmRPJ+0MyciUN8M4g1HpIBWOCCQZgai30+OL6LsKOsd4xBXXSBAguRuyWkhbhYzd+/eHTn37tWrV72FjxZClV9UBqJ57qjewsICogcAqUNZDPaBFk1ZciJ5WpB60yolZBKzIN9UzVwG0je1IK4eETaG1KKUTe95HZVoDUTxIhZMgAQK3rqTjmSaDqj5wLialc8++8wseF68eGFE7uxPZ52F1wsD0TxEDwCygGqLr1+/bkXvgqYsGZY8b7qZieAFLHjfRT0ahcGI3nGb+jxIM4pID9SwhjwzTynUccklQALlbsE7GsGvuYoXRfn091dXV01Kpt22frllJK/442LHb0P0ACDNKLtB1y5XVO+ApiwZkzzvfK3LGrz6dqTRB9I2IeX4RfP067Cianq/gREnRPEgv4JXcA82f/To0cSpS7YZgTppureLv150lt4sGdFr/K4xVvS2t7dZOAJA6lC6umvUAk1ZsiR53noejT+I4gOsVOt73gUx0TxIM74PL7rfJzUfClrwfIawh/5wBiChgldyZkCZ9KNpRhy8fPnSLGzUOdNv22nuDK3Ns9vu7q55jVu3brFgBIBUorR1XcMc0VOzqk3uLymXPKVkeheKiuxF8QHMiAVP63miefEhETENRLqiYARcsw4tmsF2OfS7Esd4gDShdEnvd0oPUoLab6Zbrd8cyqcnh+x/yKHg9WbfaRbUqOYqfty/f7+vFs+72do8cf6Xc/+/c3bWS3c6OTlhwQgAqcXTlEUz9Qi+pFXyvNEA1ebFuSBW+hkHJzqciFDZryZzFE70txJ0hCozET0fCVOket46Vz2AGUjRdGpaORaQM7lb7NKYNj3Ti61HOTg4GBqpW/tqzUTz9n+zP/TvrK+vm9epVqssFAEg9embV69e/da5vjbpvplayTtu9y0WQ24UMUk0j5qiiESkWi+NGFQ/qeydE331j7b5y5gzc3LKaLm+E970Zk/dX5H9DjkSvGKXtu2e+fr165kXM4r+6XUajcZQgXvxqxdG8so/Kw/9O7VardfshUUiAKQd1RvfuHHDRvSUDl/i/pOi+6S34YoW7AmJepQ5QOGh7qYSjXnkzodW1A8Iko4TJd0fuc+e1reHjQ/RcTLps36pma7XIH0WciZ4G3a4uYRq3vRIW4Pibbri3k6/OTWSt/yj5aF/5/z8vNeAhZRNAMgCSn+33YcZnp6ye2V3gbjlWTDWYoooJeJz5ELwhg+k76X9OSm0ZUlbDzUU6QrJQJOeQRB07/mtWsbB2tNRabATRlHrB6RoQo7kTuMR9uxiQ7V06ow57yLGzolqt9udUdtibdGI3rC6PFI2ASCrPH/+3C16DcYspOCe6U3/UtQgjg+iSEYc3T1zJxsStyGyoXNh0pQ/RY4c4fOXRTo8+u6zaeseR4ogUVPIl+AtdTnVAkPjDsYNN59F8hSJG7UpiifJa/+xTcomAOSON2/eMGYhTfdN76IzrOHnE0mDJ5rEAQpY8J7VN3yloSvUSguc6biNqBND9IYdh6O1WVNlL+WuvsF+hJwJ3upHH330jR2P8O7du0AXLvbp9LhtEskjZRMAsoyua3qIxZiFFNw7vY0h4mze4B3ozAEKDlOD5x/B2wrk9TWGw//1S+x/f8wYBNvVdEjNnfl+Xv4ZYysgr4LXq7+7c+fO1OMRxqF0T7324uJiIJKnbXV11bymnnqzKASArKHrph0947DL/SqB909vZ804F5LeLo8coGBwmn+0vBIddO2cHhB40zf1a+QEAGYUvC27iHjw4EFoT6X1+svLy4FJnn3KTSQPALKMp07vgHl6CbuHeps8zJq2F3gkD8kLcr/WomqOYmorPRE95h4CwAyCV7OLh+3t7dAWKUr9tDV047alN0tG8i7+ejFaBrvCqNcMOuoIAJA0NE9PddLO9fqUhixJiuR5a4NiauZgZuVRkxfGfi36CF6onUuVWkjaJgDMKHcacH5oG6zMM/9uEpRSqfdaW1sbK3kSvIXXC+P/nvPZWQACQB7Qw7Jr165Z0WszOD0pkjcY5SnH8UG8MkL0Jxh8ujm2lL4ZevTQ8/BAEWOOBwCMEbzlLk0tFLRgCLrByjySpxTNcXPytJ2dnXVsgxgWfwCQF5SevrKy4h6cvsZ9LfZIXn27r43+k3osxZOmtb9n/hcHKJQoXinr7w0AqRS8ou2gqYVCVPVsSjXSe5ZKpZHyZoehr301WgZbrRYjFAAglyhF/fbt2+7Om2Xub3FK3uWQ675IT0yStx9G18c84xX4qKNp3igi4g4AQwSvZDto3rp1K9JaNs3b0/uWy+WR8lb7dc1I3sbxxsi/12g0zOtpocOiDwDyiKfz5g73uZjurabzoqdRRhzdEL1dGeNsAJMVvOMxop6vNhDN655nUaSKAkCqBK9iFwP37t0zrbmjXIxMKnmVX1SM5O00d0b+vf39ffN6WuSw2AOAvOLpvLlP580Y7q9+EZeoUzaVxkfTlWBxZrD1CZZ+L/JoomdER1yNfQAgkYK3ZxcBDx8+jHUhUqlURs++e7dqJO/wt4ejZbD7Ono9vS4LPQDIM3TeTIDk3azWN71CoG6XEUbxmkmoC8wS3hpHDdSO43PoWHrScAnbA0BvRIIWAIqmxbUIefTokVmAvHjxYqS8qaumJO/8L+cj/976+jqD0AEAHDydN5uIXsSSpxQ67yDyqERrIIoXsWBmWPJ2+vbr0/p2TJ+j//g+PTnk+ADkWu4WnNSdSEYkBCF5zd83J+qsaWbpLS0xIw8AwIUaaanjMKIXg+Q5i/GKV7bCTq1T7V9ccpkDyavFWY9nUW0loxQAwCV4Zgbe1atXv41b8IRtELC7uzu26Urpp6M7cJ6fn3fs+AcWdgAAQ0VPs/SWuS9GJHl+0Tz9Oqyomt5voDEIUbzgJO/xSSMJtXDe2kCdUxwfgHwL3qeffhrJDLxJsGlEp6enQ+Wt/LOykbzdD7sjJe/w8JDOmgAAI0TPNUsP0YtK8pzoT2lgtllXFoJu2GE6eg4OYY8tpTCjkbxW3B1Te5/F072V4wOQO8FbtEPOkyR4dhD68vLoNMzF2qKRvNZ5a+TfUzRQr/fgwQMWdAAAPiiV3SN6dNOPQvKET6MMk2IXlCSYyI43ykStVgiS19/VMk7J847H4PgA5FPwlKoT1ZDzSZCM6XNtbW0Nn3v3u8bE9Xi26UqcjWQAAFImeudditwvI5A8Iwg+EqY0u5uP6+vzvJnmpg2kaDojE+Jo759pyfMcwy+qR6txfA4natuXksvxAciN4C13aSVR8IRdZGiA+bj5ePrvqO3s7Kw3E+r9+/cs5AAARqCZqEptd66bf0D0IpI8CZe/jF1G3CRrU8rd0kq1vuf3ek7dHwc28Ehefd+zr0txfA5FEJmBCJBbwVMqjpGppHWblIjpsy0uLo6UN0XwJHmK6I3a9vb2zOvdunWLBRwAwGyit879M2TJc0Vg9n1F75KWauiGRYjUVdHM3/NLzXS9RpxphFnGm3arYxGLbD47WkvCvD4AiFTwCkkWPGGHoJfL5aHipho8CZ5q8i7+ejFS8tbW1szrbW9vs3gDAJhC9O7cuWNF7wLRi0Dyeov0rsh5G2cMwzvUfPTfrR+QohlqJK/i3d+xfA6dP/3HvsbxAchHBE9PaHUDT+LCYpJUzZ3mjpG8jeONkYLXbrc7du4fqZoAANNz7949RC9qyRNmnl1XEiYVuLEiGFM7/zzhM5/uPBbJGxjlEM+8PgBA8CyazzdJV83Vd6tG8jQnb9SmRiuMTgAACEz0qNGLSvJ6C3al3j09OZxd7ljgRxvN6++wGbVcqxbTex4QvQXIrOAtulM0kyx4iriNG4De/mPbCN7C64XO+V/OR8vg6ipdNQEAAsCVuonoRSl5FmfAddlE94bU3JnGLZd/VqHuLh68zW6iTtkcrAs8PuW4AGRW8JpJrsHzCt6oWjx3qub6T9Yn6qqp103qzw0AkBY8zVjOmaMXseRBOtDIC698R9XJ1ETxBms5KxwXgOwK3o0bNxIrOhrAbkccjBM800jlq7WJUjVtV01SNQEAQhE9ZYgQLELywIu3GU5U0TxvFE+jMtSxlWMCkCnBW+jSSOocPL8UoI2NjbGCd/ans4lTNV+8eGFet1qtsjgDAAhQ9FwD0xE9JA+8aD6eTzptOdQoXvVolSgeQC4E7zANgmejeEtLS53z8/Oxkrf3t3sTpWpq29zcpB4PACAElBniEb0l7r9IHoyI5knA1H0zjPe6rNfsb/hCFA8gu4L36aefdg4PDxO9ULBRPInYJNukqZraSqWSee03b96wKAMACFf0VBqwyH0YyQMHM05hILJ23A66Ps8Inn/31RLHASBTklezgqcoWZLTfWxL7oWFBdMkZdymoedK05TkjUvVdA9BT/J+AABIM8oUUcYIoofkgQ9K0fQZa3Ee1FgFNVoZiBh2UW0e+x8gU4K3Z7tJvn37NrGLAn02NYLRZ11cXOzs7+9PFMU7aB8YwSv+uDjR39esPb0HQ9ABACITvVNllHBPRvLgO9GrDUTZLiN8W3NFCh/X15WS6TdGgzRNgEwJ3pYVPI0jSGr07uHDh71OmsVisdNqtTqTbpVfVIzkvfjVi/FRv4uLjo1osggDAAhf9K5du2av7wfcl5E8GCd6l7Smjeop3XNIeqYRPAafA2RK8DasOL18+TJxN3/VbWxvb7sXAJ2trS0jYtNsiuBJ8hq/a4z9u5JHOxuQBRgAQPgoNd7OO+1CthiSB32i97S+PUT0TK2eUizVIdM3aqf6vmq9YqRwyGtoTAMRPIBMCd5alz8nbVSAonZqpqJonRU7sbq62jk9Pe1Mu6kGz45OUG3euE0NZ/R+auzC4gsAIBqUSeK65m9yn0byoD+iVzY1eUNlr692rznJ33PYYf8CZErwCl3+oJvp/fv3E3OT90bthJqg1Gq1zqybrcdTd81JNjsj78GDByy8AAAiRA/4XNf/de7XSB64ULOUEemb0/H4pBF0t04AiF3wlpzZRJ3bt28n4sauUQW2oYqtuZPYTTL/btxW/lnZSN7uh92J/n6hUDCfIan1iQAAWebRo0f2XnDRhTUokgcDslc9WlWK5axyx4gEgEwK3oLTqtrUnCk1Ms6bubpX2nl3QoJ1cHDQCXJb/tGykbzm75tj/67SQW3Tlbj3DQBAXrFjcrqcdVnm/o3kgQ+Xg8yVxtkVvkt5822o4vxZRZFA9htAZiXPDDtXy2p1NItb8GzrbI1DmHSo+Sz1eIu1xYn+/u7urvk8WmCw0AIAiAc9ZFOmiSN6LWboIXkAADBc8HaTNOzcjkRQauYkA83nqcdb/8n6RH9/Y2PDfKbnz5+z0AIAiBF1V1bGiSN6DWboIXkAADAoeJWkzcKzN+9Go9EJa5tmPp67Hi/JA+EBAPKCO+Ojyz73cyQPAAC+E7ySrXlTSmRSntDq8ywsLHTC3NRRc9L5eHYIuqAeDwAgGWiszdWrV791rs+57/bOwgYAAOyoBHUoMx3LknLTVjdNOx4hrE0z8TQbT5Kn2rxJm64wBB0AIFnonvHxxx9b0SsheQAAkGfBW3AK1hM32FvD1/W5tra2QpO8029OjeAVf1yk6QoAQMrRHFVH8jTjtYDkAQBAXiXvQDdEzZ9TemSSbtZ37941N+v9/f3QJE9z8SR5qsubaJ5euUzTFQCABOMardDKayMWFjgAAPkWvIrtpKl6hqTdqG3TlWazGZrklX5aMpJX+3Vtor+vLp80XQEASC6ql3Z13MxlIxYWOQAA+RW8NdtA5NWrV4m8UavLpz6fmp2EtS29WTKS1/5jm6YrAAAZQTNeXY1YKkgeAADkQfCWP/roo29089McuiTeoG1nTQ1AD2uT2EnwJHoT1e/RdAUAIDXoAaau2d373Z/1YBPJAwCALAueGq2c6sZ3+/btxN6cNYhdn3F1dTU0ydv/zb6RPKVsTrJpVp8+061bt1hAAQCkAD3IdKJ5Z12WkDwAAMiq5O3phqfBsUlrtOL3BHZjYyM0ybND0NV8BckDAMgmumY7oneal0YsLHgAAPIleGXd6FTrpkhZkm/Ktg12pVIJTfI0NkGSpzEKE6V3ttsdK8gsnAAA0sH79+/NddsRvV0kDwAAsiR4q05dQufly5epSbHZ2dkJRfDsEHSh/0fyAACyizoiuwalbyB5AACQBcFb7NLWze3BgwepuCFrMLs+78HBQSiS1/hdw0TxVt9NXvOH5AEApBfNN3Uk7yLrg9JZ/AAA5EPyammrJdNwdn3mVqsViuRNOwQdyQMASD+uQenNLNfnsfgBAMi+4JXtwHPNDUrLjdjOowtr2zjeMJKnDptIHgBAPlDDsTzU57EAAgDItuAtd0lNHZ5FMqrPXCgUQm+60vx9c6p/Z+WTxRIAQDrx1OetIXkAAJAmwevNw1N6SppuwK9fvzYitb6+HprkqeGKJG/SpitIHgBAdnj06FGm5+exEAIAyK7k7djUwg8fPqTq5quOmvrs5XI5FMFrnbeM4BXeTh8pRPIAALKBa37eAZIHAABpELw13biUjqK0lLTdeN+8eWNuvKVSKRTJO2gfGMkr/bSE5AEA5BSVBly9etWmbVaQPAAASLLgLTnpJ51qtZrKG68GtevzLy0thSJ5O80dI3lbv9yaPs1zYcF8trRFRwEAYJBXr15lcqwCCyIAgOxJ3kHaxiX4ce3aNXPjbTQaieisabfl5WXzudLUqRQAAIbjGqvQyspYBRZEAADZEryKHZfw/v37VN9079+/b266m5ubiemsieQBAGQPZWbY2axZGavAoggAIDuCV7DjEpR+kvabrq3LU8rm2dlZIjprInkAANlEZQKusQrrSB4AACRB8DQuoZnGcQmjsJ3PNjY2AhM8iZ0ET6I3y2Yl7/DwkIURAECGeP78eWbGKrA4AgDIhuRtp3VcwigULfvkk0/MTXd/fz8QyWv/sW0kb/lHyzP9+7W1NfN5FGlkUQQAkC1cYxVqSB4ESqFaLxWe1rcNj08afVTrO+b3u3/nxvePMlEYCgBzC14vTTOL4vHgwYNAO20ieQAAMMnDxTSnbbJASorYPTta64pb7fPq8Xn3v52JeHJ80f3vfuFZfYN9CJBryWtkLU3Tja3NExcXF3NLXuN3DSN5a1+tIXkAADCAK22zndZumyyQYuZmtVEoPD05nFjshtO6+bie+iJRAJha8DZ1I9K4ga+//jqzN9yVlRVzw93d3Y1d8lQfqM+ys7PDYggAIKMUi8VUd9uM7Y2/9+XR4s1qfVOphyvV+p4nJXHfSUmsfFFtLGdxYaaff+VJfTcAueunK4xZ3WcAMCB4Gnr+B92EXr58membrR1Wq5TNeaN5mo0nydOsvFm2crmM5AEAZBxPt81VJG8EqiHrikj582r9YBpx+bx63JTwSYyysDCThCnyNuLnVcpmrcuWSeN0090Pl3J43B7177+oHqXuZASAqSXPDD2/c+dOLm64QUXzar+uGckr/6yM5AEAwFAePXpko3nNtKVtRvZGahTy+ZPjs3miVI78VNIteEerw+ruHPktTfxaXx4VHRn0r9ejVg8gy4K3oRvP1atXv0370PNpo3kLCwtmfMGs2+6HXSN5lV9UZvr3lUrFfI5qtcoiCAAgw6hbtX3AqC7WSJ6LAGvO+urPFNVK26LMROIum6UMRirn+HmM7F2mufrtqzILYoDMCd6iM8Ons729nasb7u3bt83NdnV1dWbJe/GrF0by9N+Z/v2LF+Yz6AkviyAAgGzz9u1bK3kX6maN5EnwHtfXR3eLPG47dWllT0qiGSHgpGmOkr3UCIxSNIdEMmtBjUIw6Z0+ET1SNwEyJ3l7uuGoKDxvN1s1l7GtrdvtNpIHAAChY0f5dDnNveQZcfOJWgk1WlH0aVI5coTPXxa7f5b0nSyJu1k9PvX5/FvBRwvrG979Lrns7u8lFscAmRC8Nd1oJDpKWczjzfbu3bvmZqu0yXkkb+uXWzP9e9Xi6f1102fxAwCQfZS2ef36dSt6m7mVPCMafkL2+KSh9M2ZImFdSTFdOFMoemaAeYSf2URCfbpuskBOHmomZB6I5LTLLEwteAtdWnmPIr1+/bo3N09Rtagbr9RqtU6W5xICAMAgrpmtSttMfPAk8Bc0NXj+EbxAolZKAR3y+qUk7mDJ6cDnjUC4hoxnSOQ+yqPYXY4Pma5W1XaZJSqba8mr6AajInA9VczzzdZG02YRPSQPAABmQdd9595zkCvJc0YktAa6PAZcO6dUT2/65uXYgORFO7yypdTJqEZBeJuxSBJYKMce1S3P22XWfKee1reDquWE1AjekvP00DxN5GbbL3p7e3uRS57SRjkOAAD5Qd2sbV140mfnBb2ArUXVHEXNRLwRMtW9JT6KF+EICGfEAtG8ZJwLxSF1mbOPFLmURY5nfiSvlqeZeJOi7qJ2rEKz2ZxI0g7aB3MNQ280GuY9b926xTEAAMgZz58/783Oy4XkDRGKWshRkUqSJcbb7VKL8qijL97B8/o1C+ZoGd9l1kS/d4Z1mR0xHsOyw37OvOAVbbOVk5MTbrJD0mfW1tYmk7TfNYzkrX21huQBAMBUpKUJS2gyoYVrFELjrWtKUkqiz+K8EvVnGJDvJ8cXpPlFKHiqvRuRcjlpirGJCnfPnxGpnvsc10xL3qluJg8fPuQG64PGKly7ds3ccA8ODkKXvFarZd7rxo0b7H8AgBzy6tUrK3maWZvI9Vfq0wKTmpLodE3s+1xx1QxqHmHfZ0nhIPk04ju30Gm8M+u54JxXO8NEj/2eScEr6UYiicl7s5VJ0mcmiea1/9ieS/LOzs7Me+lJLvseACCfaFatI3q7mZU8p817bNG0JKYkmtS7hEQYfTptkt4X9vG/TLccEDFF9gKJEA5PAa2w/zMleAvOU0LTZISb6uj0GaWzqjbv4uJiIskrvC10Zt1swxf2PQBAPnn37p17pEIhcWuIYFLSPA0lntU38p6SOBBtiXGW38DcPGbmhX0+LnnTKiVkErOgz/uB9M3uua+mRByHzEjelh2ZwA118qeqkzRgkeQtvF6YWfKWl5fNeylVlH0PAJBPkjxSIfi0xO4iM6oRAUlOSRzoNBqx+PZLeKPAKIX4Issmghew4LmP7WBE77hNfV4mBK83MkFPC7mZjkedR7W/1Bhl3Lb0ZsmI3vlfzmeSPKWF6r3evn3LvgcAyCmekQrriVpHBJ2WqGYjpCT6NF2JUTq9Iq7oD4voiKLKEURxByK1pG1mRfL2Gbg92xNVzbEbtxV/XDSS1zpvzSR5m5ub5r00woF9DwCQX6rVam+kQpKasGQmLTFpKYneofBxD2r3zutjER1WFO+4GcdDj5VqfS/ucR0QqOD1RiboKSE30cl49OjRxIPRSz8tGclTp81Ztt3dXfNeDx48YN8DAOQY1YTbDs9dEvOQPTNpiUlLSfSmj8Yted6UPhbSIZyDj+vrAx1VvzwqRhRBXPKKPNG8VEuengaap4PcQKd/mvrixYvxkbifbxrJq/26NpPkHR4eMkYBAAAMnpEKS9mQvISkJSYtJdG7X+JshqGIjrdukoV0KNHbWpxdXr0py2qIxHFJpeAxMmFG1IFU+06plOO2F796YSRP/51lUwfPxcVF834SPvY/AEC+UZO0JI1UyFRaYpJSEjWzLCmz+3RMvI05WEyHH72N+oGHXzRPv8exSWcUT3PfuGlOx5s3b8wNdmNjY6ykKYInyVNEb9ZN70PEFQAAPNG8iyRE8zKVlpiklESfRjCxpc4NzGyLqTlOlvE2XNG5mIQIshojcXyI4uUFO7NokoHoh789NJKn2rxZt4ODA/N+n376KbWTAADQuX37dmKieZlJS0xaSqKkLimNYLzD6pVWyII68OO9lYR9nJTPAfNF8Rh8PhsnJyfm5qoZduO25u+bRvJW36125tlsNE83do4BAAAPG5MSzctMWmLSUhK9jWDiHNA+WDcZ38y+rOLtbnmzWt+M53twtErUNrWCt8Hg8/lQ9FP7cGFh/JDzsz+dGcnTvLx5trOzs87S0pJ5X6XqcBwAAPKNndkadzQv8LTEuBa3SUxJHKjRikGATZ2Wp+NjHMPqs453AHpYw8/T9rADJha8BacjF6IwJ0qd1H6cZFusLRrRk/DNs9mGL8w0BACApETzAk9LjLqjYJJTEr0CHMe+oeNiVJHb49M4RicM+U7SSTV9klchihcM169fNzdXRdjGbes/WTeSd9A+mEvyms2meU+9N8cAAACSEM0LPC0xMQ0nEpCS6G3GEfXin9lp8UVtY21A9OT4jJmIRPHySrFYNDfWVqs1Vs62frk11xiFvqigM06BYwgAAEmI5oWTlhhH6/iEpiR60/iibMAyEEnsLv7jqgvMOp9Xj5v9EdNGIRGRPCSPKF7OuHXrlrmxNhqNsWK2/5v9uTts2q1UKtFpEwAAEhPNC0YmPE0nGAI9OpqnDogRLPRLPu9LFC+s/d2V9zgfdAx/4EFNHlG8fN5UNd5g3NY6bwXSfEXb3t6evZl3Hjx4wLEAAMg5euD38ccff+tE84qRrzGCeBE1mYgrLTENKYkD0byQJUCpgt6ZgUTxQpfqWhLm03kfKlCDSRQvb6j5ifZprVaLtPnKxcVFZ39/vxfNY84hAADooZ/zADDyvhyhpatFFc1LQ0qir3R1fx3GTEHnvZpRSiUMNv7ReRmTbJaT0AgJJhK8xY8++ugbonjxSp7m5EnyNBw9iG11dbXDrEMAALDRvE8++cSKXqTRvLDTA0ONZpiZYClpLOIX7TSfPcAGMYrieJtukKYZkVx5R3hU662YJG8/6tRgIIqXZsmr/KJiJG+nuROI5Ol9GY4OAAA+0by9VEqeXzRPEhNWAwo1VvE2fEl6SqLPmAfLzryNYrSY9xFeIjkRofPOu//j6LDpjRjH2QAGRgoetXgJkbzar2uBNV+xw9H1/npyS8omAAB4avMi67QZbLRK4xQGROO4HXR9nhE8b6OLmIaNzyBjO36iJ0HVIPlpJdWJoLaGyOM+dXhRClZ/7WXUKZuD0XSariRY8jYkAjdu3OAGGDB3796duPGKmXH3+2ZgzVfsVigUzGdQC22OCQAAxNFpM4yFZnkwmnR8HlRNmBqt+NWcxVUDNfM+8om69VI4lXL3rL7hF92TtCn1Ux1Nh6Rm9qKDLKajRZLuPZY6XyOM4jXT+p3IoeQ1dbF//vw5N7+AsSMUTk9PJ5YyCZ5Er/G7RiCSt7GxYT7Do0ePOCYAAOCem6csnkgCMGFJTG2IvMxVHyS58RMbdRBMW8TqsobLM19wCJcpeFP83QQMgs9ryqb3/IxKtAaieBELJkwleOu60F+7do10vhDQftX+VdrkpNvmzzeN5Gk4ehCbooi2y+bJyQnHBQAATK22I3qV1EreUNFzGlJMG9UzbeH90zON4CVl8PksUiDx9dZRzYqieyzsY4/SVgab64Tb2dR0VI1JLmEmyTvQRb5arXLTCxhJs/btwsLCVFKmCJ4kb/lHy4GlbJbLZfNZrl+/3jk8POT4AADkHNXgO5IXSTlNuAve4Y1GTL2QFqLDxgiY+r7LBXNreNSqfpCFmjOJmfbFmPTLEVG+ei2quYQwfTRPvw5Lvk36bvX4lCheagSvaJtyqBCbm16wSKa0f4vF4tRSZlM2T785DUTyNDfPjlNQRO/NmzccIwCAnKOO2o7olVIteU5kozxppMp3vlvOas4U9VFErvD4pOGXomn2pfkzEyktsXBOZDRvcJxI95gFHXF2IsGDEfOn9W2OQ2Ilr6aLu9opc7MLntevX5ubZ6k0fadMO0pBqZtBbefn55319XV7Q+88fPiQFF0AgBzz8uVLe09opl7ybKRqRPrmdHQXy0StIOkoMuv3ECOosQqmw+yl7HsE7+SQ/Z9YwVv66KOP/qyLO3Va4aBGNtq/lUplaiFr/7FtJG/h9ULn7E9nnSC3ra2tnugpfZNB6QAA+UQP+mzteJfV1EteT/aqR6veNvPTyB2RK0hVRM9HwsyojMf19TkfmhQHUjSdFOi01qfmRPJ2dVFXG+Uobyh5Eko7cHZvb28mGdOsvCAHo7s3pZIuLy8jewAAPJC094JQZ1nHsti5HGSuNM6u8PlFI5yGKs6fVagvgjSi89xfxi4jbtNGpE3tplJ5h8xZJMKdaMFb+Oijj76Janaa3kPt+zWHz0qFRgvo97I8u83WOkioZtlUj2dn5l389aITxqYh7W7ZU/3g119/zcIHACBH0byrV69+69wHCpmSPIC84NTN7Y+IUrdUQzeqAZGZvzfkYYh9jaDSQCE0yatY0QojUid502sLNXWxAjEMicXbt28zddO0XcvUWVO1cLNuxR8Xjei9+NWLTpibZG9pacl8ZskpogcAkB9s5kmYw9FZgAFEgOk0ezkrMtAGRIqGk6KZCslr6WIuEQk6YqfOjV6JKxQKnc3NzV5ES50e9f+qVbNiIRnc3t7OXBRvlno8v2ieavNUpxfm1m63e1E9RA8AID+ow/bHH3+saN5Fl1DWcSzAACLCzLObtSbVTwRDnr8HgQnemq3BCvomYdMx1U1yf3+/02w2J2rtLxGyQpiFujAbxZPA6uebe8bdz8pG9FSjF/bmFT2a8gAA5APV6Ic5HJ1FGEDUUb2unKkmb3a5q2+wH1MlefthDD+XDOh1FxcXZ5ILNSexM9zSPrNP6af6WTSAPIhN3TUXa4tG9A7aB5GKnrquZS2VFgAABrFjf8Iap8AiDCAmpm5ARN1dGgVvqcufwxh+rgjcrDPh7GZnuIVRKxglNlXzxYvg6uj2/nbPSN7yj5ZDa8Li3lRHaIeni7t372a6SQ4AAPydyfIJa5wCCzEAgPAkrxLW2IR79+6ZG8Pu7u7sEauzMxMJ1Ovo9dJ4g1SXMttsRhGxILeomrC4U2klqmoe4x61oPMnS/WTAABwiRqnOdf7GpIHAJAeyTMNV5SSEfSNQdE3vXaj0ZhLLNSQxUpFGkXv5cuX5rMrChb01vx9M7ImLO6t1WqZ1FMr4O4xGDRnAQDIDsryca7xgTdgYSEGABCO4K2G1XBF2Dq009PTuaXCLXpq65ymG6RN1Zwnojlqq/yiYkRPUb0o0jYHRLPZNE11bFdUavYAALJFWA1YWIwBAIQjebUwGq5YbB5/UCmKbtELetRDWATdVdM3hbIrdoW3BSN6G8cbnbg21eytra31onoPHz4kqgcAkAHsvUzZP0geAECyBW8xrIYrYUmeNkXD0tRxM+woXi998rxlUjYlersfwn2vcZttuGOjes+fPzd1iSyUAADSia7hup471/Y1JA8AILmSF1rDlTAlT5u6dep179+/n/sonnvTKAVJnqj9uhar6ClF16brumWPyB4AQDpRdoZzTd9H8gAAkit5zbAaroQteeq4adM2k9rRUTLz2Wefmc+oeX9RbeqymRTR06ZavUKh0JM9RY41ekHNaIjuAQCkB5VMuBqwLCF5AADJE7ximA1XwpY8bbVarScOihAl7WZox0eoRi3qzS16+7/Zj130tGlxYGceInwAAOnEds0OqgELizIAgGAlby/MhitRSJ42W58nlBqoWrCTk5PYb4K2Jk3RxrB+9mlEL+4aPfem/aHj5k7ltCh1WPuOlE4AgGRiRwIF1YCFRRkAQHCCt9DlD7pIh924JGzJ06YZfN5ZbboJxS14Uadp+m07zZ2e6G3+fDMxojeJ8On3VP+hdGKifAAAyUDXYzU+c67Vq0geAEByJK9kh1aHfTOIQvK0qamJ0jc3NjZ6TT7iEAO34L148SIRIqV0Tdt1c+2rtc7Zn84SJ3vjhE/cvn3b1F+moaMqAECWseUIXXaQPACA5EjeflQNS27cuGFuBBqWHdVmO29GIbHuJ5uurmOJETy7NX/f7Cy9WTKip/8e/vYwkaJnN83bUw3f1tZWZ3V1dUD4dGwRPgCAeFCGhXM9biN5AADJELwFpytWJAtkNdWIWnoUEbLpm5JMRdfC/Bnfvn3bm4WXRMHridNfzjvrP1nvpW9u/XLLDFFPw6ZuqorU+jVu0RNlpecifAAA0T3YdM3Mmytlk8UZAEAwkrcRZZTLFmirhX6Um+r0lpeX+2a0PXjwwAjfu3fv5vqZFGF68+aNeT2bjmpn4enPkr6pCYtN3yy8LSQ+qucnfKp1tBFbr/Tp3NaxUVMhHScWZAAAwaM5tc61dxfJAwCIX/IOopwtp6d9WnhHnbJpN0V/htV4SdAkBEI3q0ePHg0gWbB/x/XUsg/JXaVSMSmGadmUvinBs1G9jeONxNbqjRM+1fFpTIWdm+hFDQKI9gEABIseojnX2TMkDwAgXsFbjDJV0yJR0nsq1S6u7fT01ETx1JjFPZh7FlQjJqlQvZgihmndlKqp7ps2qrdYWzS/TksK57BNx0TiJ/Eedqwl7G65V32J0m5ZuAEATI7r4ecakgcAEJ/klaNuSCIklDaaJzFKjORcXBghsEgCVU/nRumX9s+zurX/2O6r1VNjlr2/3cvMz9dqtcyxlZgPi+q6UR2n5vVJ/vSkWuev5vbp/90kYR4jAECcuFI295A8AID4JO8wylRNN65OXKaWSml2bMnaDtoHneKPiz3ZW/7Rsvm9LG5W8JXOK5nXOenXxXNe3CnBfkgm6RIKAGlFGRDzpmyyQAMAmE/wlrr8OepUTa/o2QGq6n6pqJ4iZVpwsyVnq/26ZgTPLXuK7Kk7Zx42Rf4ODg7M+ano3zDcjX2CQHMAFT1U7SANYwAgLbgakK0heQAA0UveZhypmn6pm1rM+tW5IX3Jlj3V7pV/Vu60zlvsnAk3jfNwpwR7GdYl1Fs7qBmMSjlF/gAgabhmxM6UsskiDQBgPslrxJWqOSzFQzeGYTVS+n2l0WmRzBbvtv+b/c7aV2s92ROr71ZNdC+NHTmTuNnh7zrny+XyyG6htm5QMyj1fda/Y6EJAGlN2WSRBgAwu+At2cVhEmt/NGZBqZzDpE+/t7m5aRbAqqFSBISavug3RfAUybPdOC2ln5ZM1C8v6ZxRy59tCqTvgORvWMRP0uce/2HTPoW+YyxGASCJKZss1AAAZpe8TVvzk4abhRakWqBq0Tqujkkt8m2NlBVBoRb67rQ4tgDFoytziuJ5o3tW+BT5Q/hCFu5WyzzwUNRv2tpARQGVAmq7h7JABYAAUzanHozOQg0AYHbJMwPQnz9/nrobh21dL+nTolTtmrVA1UJ11gYXigxKCjVHzT0mgW36Temaw4RPKZ27H3ap4YtQ+tzjPzQT0j4AGdc5VN8Jfa9s8xehVFAigQAwCa7B6G0kDwAgGsFb6HKui28Wa3eUfmoXopJYu0DVAHZ3q3pXKsnYxa6iIzYSyBaM8KmBy+bPNzuHvz1kR8W8KQVU3UP1kGOWsRH2O+VOD0UGAcB2z+6yjOQBAIQveWt2Xhc3oUs0xFoLUkUqtEDVrLJRQ7L1Z1oQa2FMLeCEIvGXc5O2qRq+xdrigPRp+PpOc6dz+s0pOysBmzu12R0NVOfPSYfI+4mgOzLolkE7ZJ7rEUB20L3UuQZUkDwAgPAlb0cXXaU5chMaj7qESf60v4YtbNfX101qHKMeJt8kc5VfVDqFt4UB4ZMEqpZPUUBSO5O/ucdCeFNDZ0mf1sJQjWWUmu2NznvRAxquUwDJRN9j53t9gOQBAIQveU1ddF+9esVNaI5ag2q1aqISn3zySW9xqhb3mu2H7E23Ka3TRvncc/gsS2+WzJ+pY2f7j212WMpF0F0rqIi4rROcNjo4rIGMnSOoSKGuc0QJAeLLknG+nxcqFUHyILV878ujxZvV+mbhaX17pVrfKzw+afSo1vf1+93/Vr6oNpbZXxCT4JnRCRITamWCQdEGPa3UwtLd4bPZbLKyn1UIuiKnKN7G8YZvaqeif6rno2tn9jalP2sgvDsKqG6hVgS9TFNDuLKyYuSPOYIA0aHv3bSjFFiwQSK48f2jha64lT+v1g+6/+1MyufV46aET2LIfoQIJa9s62O4+YST2mmjEYuLi4heQFvz903TlVN1e96ZfKL442Jn65dbNHFhG4gWDpslqO+pHs4Q4QMIF9cohR0kD1JDV9JKnz85PptG7nxk71yyx/6EiCSvpoutUg25+YSDIqRK49R+XlpaInUzhE31fC9+9cK3a6e7iYvkkI1Nm76HapQk6dMDGL8In7sOEACCwTVKoYnkQeK5WW0UCk9PDueROx9ahWdHa+xfCFnyzOiEd+/ecfMJWfRsiopSz9hCXLz/9cJE8NTERRE9vyYuSvtUPZ9q/9jYtO3v75vmMKqj9Wv8ojmcXMsAgrkfXr169dtpRimwYIN4BO9xfd2Jvg2RteP2ypP6rlI4JW09qvWSavKcNM1RsldmP0NIgrfK6ITo0CJR+1sLSbbotnFNXGxqJ6Ma2OymCJ9mYSry7pY9ReRJ5wSYH9cohYnWuCzaII70zHLhyfGFn5yp0coXXx4VJ3kdNV5xhM9fFrt/xv6GECRvWxfZe/fucdOJADV3sLU/bPFtGsGger7Vd6u+XTsVASStk81u6gKqtE2b0qlhzkT1AOZDY4gcydtH8iYTDhMZMri7OF52ctxxOjmW1BiEBW4A+/tZfcNXyLr7W+mbs7xmVwqXTBdORA+ikbwGoxOiQ7U9tjMgWzI290B2CZ63Y6fq+BjRwKat1Wr1de7UwzHq9QBmwzVK4RzJGyoaJu2vNjpd0MNl5GlfksJCd8YUTdXg+UfwtoJKAR3y+iX2PwQkeIt2dAILleiws/PYkrk1ftcwoxi8wqfGLarhU70fW743RfVs3d61a9dM0ypGMABMj+ZYOqI3Nustf5IRTKOPloSCRe/kOCMSWj7iXA7yfZTq6ZV3/ZqZehCQ5K3bLnLcbKJDqV7a72zpET73XD79v35PKZ9s+d0U1fOOYdCClawIgMl58OCB/f5UkLx/djlc22ni0QmUrjAiDxOnxdaiao7yRfVo1RvRu1k9PuU4QACSZ+rxdJHlZhMdanKj/a46H7Z0bIreKYrnreFTdO+gfcAOyvGm+XvejpyK9HGtAxiPvivO9+Yg95JnmnN4I0iD89UkIFt9XRwvUzorl3J43B717yUVLIBHR9d89l0tZKmskLYJIUge9XgxYMcoKBLAlr5NETxvdE8dO9XIRfV9bPndtra2ED2AKZimLi/jgne0Oqzu7vNq/WCaRb8jKrWh9XrU6g3F2dd96a5RNLLxpuZq7ALHA+YQvIUuF7q4Uo8XLbdu3TI3NUUA2NK7Sej2/navbySDxE+jGJi9l9/txYsXPdFTrR7XPIDJslu6FHIpeSYS59OEw8xXm2NYtpG9y86bzGabPYpXyvp7QyYlr2hrSLjJRIudDaRGDWzZ2DR4fe2rtZ7sLbxeMGMYkD1ET+NSFK3g2gfgj7rUTjIvL7Mpmp8/OT7zSxEMKoJk0jt9InqkbnqjaWYERWzRNG8UUb/muMCMkldhPl68N7RarcZqOGObhqmXflrqi+y9+NULOnLmcNNDHDtIXc2W3r17x/UPwAfXvLxariRPEqcmG2G16e+PFtY3vNFCyaXmtrEovmTgWESc1joQzeseL2YewoySd0DdSDzYbmK7u7ushDMse+7IXvHHxUR341TqsNjb2zNRqEqlYjpHWgqFQl8XST/cf9+iGjW9ntBDDfs+eUlVPj8/N01ZtH+UkkZqPMAgegDiXEfauZI8M8A8woHYZpi6T9dNFsWXXU29gqXfi/6c8DTOmSNdF3Iteee6qJJGFD2PHj0yNzQtfNmyvSmN087bUwqnmrMkSey8IwCiRpGuzc3NzunpaabPA7uf6WQM4I8dLaT5vbmQPEXQBurwIhCuIeMZSrlP1azWy3375PFJI47P4XN8dpAWmFLwlu2TZW4uSB5buJsatGjUgnvsQty1eooiW9HS4krNgMTDhw/N+fn8+fPOmzdvekwy6FtRKve/Ea9fvzavZ1E9qn0vDRH3RgKzWqeqTrp2xAIP1gAGsbXqXUq5kDzvYl6pk1FFjrzNWOjk6BNVDTGiOlW0lUgrTC95ZV1MdVHl5hI9WkAHLXkXFxd9qXCWZrOJZSVk05w9RfPsyIX2H9uxfI5yudwTK0WW4kwhVJqWPoPrKX4vupe1lE6730mRBxh+X+yym3nJ843iVeuVCN+fTo6DclWLsx7PcrPaKCDgMKfk1XQx1UWVm0v02OGvWvTNumkBrIXwJLVS6+vrnbMzujwmYVNdnurzrOhFPVfPisYnn3zSefnyZWK+ExJNRfpcrdT7hE8RPtW3pXlTTSLNrgD8UeTf+d43My953m6XiuJF3WCDTo6jo5tx1cJ5awN1biAuMKXktXUxpdtbOiVPzTG8IudOuXNjIySLi4t080zIJrGzoqf/RiV6kiUreEqjTOr3w0b3vMJnpU8PLRQFT1ukr91ud0iTB/Dnw4cP5trkzO9dyLbkDc6uq0T9GejkOCDeLff+0GiL2D6LJ8qLuMAUgrdopYAbSzolT3O39O/v37/fefv27cj3ev/+fef27du9RbK6JrIlYMH/x3ZviHoUomejSEkXPC+K4CnCpwcWzgLQN9KXFuFbXl7u8IANwB99z53v9lpmJW+gi2OMQkEnx+H7Ik7J+7x6fI7kwYySt66LqBb+3FTiQYvseSTPzt7Sk89J31OpeXaRPE+aKFs4oqdxC6G9T7ttIrk69tVqNdXfHUmfzmU94PA2bkmD8Okhiz6rGtxwLQToR98L5/u8lVnJ83ZxjLPmik6Ow6OrcQ2KVzTVG2FFXmAKyduilXe82NqDWWXLRmSmfV9F/Wz6pqKJbMkQPTtiYf83+6G8x+rqqjnmekqexe+SX2qnFb6k1aKqERIpmwDDH0Y63+H9LEteIro4Op+FTo7f7Yv9JDSiUQSx/3Mct5EXmELy9unwlgzJU8v4aTe1Yp9nkaj3thG9rM8mS8umrpuSPMle0GmbinzZ9Gyl7mb5e+VXy6cI5v7+fqKOtx2lwLUQYPA7PKr5SlZkIhFdHAWdHIdHNW9W65uxnB/PjtaSMK8PUit5TWpC0it5ajgxb4c+O6dPnTk1eoEt/k3pmhK9rV9uBfq6tptm3tIDdX1z16JubGx0Dg4OYj/O+r5REw3gj7v5SnYlLyFdHAWdHPvku5KEbqOK7HoiijXkBaaQvItp67kgOZJnRybM0zxDx35lZcW8ztbWVuwLX7ZO5/C3h72xCkFutn5zXIOerKKMBfcMPkX2JL5xCJ9GQFjpZkYpgD/23tSlmNVIXmK6OJrPQyfHYVHN82Q8BIgv0gupE7yCLp43btzgZhIjr169mqkmz7Zg16J1XknXol+vpdQxZujFv1389aJXm9f4XSOQ17T1X2pQkufv28nJiW/dXhTCp/Tq3d1dM/bBvq8iFWRSAPhz9+5d+13ZyKjkJaeLo6CT4/BjE3WU9Ysvj5a8nVcVbUVgYELJ29DFUxdRbibxRhdmGWegxWiQUQC9DtG85GybP980krfTDKYpjuSC4dv9SK6UrqwHXV7hU0qnZlBKzObZFLFTWrUdl+BG3zkED2A46gDsfF92cpGuGVcXR0Enx35WqvW9OFM2B+sCj0+RF5hC8nay0EY97diauGk7XNph1s+fPw/kc9i0Uc3dY4t/O2gfGMkr/bQUyOuVSqUOTZaGY2fweYXPdudUOrXET8JmURMXjWiwKFrqlTs7rsJG3fVQTcfg66+/Zr8D/N1kmS5dDrKarpmILo4mckQnx/6Uzcf19YEZhl8eFSOL4nlSZ1UniLzAFJJ3oIunLqLcTOJDM750HDSgepot6EHKriJ3kwrKFu/WOm8ZySu8LQTyelY2lK7I92688G1vbxsh85O+aVFdEddZgOlRF2Dne9TOpOT5zKaLbSFPJ0ff9NVmHNE873mhJjiKtCIvMIXktXTx1IKGm0l82DTJaYY26++GUV9lOxAqTY0t/m2xtmhETzV6825WOPjOTY+ibop0q8GRon0WSaDmDbpxSyFyBzA/rmZJi1mM5FWSMpuOTo6+x6fkjeZpgH24EdWjVaJ4MKfgLdK6OxnY7mHT1P7Y1LugU21tfeAsnT7Zgt+KPy4ayWv+vonkAUAuUQmBc/1azZzkebs4anEfV8SGTo6TRfN0jHTcwnivyzEW/Q1fiOLBDJK3auuvuIkk4ymlangm2TS03HblC3qgtV7Pfp5p00fZgt9UjyfJU30ekgcAecSWNHTZzJzkXUaLPF0cY6jLo5PjGBEfiKwdt4OuzzOC9/Tk0CdyWOI4wJSSt6mLpi6e3ETiQ3VwdnTBxNEd56mm2sCH8ZlsNE/NJhinEO+mYeiSvN0Pu0geAOQS1cc616/dTEreQP1VDIO36eQ4Nm2z7JUvM24ioLEKkuyBiGEXHRf2P8wgebtBdmaE2VA9pI6DhppPsrlr8cIcYG9r89TBky2+be9v94zkaZwCkgcAecTOce1ymknJU0Qori6OvSgeNWCTiF5tIMp2ud+25ooUPq6vKyXT+9oSbdI0YUbJO9RFU80EuInEhx1bMGkNnGbpRTH2wsqnOjJeXFwk3YUi2bQf3O3yo+hAevjbQyN56z9Zn/u1FJnVMQ06xRcAIEzU+MiRvLNMSp5Q9C6uBix0cpxT9C5pTRvVM3Lvn55pBI90WZhD8lq0U0+f5Cnip7+vJ5thfzbbJVDClweB089p559pHpqOid3fw1DqrDqRhiV87T+2AxujYEdu8J0HgLTh6rC5kEnJ84vmzRshmlBa/LpHEsUbtc8Gu5D21epJmocNtXca7VSMFA55DQk/kg1zSt4FqVvpkjyJiG24EmaqpsUOaVcnz6yKnZrL2E6l45DQuVvl+/357u5u4MK38HrBiN75X86RPADIJbYLdZdCJiXPN5pnOlwGU/PlK5bVxrKpKyOKN4scl737bri0" - + "DdbajWCH/QtzCt6SLpbXr1/n5hEztslJuVweu0i3XTV1s4visymtzw5HbzabmZE7NZNRraEdDu6WtIcPHxq5lXwLpQmNSiHS8bNzDsMSvtV3q0bylLo5z7a+vm4+m2a98d0DgDThus6uZ1byfKWr++thUaEA3qsZpVRm7nhddiStTSFww3l80oiyDhMyLXlmfIKiEdw80iN5koaoO6Kqg6eVlix02lTkzi13+rnUuW3eOrVxwjfPOIrKLypG8l786sVcP7ut56TZEgCkDXsvco9RyOQCTU04fJt7BDizTjLh1+iDNM1Zhflo1TcKO6HcMSIBApa8si6W9+7d67uIKnKhSIYupmrsoV/TpCE5kqe/o78rKYnq8+n4q5On3leSkObonY1kCXUPDSttcZjwra6uzhTZq/26ZiRPEb15Bdfvew8AkHT0cMq5lu5kWvJMKuDwmq+deZtxqM7Pp5NmLGMbssblIHOlcXaFzztY3tVQxfmziiKB7DcIQfK2dbFUWpounkrfUurmsFokpewp6if50+I1inqwvCCZ1j7e2toau0i3TUDevXsX6Wd89epVb25e2qN3Kt7XORzVvpPwvXz5sifKkzbYcW+qxbN1ea3z1sz7QSm3Uab7AgAEhdYpzprkIPOS58jYjm9915Pjs5vV+ua0dXNOg5VhzT72qcMDyIzk1XSx1OJTHQVt3ZUaM0g2lBao/2pBatuuu9GClbqeYLDNTdTRcdwWZ+MM+xAgTZ02Fb3TOWzPW0Ww4opM65jZ7nAHBwdT/yyln5bmTtlUo5mFhQXzfSdCDwBpwo716dLMheQ5Ylb2i7q55rPtK43TL7onaVPq50q1vjckNZNGHwDZlLyGLpb/6l/9q16b/FGpeHY+mOTPLpr177jx5EfylMZr5+a1Wq1O0jd39C4pDyVsupHSRqfd9n+z3xulcPHX2ecWajQEdXkAkDaUQeRI3nluJM+I3rOjNbXln7CL4/lUfzfAOj8ASIzktXWx/Kf/9J/2GkNMM/DaRveiThvMIraYXAKdZMnTDVZ1bFb0ktxt0z0SQdG7UR0yo96HNmo+iygXf1w0orf7YXfmfaOHNVZ8ieYBQJqwae9dFnMjeTYqp1q6SVv2j0PRPerBADIreWaxaRftqlGaZrNd+mxNH8yOJET7cpLui0mYc2Y/r0Q/rAHg82y2kU1SU4rVGXXSGkzvdtA+MJK39GZprmiebUCj739SBBgAYBx6IO1IXjFXkmeRmGnQ9pj0yxFRvnqNNv0AmRa8ZVt/Z6Md07bGt7nxEkX9Pzef/EiesF0j1S0ySZuiY6o502dTZ9gkHu+3b9/2ouezbGtfrRnRK/+sPPN+kpzb/aS0a+prASAN3L17165bSrmUPG8apyJyl50aB1M0jdRddnGs0aIfIDeSt24XmfMs1G1KnBaJdNuc/6a1v7+fGslT9Memzezt7SVG8nQuRz1HcFpsXYkkayZB+2O7s1hbnDttU+m27gc96vLK9xEAkoytDe9Syb3kAQD4SN6mLpL/4B/8g7lmn52fn/cWiczdmh2NptA+VK3UuM3WQiahlsq2s5asJGFIujpW2jTNpD90sM2OZm1gc/jbQyN5Gqtw+s3pzPtM32E1/LFReWpsASDJ2HT8LrtIHgDAoORt21lZk6YJjooG2LSvKGeP5VXybNQlKZ/dpm0mYUi67fqahq6R00Rvh20apSDRW/7RsonuzbPZGltF94nKA0BSURq+cx/cR/IAAAYlb9emWU4qF6M2LVTtkOm40wiRvGhR5Md225ymO2vQmyKJdt9sb28n/pgrNXLSsRmjNjs7T6Kngemzbjp2hUKhJ3rU2QJAErE1zRoDheQBAAxKnhmE/vf//t8PRPK02dlbWiByI5oOWxt5ejo+7S5pkifsw4I4h6TblMO01IfalKN5JU8dNlffrRrR03iFeTpuKipv5woqdZMaPQBIGnqQ7B6IzqIOAKBf8g5t7ZL+G0QbfEVSbL3Yq1evuBlNwfXr1yc+DkmUPDvMPa6UTcmx3S96ypuGYx6U5GlTBE+RPIne+k/W5xI9fY/teAVqbQEgaajpl3N9aiN5AACDkneqi+Tf+3t/LzDJc0dT1P2Km1F+JM/WSMw6EmDezUpJms67ICVPm7vj5ryip01NbGytLaIHAEnC3geRPACAQclr22HWQUqe7W6oAcvciPIjeUqPVHqfPpe6NUa92RTDNA31DlryTLrl75uBip7SbxE9AEgaqv937oULLOoAAPol71wXyGnkYtJUL9uAhRtRfiRPTNM8JshNdWS2U2yajnkYkhe26KUlFRYA8nHP7LLMog4AoF/yTOQlaMnTZqODdNmc/qnkuFlzOk5WzpP2Mzx48MB8tt3d3UglT++n99X7p+mYqwNoGJIXhuhtbm6mZjQFAGQf26ysS5FFHQDAd4K3ZEXBRl8m6eo46Wbro9LQxj4p2OjcuC3JkmcjUxKCKDd7vqWt2Y9tVqP9FsbWOm/1mrGo6+Y84xVsGraipczQA4C4sWuXLmss7AAAvpO8ZdskQ7VzQafY7e3tmdfURZibUX4kz87Li7L5iur/bCphmurxxP37983nrtVqoe0fNWOxojfvwHT75FwjKpihBwBxohph5765wcIOAOA7yVuzEmYvlHpSH9SmlEO78CZlMz+SZ5uv6NhHtUmQ0vpA4e7du5HMFlQET5E8id7SmyWTyjlTZLDV6ome0osVgeS7CwBxPiTrssnCDgDgO8kr2W55to4q6GiCTaGjhic/kieUzqfPp2YoUWz2PEvj0O4wUqVHiZ4dmL7weqFz0J7toc7FxUWvPs920X3//j3fYQCIFJvu3mWbhR0AwHeSV9bFUU/CtDgOY4h1miMsUWMHu2oMwLjNdpJUylySo1NBRoZHCUeaI8Y6hkE3PRq5v/560Sn/rGxET+x+2J35tfb393tjK+z3XD+P/qtZhYgfAISJHiA7159dFnYAAN9J3pYujnoSFtYQaztKQel7aauVihoJivbV8vLy2P2q2skky7MW+FF12LS1nzp303jcbUfVqLed5k5P9DZ/PnuTHNVDuqN6XvQQCdkDgDCwjb661FjYAQB8J3nbtvtlmEOsV1dXzeu+fv2am1JOJM+OBYiiw6ZN1Xz58mXqjrm+d/rsGjcSx7b/m32TtmlHLMzTeVORSJ2XijKrvrBcLvdET9cWUrYBIGi0rnCuM4cs7AAAPJJnGyfY2qCgU+yUAprWeqkomSaamnTJ07BsfT4JftibTRdMY6TYin2hUOjEtakBixqx2BEL83Te9BO/jY2Nnuzp3FaUVwszRjAAQFD3zS4NFnYAAN9J3p5b8mxue1h1earT4qY0HFtAPsn+Vy1Ukvepu75QNXNhbWpWYue2pfGYWxleW1vrxLlJ7NydN0+/CbYJjL0GuFF0Tw2fSOUEACQPACBYyau5JU8pVpOmC04VKUh4k5CkME0k1S6a1Rk1qT+PbSgSZl2erceQLKTxmNvvnBrHhCnDk2xK1Sz9tNTrvLn3t3vBvv75uYlAv3jxopfC7ZY9xqwAAJIHABCC5Anb+j7oUQq2+yFP7YdjF72T1ESmQfJevXrVqzcLS2BsKnCaZ7XZmXNRdCKdaJ/+otLXkEXdOMPY9PCnVCr1Rfd0/VFGAdcJAEDyAADmlDxdJO0F00ZGlGanzphBbUpHY17ecN69ezdVbVYaJM/90EAdMMPYbL1Xmpv62DRdNZBJyuZuyBJ0nZ6f7Ok42gdBNrqn2j068gLAKGxdc5c2CzsAgO8k79AreUKDjYNedFopSWub+7Cxcq3F7iSbUt7s+Isk/1w2mhf0aA7vwwPVtqX12Ctq9dlnn4VSDzuXfP2+2Vn+0bIRvcXaYqfxu0ao76dor2pN7TEVGi9BV14AQPIAAKaTvIaf5GnRaWd3BZVCphTENA+sDhtF5KapX0uL5Ilr166Zz6qITdCbIp9ZOKc0/sGKjUYPJGVTnd7aV2u99M0Xv3oRyfuqds+msdp6Xp3rRPYAAMkDAJhR8oTttBlk1z87z4xRCoPYJiWTilCaJM8KrD5z0Jvq/fTaWTgH9D20D1f0XYm7EYt7c9fpzTtPb5oHQxJedxqnHhgQ2QMAJA8AYEbJUzQv6OHopGz6Y8cNaDE78aI7RbMHp5n/N+1mU/qyci6oNvP69es90QvquxfE5q7T05iFsNM33ZsyCtwdOfXggOYsAKDrgHNdOGNhBwDwneQ1R6W62Zb+QXXadKdsknb1HbZubZqoqSIcaeoqacVFc+2C2jRoW6+p187ak2m7vyTG+v7pZ03C1jpvdVbfrfaielu/3Aqt+6bfpnRmNYWycq+HHFxLAPJNr0MvCzsAgJ7ktUdJnk3ZnLQZyCSbfRpPytV3aEbYtOmMaZM820EyyHqzVquV2ciwxMV2JrVofqX2XxKkT3JnRa/wttA5/O1hZO+trr/u0QuSvfv37/tmJAAAkgcAgOT5RBTsOIWgNptmmIZasqiwi3k1m8iq5Nmh30GeS9pfek11g83ieSHR04OWO3fu9Gr1vNK3ublpUhnjSOs8/ebUCJ6VvY3jjVBHLXg3vzl7qtlD+ACQPAAAJG9MZ8Kg0+zsYp+6vEtsV0WlsU7TaMM2sUlTRNSeS9PI7KhN7fbTMCswKFSvJ+mT1Np6WYvOHz1A0fdL+zdK6dtp7vRq9fRfNWk5+9NZZO+viK5+dtuExy18NHkCQPIAAPIoeWfjJE9PxYPsjCiRsTU1qkXL843JPR9t2mHhdpZYmiIWs6Sljtq0z/R6Gpqdx/NHswElMbZ21g+lR+uBgPa56tkkgEFJdp9onbc6pZ+WelE9zdXTuIUo6/VsdFfRTbfw6YGS5JfFMACSBwBAJM9hlqYgky7O9aT9w4cPub0x3b17d+Z9a2sb0zQEXFFHfWal2AWxpWmMRBTCp/2gqKakz84mnATNGtR3UrVu825K4XTP1VMXzt0Pu504NomdW/YUSdY+oisnAJIHAJB7yXO39w8yBcwOOlbqWR5Fz46o0H6dpYmG6rHSNgTcnaobxGbrO9NSlxgHSvFUtFcRPwmOBFDY1FkvOjbar/OmZ6sRS/HHxZ7sLf9o2YxgiHrTNUuRPffPqO+dospp+u4AAJIHABCo5AmbDhZ0Z0QrKhK9vLVBn7dzqR1FkSZB1meddh7gqC1tzWeSeky2t7dNcxdvnZ+N8inNc9ZunhI7CZ6VPYlflJ04+z7L/n6vltU9bw/ZA0DyAAByKXmKwNgFoP4/qE0LRyt66jCZJ9GT2M46g1B1jWkdAm4jSEGkBqax+UzS0b5UHe6NGzd8hW9ra8t0tZx2U8qmUjet7CmlU6mdcWy67tgHBMgeAJIHAJBFyTPD0JXSNe4iqnQv/V3VuEzTBXLcpsW+Td2UAORhoaXoiZXmWWQnzUPAbVQ4iG6taWw+k7bzVN1fVTvqjfJJ+BRBneb8VRMWdeJUUxYre2rWEmUnTmQPILOSd87CDgDgO8lrTLNItjKmGpcgN9XN2AW7IghZj+jZBiSzNrORIOnfS5jS9rPbZjNBRISRvGjRflYnU3eUT51yNadvqu/7X85N50332AXJX9SdOIfJXhofngDkFdW3O9/dNgs7AIAZJU8RP/tEP+g27IoO2o6RksksN2OxYykUCZll06Ja/17ClLaf3Y5RmCVNFclLDurmaYVdqG5v6ij+n87MAHUb1dNg9bhSOK3s2fTxSbIbACB+FHlH8gAA5pQ8oQ59+jdaDM3ajGHoou/srLfIkghl8YYkeVUt3Tx1aRKktO4je/7MKrhIXrJQ0xYretNG9OzW+F3DCJ6VvfLPyibaF8dmI3pqjMTxBUDyAAByI3mSFDVJsRG3IMcq2FRE2zkyi4t31TjpZ1PTkFm3NM+Hk9wF1akVyUsG7nrdWR9cKFVz65dbffP14ujCaR+gqNsoxxYAyYMM8r0vjxYL1Xq58LS+vVKt7xUenzR6VOv7+v3ufytfVBvL7C9IseTt6+Io8ZjmoqqaOdslMcixCl6JUe1PltI29bPYeia1c591S/N8OKX52TEK8zbwQfKSg+0WO+tIkN5Dnm9O+6J6mz/fjLRWzzY1Ulp6Hud3AqRY8k5Z2MFIsbtZrW8Wnp4cdgWuMymfV4+bRvi+PFpiP0LKJK82qyyENVbBPNXvLv5tkxc1esjKzUg/i+1MOI/g2NrFtNYNBSG62kqlUmeWhxQQPGp+YK8Hup7Mk8rtjepFXatnrz2M5gBIleQ1WNiBL4raff7k+GwauRvgyfGFInw3vn+0wD6FrEuesGlas3aJHPlE3+kgmZUmCDaCFcT4AEXB0hxpsHV583ZpZRh6snDX59m6XYl4q9UKJKon8YsiqqdZgFmuCwbIEsrkQPLAly++PCrerB6fziV33sjepSyW2L+QdclT2mZQqXejFltKDU3zWAVJqm22op9pnk2DqO3w+DTvD1vTOc8mSdTrSC5Y7CQDRVVVz2bPd1urN2s31TiievY7pgcpdNkEQPIghdx8XF//vHp8PkLYWl12TG3es6O1Hl2BMzV5l/V5o4Rvh/0MWZY8YZuwBD1SwSzwXGMVVPOTxsiVW/DUbGVeGd7b20t9lMEOg9fDgXm2NDegyQNK49YsRyt7knqdv7M0Z4k6qmcfICi1WNLKgHQAJA/SIniqvRuRcjlpQxXV4akeb0Sq5z7pm5BgyduZd5Fs555pwR3GpgWhIgFW9NIS0dMCV/s1SMHLUvTKPhxQ1ATJyzavXr3qNWqy6PswbRpnlFE9fVftOBd77eFYAiQP1c4639N9Fnag+rstXyF7enI4a7dMpxvnzjDRY79DQiVva97mJlrAhVWXZzf3kGLJgZo8JDVqJ+GwjUXcC9qg0lltU4i0p5Hdu3dv7uYrGsBN7VR6ord6MGG7cNo071nmJWq0gkYsSPQWXndfo7kTynXHXRcsdK3jWAIkCzuWp8seC7u8C95luuWAiCmyF3IKaIX9DwmUvLIujlpwz7N4s6l3YdTluSN6VnAUHUtK5zt9DkmGN1KxuLhoGoPMOiB6WHQhK+3dNWx63hpFO9NsnvMXokfReCv5ttusorLTdOTUsHQNTbdRvdV3q53WeSvw645rAZm5kS4AWcDeS7pss7DLMUqt9KZVSsgkZgG/T3EgffPJ8cUX1aNVjgMkTPLWgxj8656RJakJS/b0unoPu+iKM01P3TLd9Ua2wUTQYucXWUhz0xVvBHieuWrazwyuTi/6Dnmj3urGOc31wxvVq/26Fvj3ThFjmzKuBSXHDiA52G7NXSos7HLM59X6wUAEL2DB60X0qo3CYETvuE19HiRM8tZ0cZSszBvN8kaxgp6d5110KXJoP3vUdXoaHWFnguln1XDyecci5C090Y6UUGOdWTc1+wni/IX4UGRMHTnv3r3b16Dl/Px85qje+k/WO2d/Ogv0u6frmc0iSGq6OEAe0f3QuXaUWdjlN4pXHKzBq2+HmhqqLpykbUKyJW/ZjiiY90KrGjHV9tmGGpKfWedjTRrVsnV6igaE2f1OC1F18FKTGXdappqgTLMYnXdTbV9W5sJpoWxnqc0reZICFjvpRyJlI3uS/2kzAtxRvcXaovl1kJuijPpsug5wvACSgesB0ToLu9xG8Y6bfbL1+KQRxfuuVOt73hl6RPMgQZK3qIvjtWvXAr3o2vRNLYrC3Nx1epKvIEVP0qrULHejCHdaZpiRymE/q41epnlmoBu7P2fdVMMV1EMKSAY6t63o6QHAtPP1FNUr/bTUN2ohqM09P49oHkAycJVNrLGwyyFKyfRG1BTZiyiCuGTGMhDNg+SKnrlABh2lsaMDVKMWZrRLr+0WvVmjXDZa59cd00aLwqy3G7fZwfBZqj+zUdFpGm4gedlHD2vcEfNZZG/3w25fU5ag0jdtNE/RA44VQPzY7CGTmcSiLn90parW32ylfhDl+688qe/2d/I8PuW4QIIkrx1GdEh1NrZuTZGvMIalu6Nc6tBnF4VW9vQZJG1u9NTP4idz7rpCNQXR4jLKlMxhEQQbxUv76IQgJU/HxdZJsdjJFnrooki6sgy8jVkmfdCiGXru9M3m75uBRfPo6gqQrPuIyUxiUZdHyTtu90XSnh2tRfn+ftE8/R7HBhIieS1dIMOoadNr2nRHSUrYzUkkZO4BxtMgSdSsvzijdX6b6pJspHKeeYZJTrOZ5wFAGJFoSJ7suZ7WG9TsaKIHQH86M5E8233zoD3/d1up2vahC6IHEC/2YbJZz7CoyxfehivqeBmLaD4+aXhSNsscH0iI5DV0gVSqYlgXYdv9SiIV5iw9u2nAtpqUKBKn+VtutECTVAhFAJO86fOpAUVWZ3QFIXl2sc38suyjbAPXTKyJ62Iv/nrR2Tje6KVvKpUzSNFjSDpAfA+BnOvBGZKXz1TNLY9c1fL8OQB8JG9fF8kwh4vrQmxTI9WRkm38pnEJShm16adZStMMUvJs5DbM7qqQLOxcLEW4p9nUhMWK3otfvZj7O2oHpVOfBxAPuu47ktdG8nKIt7vlzWp9M5aIYvVoNY7ungATSN5eFG357Vw0obRIPQWXyLANbnY0gE0Hy0o3TS/62fQzTttUA8nj6b19aKTr1jSbhqUHJXq28Y/SxYgkA0SPHn4698oGkpdDvAPQwxp+Pl7yGsvewegcH0iI5G3rIqk0qLAvyNvb2738eVunN2vTjSxvSivNytDzsCVPDwzCTjeG5KHjba8h087jDFL0bLfNKK6fAOB/HehyiOTlEHWyjGN0wpCUze8k78nxBccHEiJ5lSibeqiWxTXXxizS2fzFJeu1PkgezIOt9Z1lcLpb9HaaOzOff2rSZDu8Ek0GiBZ10HbWEjUkL4d4O2sqohZbVPHJ8Zn7s3B8ICGSV4qjrkRpFrY9uur01Jo875tGAqi7pxXgrKZpWmxtlSKX80ZSaH6RP9xpm5N22xwmeoe/PZz5HLTfWdUIclwAoqNardr75TaSl8t0zeNmf01eo5CISF5OJe97Xx4tqrNo4Wl929RLquuopVrf1+9rWHycMp5DySvGtUBxPYXrDT2etGNe1jZFItQR1D3rL+s36CAkzy6ww64phWSi64VNAZ8lImyHpmuOXvuP7ZnOQXXB1SxQfQad0xwXgGiw2SBdykheHiN5T08O45yRZzGz8nJakyexU8ObgWMxBkfQK8wUDF3yFnSRVFQtjou00ux0oVa6kx1CrkV/3APIo95sREpyp/qePKQfInkQBIri2vo8RfT29vamOofseAXN09O4hVk2d7MkNZniuACEj6v0Yw3Jy2W6Zr2WhPl03nl9qhXMyf4ve9NUp0aD5J/Wt298/2iBczo00TuLOz3QPTjdyp7SOOdpr5+WTY0j8ljXE4TkbW1tmddQ2g6LnvxizyXLNA2dJHaFtwUjepVfVGY+F3W9yupMS4Akooeiznd+CcnLZSTPpP/1hGHlSX03Ltnpj1LVD7K83yW13qY38+LIYonzOhTJO9WFMgmz2PRUfmVlpW/BplQoNTjI6ma7aSqimceF+TySpxS9PO478L922EXftKMVmr9vGslbeL3QaZ23ZjoXlXJtR3pE1cgKIM84a4ReI0MWdHmTvGdHax5ZaMUkefuez7GV1X2uMRWfV4/PRwhbq8uOEV8dH0tX4IyUX9bnjRK+Hc7twCVvP2nNK5SuqO55tjmL7cSZtQYtSku19TxhDqTPquSdnp6a11DaDosesAPKVWM8bcfN0k9LRvT031k30jYBosE1CL2F5OUUpfiZdL+YO2x6pSfOBjChCp5q70akXE66750axsqIVM990jcDlbydJM96UoMWt+xN+5Q+qZuaRmgxamvx8pbiFYTkqelFnDWlkCyUcm6vFWpkNI3oKYKnSJ5ET5G9WTfVBZK2CRD+g2D3jDwkL6d4B6JHnbJpIlQ5aLqi6KSvkD09OZxVrJ1unDvDRI/zOzDJ29TF8sGDB4m9oGux5K670QIujc1ZJHYbGxumSYS7k2YeZ2wFIXnaVL+Zh5ETMBlKO7eNnKYVPdXkzRvN0/sVCgXSNgFCxEbtu+wheTlmILr05Pgiyo6N3jEOcdUFRpwW60Qs65shp4BWOMcDkbx1XSzv3LmT+Au7UqC8KZzqpqeITpI31Y7ZqJ1b7hQ9zaucBCV5GoadlJpSSJ7oTXN+nf3prBfNO/3mdOZz0qYRk7YJEA56gOJ8x7aQvJynbHrT/qISrYEoXsSCGQX6ebz7V0ImMQv4fYoD6Zvan9WjVc7zuSWvoIulGp6k4eIuKZKQuoVJaAzB/v5+ouROXf6shLjFLo+Ru7AkT5FRvY7Seln8gEU1rrZT7zQPgWw0r/jj4lznpe38mpbrKkCauHv3rr2vbiB5OUcRn4EasZBn5ilFMS65jDMd1kTwAha876KyjcJgRO+4TX3e3JJnZuVpqHCaLvLv37/vbG9vDwifUqX0JD3OTe+vluq2qYqij0mteUy75NnupIxRAC92jpbSNqeJ5mk4ukTvoH0wV9qmTSVWmjbHAyA4XJkxRSSPaN5ANE+/DiuqpvcbGCGQzShecbAGr74daXSUtM2gRM/MypM4pfGCr5o95eir2YGVPT1Jn2ZeVhCbFnZ2XpY7epe3zplRSp4do6BurOxX8D4I+uyzz8z5sbu7O/E5tfth10je+k/W5zo3y+UyDyAAQsBVtrGI5IG/HDw+aai5R9CC5zOEPXT5iSeK119vqP0ZxfuuVOt7XmEnmje35DWyUj+iBZWiklayNLtKKX2q3QurWYvSwZQqaudkqR5IjWyoxwlf8mzb+jTUlEL02LRNNTuaNMKvaJ6dm3f+l9mvGbom2OsBNaMAwT3Ude7v533rGBZz+UbpkgNDtruiEtRYBdMN0m/O29OTw6ztS6Vken9ORfYiiiAueUdjEM2bW/JqWapr0oJKi37bfMGihZ5q9yQWSqGSIIhWa/IByIrWafGm11AamO2kZ1EaCelZ41HkTftL8j3PpmNn9zv7FUY9UNBDmEkf9Kx9tWZEb/83s9f56lqha0Rex6QAhHV/d+63TSQP+iN6PhKmSNC8dWQSnIEUTadmLOhoYUIio7V+Wa4fxCns2vec33NJXiWrLb91Q1A9nK3PmQSJmzp3ulH6p3f8gUUyKalM0kD5pHPv3j2z75RuOW8U1S6i2a8wjNu3b5vzRI2QJhmrYFM2N4435k7hts2XSCkGmB89jHbuvftIHgxE2/xlzJnpNmU0SlElb/qgp+6vmMX9KHnt+3lDbmQzSTQvazWPEUueGaOghVCWbw62WYue7GvBJfET6oA3qQDajnl6DaWCkYYVr+RpS2PjIIgWdeW13/NJ5ue1/9g2kqcmLBd/vZjr/FRtsH04pCHOHA+A2fEbn4DkQQ+nbm5/yJBt0VIN3bD2/OryaObv+aVmul4jqDTQpOFtuKKOlwmJypY5v2eWvCXbBZKbyN+ZdEstxtyo1o/xB8mUPNvFlHQ4GIW+u4r42vTecaK3+m7ViF7jd425z1E7vJmRCgDzYaPyejiN5MFwSeiKnE9tly8DTUZG/t36QRZTNF2pmluen7mW58+RIdEzHTbzOpwb0it5tp02Ag7jUDTfduFVCvao7cWvXhjJ2/z55tznqITSPowgrRtgdlydNZcyLXmXqYf1TcmKSRlUZMOiSJUkplqvZDWiFEhUSvPsfGa9zYIRwYjTFuPAm56qczCeY3e0Gkd3zwxL3qEunLT7h7RJnmoms9IdFsLHNm7QHLuRTX3OW0byln+03Ali0xgHonkAs6OH0H6dNTMjeU6qYXlaMXEiUZUsR5jmigp15Uw1ebPLXX0jL/vKe+6FNfx8EkH3NrnhXJ5L8nZ18WRoN6RN8tQQhwcUMA22Pm9cZ93C24IRvebvm0TzAGJGD/IcyTvNnORp1pt3qPcMQnJOu/nR0dGeRA+puTONWy7/LJdRUm/jmjiby3gHznMOzyV5G7p4avHNzQTSJHmVSqXDAwqYhrt375pzRiNURp5bv6gYydv7271OEJutzctiJ2OAsNE13pG83cxInhp9zBplGtlcJAephRCGWPV31oxTdL0PPTg+c0lekVQiSKPk6TUYiA5hnH+SO0meZC+I7eDgoMPDNIDZsPNVu2xmQvKUCudE34bI2nHbmRlWNimHlmq9pJq8CRqGlFngwnTpmv3nlB5CJCKSh+TNK3kLtKKHqJCQ6XzTYPl5N7Wot/MK2bcwCQ8ePJhI8tRZU5K3/pP1QCTv9PTUvK9Gt3AcAKbDNtnqspp6yTPiNqT7o5pfTJomZ2qXLoXPXxa7f8YiFyY+L71R5ZgiwmZWHjV5QYteUxdQZr9B2EjIdK5J0ILYbK0THTZhEjTnUufLixcvRp5XZ386M5K39GYpkPPUPpBQh0+OA8Bs940ui6mWPDXy8BWyxyeNWSMnowZ3I3owxcOHWhKiwd55faoV5PjMLXn7uoC+fPmSGwqEhuYQ6jxbXg6ma6G2UqlkXlM1T+xjGIet7Rknedo0EF2id/6X80DOVaLOALPfNzTuyXf9kpoUTdXg+UfwtoJKAR3y+iUWujA+kmdGc3wXVX5S340t0u2ZT8jxmVvytmgKAGFjm0+Uy+XAJM+2p6fWCYI+B+1Q9NNvTgONOn/48IFjATAh6kjrSN5BaiXPGZHQ8nYNDDpaoiiIN31Tv2amHoyPMpuaz74mPjFJ3n4YD0FyLnnruojevn2bmwqERpBNV+zWbDaZQQYTo2wFnS8avzFu0zD0IDts2roiUosBJqdarVrJ20mt5PmkwoWWDmeGSXsieqS8wUQPIjznTRwPB7wPKeJsAJMhyVsilQjCxs4ok5gFtWkG2cLCgnldDcxlP8Mo3rx5Y86VtbW18VHiD7uBdthcX183763PwLEAmAzbrEvjnlIped4aI4dayFJZIW0Tphes/oHoUadsmu6xNF0JS/TaPGWGMFEHV51jErMgt9XVVfO6GpjLfoZR2KHKOmfGbYe/PQy0w6ZSRKl9BpgOV9OV5VRKnnfhrDQ4RU1CXzB7uiWqRT6LXRjFzWp905tSrMY+EUbxmkmoC8yo5NVoYAFhoYcHOr8KhUIn6E1RGSIkMM15OEnzHztGYe2rtUDO083NTZoEAUyBOn47gjf0gX4ao3ilrL83pDdl0zuIPCrRGojiRSyYOZC8TRpYQFjYNDmlrCF5kAbJa/+xbSSv8DaYBxPq6Kn3Vo0RxwJgPLZRkh5Cp1LyvB0Lo46meaOIdCqECWSrMtAgKOSZear9i0sucyR5RRpYQNg360qlErjk2YYWzHmEcahuU+fK4uLixJK3/KPlQCVPs/o4FgDjsc26ulRSKXlqeNI/YLq+EWsksbtgjyJVFLIVzdOvw4qq6f0GvidE8cISvXMaWEAYTDqEepZNURnqSWFSnEXj2PPKDkQPSvLsgw5G1QBMxvXr1+33tZg6yfvel0eL3oWrfi/6yMxxu180w43KQCaieaWBVN/HJ42gz19ntMhg59mn9W2OQyiSd6gLqubScIOBIHnw4EHg4xOQPAhT8rRJ8jQUPYhN5z4p8QCTYVOr9fB55LolwQvlsneRHMfnUNqbZxG9w4IXZjhvTLpxUGMVzEOQ7ndiUPBODtn/oUneti6qWpBzk4EguXv3rrlhHx4eInkQK7Zb39nZ2USSJ5A8gGgZNwQ9DZK3k4ToxEBUhkU0THru+EiYUjdvPq6vz/O6SiMeSNF0RibEEe3OkeSt6aJ669YtbjIQKDqngp6Rh+TBLNgUsHa7PfbcUhQPyQOIHpv9oYfPaZW8Wpz1eBYNk2aUAswabfOXscuHBZK1KeVuaaVa3/N7Pafur8h+D1XyFnRR1TyzDx8+cKOBwBfWk0RPkDxIiuSpHg/JA4geNYFzJG8tnZLnjYLEVAvnrQ3UYpoFL0yKUze37yt6ztxHRam/qB6tDnvIYObv+aVmul4jqDRQGCt6TdrRQ9DYQehhbEgeTIoeXk2TrkkkDyB6bBfcLhd6+JzWSF7LvZCNcxFr2uC7PguLXZj6HNI4EM95NAzvUPPRf7d+QIpmpJK3q4vr8+fPudlAoDfsSWaTIXkQJq9fvzbnSqEw2ew7Cd7C64VAztPd3d0ONc8Ak39P9dB57JoluZLX39UyTsnrLrrPkTyYFzPPzjN7cVaMCNLpNQ7J29DF9c6dO9xsIBDUbEXnlObZhbEtLS2Z13///j37G0Zi525tbW2NPa+CHqHAnDyAybAjd/TQOb2S50lPG5bOFlG6Xd8oBxa7MNe53ZUz1eTNLnfx1KeCkbxlXVyV0sTNBoJAqb86p9bX10ORPNsSn30No3Cnap6eno49r+ww9OKPg3k4IbHUe1erVY4HwAhso64upRRH8gbqmEpxfA5FX7wdDFnsQhA49Z5lE90bUnNnGrdc/lmFurvEiF5bF9i3b99yw4G52d7eNjfscrmM5EFs2BSwSdOGG79rGMlb+2otkPNU57/eX0PROR4A/ii939ZwdxlbqpPYhZR3zpiaT8QWdUnAvD4ASIzk7ZJWBEGgFMrPPvvM3LD39/eRPIiNaVI1tR3+9tBI3sbxRiDnaalUMu8v2eR4APjjmo93OtF6JcGRvIq3wUQsn0MNM/qjKzUWugC5lrx1W0PFTQfmwQ5BDytV8/z8vEN6MYxj2lRNbbVf14zklX8WTAR6bW2tQ4YEwGQPY8bNx0u85PnMpzuPRfIGRjlQDwWQc8lbcFoXm9QJbjwwCzY9bnFxMZT5eKZuqt0276HZZ+xzGHcuTtPhdae5YyTvxa9eBHKu0gUWYDx2juW4+XiJl7zLaF5/h82ouwlq+LS3Rop29QDQ3Q6pH4F5UIdWew6FtSF5ME10YNJUTZNe+dOSkbyD9kEg56oedpBWDDAc24m5y8RBr0QvpFaq9b04UzYH6wKPT1ngAkB3qzC4F2ZF6XG2eD6sKJ5pjtFodEgthnHn4rSpmkbKnEHo6rI573ZxcWHe/9q1axwTgCFoPq8jefuZkLybj+vr3kjaF18eFSOL4g0Or66wwAUARinAPNj0uLBm43klTy232e8w6lycJlXTjk8IakaejTivrKxwTACG4BqdUM6E5AkzFyyGaJ43ivf5k+MzzcxjgQsAjugxSgFmYpb0uFm2g4MD8z5KDWW/g18UTw8apj0XbdMVpWwG+TDi9u3bHBeAId9V1+iE5cxInubj+cwPK4f5nhq8ThQPAMZIHqMUYKab9SzpcbNstVqtQ1oxDEPXLp0fS0tLU6UNV35RMZK3+2GX8xQgAlyjE5pTrVPSsJjyRvMkYOq+GcZ7XQ6o7m/4QhQPAHwkb50UI5iWWdLjZt12d3fNez148IB9D8MWjSaSNs1W/HHRSN7pN8E8pFAUkQdmAMPRNdz5vu5kTvLMOIWByNpxO+j6PCN4T08OfSKHJRa1AOCRvN4oBQ215kYEkxBVqqa2Fy9esHiGAd68edOLJk/b3fXirxdG8BZeL5j/D2KzKaMMQgfwZ9rRCamSPCdts+yVL83OC2qsghqtDEQMu6g2jwUtAAwRPUYpwMREmapp0uoqFfNe6srG/od37965mzd0SqXpa+psPd7aV2uBnKPn5+fms6jeSN8PjhNAP5od6Xxn9VB5qqzCVC2outJVG4iyXUb4tuaKFD6urysl0/vaGplAmiYAjJA8M0rh7t273IxgLFGmamorl8sdHkKAfcCgEQU6HzSTbtb5jOs/WTeSt/e3e4Gco3t7e3SABRiBa3TC1I0nU7eo8hW9S1rTRvWU7jkkPdMIHoPPAWCM5BV4Cg2TEmWqpra1tTXzfkrPY//nG1uDt7q6OvNsxrM/nfVSNfX/QWz6PPpc+nwcJ4BBXNH3zcxLnhG9p/XtIaJnavWUYqkOmb5RO9X3VesVI4VDXkNjGojgAcCEoneqC/DLly+5IcHISEqUqZruWqfDw0OOQc6xjRvUjGfm9F+nq6aieUFszWazNwSdh2QAg6je36ZXd1nKheQ5Eb2yqckbKnt9tXvNSf6eww4LVwCYQvK2SNmEcdy/fz+SAejuTWmhes+vv/6aY0A0YK4HDIrcKYInyTtoHwRyftL9FWA029vbVvAOZ1qfpHlxpWYpI9I3p+PxSSPobp0AkAvJWyZlE0ahdEmdIwsLC5FF8S4uLsx7KnrIMQBbjzdrqmbQUTxT37e+Ts0owAQPZ7qUcyd5PdmrHq0qxXJWuWNEAgCQsglhIPG37a810iCqzabCKXLIcQCb8jXL1jpv9aJ4zd83Azk/7QB0UjUB/HGlaqqr5mJuJc9yOchcaZxd4buUN9+GKs6fVRQJZIEKAKRsQljYNE01mIhy29/fN++r9+c48KDBRpKnjgj/9aKz+m7VCF7pp6VABU8oHY1jBDCIK1XzYOa1CQs0AABSNiF43GmarVYrUsnb3NxkRh4Y7JytWUZ3vPjVCyN4S2+WAumo6Ra8R48ecXwAhmAbZ3XZQPIAAOIVPVI2oS96YtM0Z51JNs+2tLTE+ASYS/JOvzk1ghdUsxUED2C67+wsA9CRPACA4CXPpGzeuXOHmxTE0k3Tbo1Go1fvxLEAjdDQ+VAoFCav6fx9s7NYWzSCp6YrCB5AdFSrVft92Z9rXcLiDAAgEMnrpWzSsj7fuNM01QAl6s2malKPBxK8GzdumPNhY2NjasFTN03V5SF4ANHhStVcR/IAAJIheqe0BM8vStHUIlaiH3U3TbtpdAKpmqDOfHYAuo3inZ+fI3gACceVqnk+T6omkgcAEKzkmZTN27dvc7PKGe/evetFTMTW1lYnjs2m5qkekOOSzwWiIrj2QYMol8sTCd7+b/Z7oxIQPIB4cKVq1uZek7AwAwAITPJI2cyp4GnouI2YRDXw3G+rVCrmczx8+JBjkyPevn1r6oGtVNn0zEnShSVzmz/f7DVZUQ3ePIKnTrKKYiN4ANPjStVcQ/IAAJIleqe0rs+n4ClionTJOLe1tTXzWV6/fs3xyUHUTk/9bRdXsbi4aES/3W5PdL6og2bhbcHInaJ4iubNE7nTQw63aCJ4ANPdT5zvzlkg6xEWZQAAgUpeWRfplZUVblo5WGR/9tlnPcGLe5NgqtmLPg+R5Gyiuk/V/Col3C1TGo+wu7s7UVqmNs28K/+s3IveSfRUjzfLpvdcX1/vfRY99Lh3756JLnLMACbHVUe7g+QBACRP8hacgmnzVI4bV3YX27YGr1QqxS54pqZqf783toFjlC3UREfi5K61k9Dr4cI06cFKw9z9sNtrrqLonQaeT5ueqQcKity55U6fTZFFjhfAbPeUq1evfut8n5aRPACAZIreLi3ss42dg6f0tLhTNO1mazlIFc4GaqKj2kp3OqZYXV01gjVp1M4td0tvlnrROzVXaf+xPdU5pno7jehQWqj7M926dct8Xo4bwGwoQu98nw4DW4uwIAMACFzyivbJtp7OcQPLFq9evepFUrToTcJ2cHDQG4DOOZdeNPpge3vbpHu7JUpjMdSxddrz7fwv5wNyV/xxsXPQPpgqHXNvb2+g3k4poy9fviQ1GCAAXA1XSkgeTEzh2dFa4Wl92/D4pNFHtb5jfr9aL934/tEC+wsgMNFjZl5GF+G20YqiKUnZiOKll2F1dp/8dz7p/OPyPzYRsmm31nnL1NzZkQhi7au1zuFvJ38tpYEqHdTWedrRHGqmonpUjh1AMLgbrsw7Gw/JywE3H9fXu+JW+7x6fN79b2cinhxffF6tH3T/v4zwAcwteWXqo7KHbVOflDo8bTbNRwtwonjpQY1JVGdnHxpY1CH1Ve1V5999+++aermp6jJ/s29kzoqdTcts/K4xca2dX9Tu7t27dGwFCAlXw5XdQNchLMayxRfVo9Wb1ePTicVuCJ8/OT4rPKtvsE8BZpY8NWD5gy7c1KpkAy1ybZv6s7OzRAiezi0baWERnlz+q8a/7vzzN0edf/J/+FHnf/q/+c87/86//7jzb33vH3eu/ls3e7Wd6o6p0QdKsVRKpU2tHHsO/PbQRO1sMxXbUEWz7xTRm7XWTqm/aqSi6DXHECAcPA1XCkgeDMrdl0dLXTnbn1fuvEgYb1YbBfYxwEyiZxqw6CkdN7PsRPG0GE/Cps9hF+Q0+Ukm/7r5/+z8B//Z/63zvYc/HMr/8sV+p312bo6pGqEs/2i5LxLn1xxF8+0kce5aO6F/u9PcMaI4UeRvf783W9Fba8fxAwgfV8OVRuBrEBZimRC8YqF63B4ZlavWa122TH2em2q9svKkvjvy31+mfJbY1wBTS16RZhjZQNEM22wlCVE8t+DxECGZ/F/+7+87//B//YORgmf5h//h684P/x//9YDgib2/3evV2VV+URn4OxI9/f6kc+50/r548cI0c3HPttN5RK0dQLS4Gq4Enj3HQizlSL5USzdE0PYlcpO+liJ2RviGv16FfQ4wteiZBiw8GU83NlVTc8Hi3tTwxS7O1YmR45Ms9EDnxX/6/c73/sn/cSLBc/Pf/hf/gwHJk9RpWLlX7BTJm7TWzt1IxR2106xHRRJ4CAUQPa6GK+dBNlxB8rIgeM/qG8NSLFWbN3NksNpYLjw9OfQVvaf1bfY9wFSSV7YpUNzU0ou6Vuo4ViqVWAVPC3Vbg0fn1mShUQLqPKnI/b/97/1HUwueWKn8x53/xt6/MSB6QjV3qr2bZvyBfSig2XreRipq/MJxA4iPsBquIHkpx6Ro+kTcFIkL6j1uVuubQ6J6JY4BwMSS12vAQipUerHDz1XDFNemNDubYieZ4Lgkhzdv3vS6ZH763/93ZhI8y2f/6f94QPCUjqmB5tOcK96UTMmnhqvTSAUgfjwNV4pIHhi+9+XR4kANXVfGJGXBRwuP1gbGMJj3ohkLwBSiRwOWlHPr1i2zUFYkLa5NYxuICicPm8prxx88e/l/nUvylp+XByRv43hj5pRMDVYnJRMgWdjsEJV0hLb2YAGWPpxZdp4UzeAFrxc1rB6t+kT0WszSA5hY8pY++uijP3/yySc8RU8pmkGnG3IcTVfOz897C3fOoeSh1Ed3Km/1//TTuSRPKZt+qZqjInmkZAKk857SJbTsOBZgKeOyk6YnRbNa3wv7fU3qJo1YAOYRvQNd0DV3ihtc+rCdNaPeGo1GL+VOgkejleSh5iU6Ps3mZXfLf/T0zVySJ/xq8jQPz5uSubW1RUomQMp49eqV/c62Ql13sPhKdxTv8+pxM6qI2sB7Pzk+I5oHMLHkMU4hpaiWUsdueXk58ho8O5xaKZrUdCYTm8prJe/hv/hqLsH7nzz9m86LX73orH211jcuQd00tR0eHnY2NjZIyQRIKfq+Ot/dUIMlLL5SHsWLsgmKGbg+mLZJNA9gctFr6MKuXHxudOlBXRN13CRc1OCBlzt37pjjJPnS9i/e/mIuyVO6p3f76u++6jzae2QeNFixU2T33r17pGQCpAh9X53v8FkYYxOQvJRyObS8P4oX92fQuAaODcDEkleyT9252aULRWB17FQfF8Wmzoh2SDWpd8nGtkHXgHptP/3Xv5lL8mqHzb50XdVj2rEZQrU8SvvmvABI70OhLjuhrzlYeKWHgY6aMYwy8Ivm6fc4PgATi15TF3jl5HPDSw82JS/MEQpKz1Q0aHNzsxepUedG9n+ysfU16+vr5jj+5f/3187//D95O5PgqZ7v//3/aZvUS3fUzkZ0OR8A0otr+PmFGrIheWDlqugdYxBXPVzh8UnDI5tljhHAxJJX0UW+WCxy00sRipzouCmFMuhNESB38wzLy5cv2fcpQHVwdkZeu902x/TD//ebmSTvf7bxH/adA0TtALKDa/j5XiTrDRZdaYni1bf6UzXrB0n5LF1qHCOAiSVvwcnFN0/1uPGlAy2yFVnTcSsUCqbxheRM6XSzbq1Wy8i+XdBLFBQx1KBzRfTY7+lbvGmMwcXF5aiDH/6Xv5pK8P7tf+8/6p0H1NoBZPceEtbwcyQvpWhMQlRz8cZGFTU3zy15j08aHCOAqURvWxd65eZz80sPSsuzEZsgUbSGNLx0o+Y8dpSC0iyV1qv6zff/r9+OHalQLO92/rs3/6G5Hih6S4dMgOyh0SbONT+yIA0LrpTgHV9w83F9PT7Jayz3R/KO2xwjgKkkb8nJyactfgpRBFY1U/fv3++LxE2LnurqNVjUZwNFX12t0Xv8Nz/+b3WWiusmUvc//F/9857Y3fzH1c7/6N/f7Pzv/pP/vZFE9iFANtE1/tq1a98614TI1u8suFKCulh6mp0U4/w83vpAjhHA1KK3qwu+0ry4CQJkB41IUdqtKzWrhx4K6Im+IrfIPUB+rgnONSDSrvgstlKCt7OmommxRhafHJ+5Pw/HCGBqySvaaA5NFQAAADIbxbOSV0LyYFCqqsfN/pq8RiExkTwkD2BW0TsgmgcAAEAUD8nLayTv6clhn1g9O1qL67OYWXnU5AEEEs376KOP/kw0DwAAgCgekpdHyavWa0mZTeed2ad6QY4RwMyit0unTQAAAKJ4SF4uI3n1bbdYaaRCjMJZTsrMPoAMSF6v0yZz8wAAADITxfs2riheJiXve18eLWqGnKTIzJZ7fNLoUa3vO7JUibtxybRoZEJSUiTNfuyPKm6xWAcgmgcAAAB/16lWq7FG8TIjeTe+f7Sg6JJ3ltw4nGYmFYlhGn7G7uc97++webQax2fxfo64m8AAEM0DAACAJKAae9cIlSKSN3tUqeRt5z8tjrRUUvCz9kXQVp7Ud2P4DBWargAQzQMAAIBB1DHbEbxYy5lSuyBS9Gig4+T8tOLsWjmJ0HqHkKvTZaTRRI9QxyGaAETzAAAAgChexiRP9WnelEFvdEnyYRqEdKWthyTpaX3bO3POh3JSf3bvZ49SsgaieBFLJkBeonkrKyvcLAEAAIji5UfyjLh15cJPztRoRe39J3kdNV5xhM9fFrt/lopo3iWlKCKn3n1FFA8glGjeH3SDePXqFTdMAACAFEXxPv7442+TEMVLneQVntU3fIXs8Ulj1uYfikSZLpwpEj1vNE/yFWbzEzWmMamsRPEAohC9CtE8AACA1EbxaolYT6Rl4WNq8PwjeIG07zcjCvxfv5S0feGkng7UE4YxFsJ0LvWvfaywIAcIRfIWupzpRvHy5UtunAAAAAlHtfROFE+19YkIgqRi0eOMSBiIJAVdO6dUT29Kon6dxJl6g10uu5/1yfFZkGMV9HMPqV9MxBMKgKxH865du2YGqnIDBQAASC7qjO1E8RJTypSKBY+kIqrmKJIkb0TvZvX4NKH7ZX9gv1x+9i2J8Zyv7TuaQvti3tcGgIlEr6kbxqNHj7iBAgAAJBTV0DuCpyycxKyRE7/QUXQt6kiSX5QsiWmblwPS/QfAO4JWnml/Pz5pDBsen4bB8QAZkbw13TTUilnF3NxIAQAAkoWybW7cuGElbzNR64ikL3R8JKYVRSTJW4cmwUlwpHNn6KD3S9lTJLTkJ2jal6pHvBw5cdweMVZinwgeQOSid6Abx927d7mZAgAAJIznz59bwUucJ6QxilfK+nvPJHrP6hujZwf21xmOEbr+9M+EdhkFyIHkMSAdAAAggSjL5urVq3ZkwhqSN1U0rb4dZzTNG0XUr5O8v5xRBzvD5ghOi37eJDadAciZ6O0wUgEAACBZJGnweeokT00++sTjWX0j1khiV57SkLJoBr1X67VJI3v+chdcl04AmEvyGKkAAACQIJRd4wiesm0SGRBJelSqT7DiaPoxkNb47Chx4diRn7/7ec2wd9NMZTBF04jgZaOVmiSaujuARIreBiMVAAAAksGtW7cSNzIhNZKnzpB9QtIVkTg+x2VDkj4x2mHRCQAxiN4pIxUAAADiJakjE9Ikef0dI2Nq/qFmK/2f4+SQBScAxCB5RUYqAAAAxIeyaa5fv57IkQlpkrxanPV4lpvVRiEtoxQAAnmooYZHQmm8bvTg5bIZUom03thEr8ZIBQAAgHioVquJHZmQHsnzDuSOqRbOWxuouXMsNiFTYtf9bk3dqOeyg+t+XA9fcix5GqnwB91gXr9+zQ0XAAAgIk5OTjoff/xxYkcmpCmS13IvKuNs5e8dScBiE7KAiVI/PTkMYNxG6+bj+jr7NDLR26QJCwAAQLS4mq3UUrFeSK7k9XeCjFPyvBEOFpqQZhSd9mkoND9dYWSuYmSi19CN5v79+9x4AQAAQmZ7e9vdbGURyZtH8jzpmnHNbVPtkTdNjUUmpBVnhmJr+IxE80BD9bBbJo3TTbVeuZTDwVEc7n/PjMVIJK/Q5c+64bx9+5YbMAAAQEio2dnVq1dtmmZqylQSHMmr73sWkKUYF8Wuz3HcZpEJ6RS8o9VhdXefV+sH03zHvvjyqDjQHMldr0etXhSit60bzo0bN0jbBAAACIk7d+7YKN5BqtYJSf1g3nSym9V6LG1KnQhG7PP6AOY+jz21pbZb7DxNjYzseZskfUeZfR+q5C2ouxez8wAAAMLh5cuXVvDO1fwMyQsmklfxRhpi+RyXLePdC9dUFFsCuKPR6grrI2G1oEYhmPROn4geqZuhi96qbj7q9vXu3TtuyAAAAAGhNM1r1659m4aZeKmSPJ/5dOexSN7AKAfS0CA9SOJuVo9PfQRvK/hoYX3DGy2UXH7x5VGqnnylUPR2dQMqFovclAEAAALi3r17NoqXyiy+ZKeYeRs8RDwrT4tT7+JYnQlZWEJaMAPMB7pg1rdDfL+SX9dNjkWokqe0zbZuRM+fP+fGDAAAMCeaResI3oWanSF5AbNSre/FmbI5WBd4fMqiEtKCeUjhrcOLQLiGjGcocUxCFb113Yw++eQTM6yVGzQAAMBsqJnZ9evXreRtpXZtkOQPpwHL3sWiGj3EtkCu1issKCEteGVLqZNRRaK9ac5q8MIxCV309nVDun37NjdpAACAGdEMWkfwUr12SfwHNN3/Yojm+S2Qg2pSAZD1hxTOiAWiedFK3tJHH330jW5MOzs73KgBAACm5M2bN1bwNIu2mOp1QdI/oG+NT8it2dURkCgepBlvt8s4HlI4s/di75CbM9HbsGmbh4eH3LABAAAm5Ouvv1Y3TSt526lfE6ThQ3qjeRIwdd8M472UzuZt+EIUD1IneYOz6yJ/SDEQzet+b/keRSJ6NdttkyHpAAAAk+Eaep6JHhyp+JBmnMJAZO24HXR9nhG8pyeHpJlBmrl8UOGpZa02luOJKMbbITenktfrtvnw4UNu3AAAAGNQmYMjeH/ospyJ9UCK0s/K3oWrZucFtWhUDdNAxLCLavNYOEKqonie70qcTU98Om3ucIwiEb1Vp57A1BdwAwcAAPBHXalV5uBIXjkza4GULV5rA1G2ywjfXO1N1cVTKZne19bIBNLLIIWStxPVXLwJPkuJmXmxid62bliqL1CdATdyAACAflTWoPIGR/BqmVoHpHABW/NJpxStaaN6pmbIPz3TCB6DzyGlktf/HXlW34jrs5hUa0YpxCl6Dd24VGfAzRwAAKCfR48eWcFTmUOm1v3pXMQ+rW8PET1Tq6cUMXXIHLHorBgpHPIa6gJIBA9SK3nepisx1sF56wMVMecYRSp5y059AWMVAAAAXHjGJaxmbg2Q4mhF2dTkDZW9/ujBJH+PmiHISCSvlYSmK73P42maxDGKXPTKjFUAAAD4DpUxXL9+PTPjEjIlecIMfB6evjkdj08aQXfrBIhH8vo7WsYted6HMRyjWESPsQoAAAAO9+7ds4LXyOy9Pws/hFIzvYOXp5E7RiRApiTPk645LHU5CpT27G2UxDGKRfIWGasAAACQzXEJmZU8i1P/UzbCNzgMutdQxfmziiKBLAAhe5G8+n5S5jwqiuitmeUYxSZ6q85NrfPq1Stu9AAAkDtUtvDxxx9/69wPNzJ932fxA5AtfGbTVWITzmdHa97IOccoVtHb0o3t6tWr31KfBwAAeUJ1eDdu3LBRvL3M3/NZ+ABkLpJXScpsOp9OuJmaQZNS0TvQDU43OurzAAAgL2ickCN4p10y30WfRQ9AxvDOplMdXFwjQQbHOdQznRqREslb6NJifh4AAOSFarVqBe88y3V4SB5A5qN5/R0246jLc7rf9tXEqm6W45MI0evNz3v+/DkLAAAAyCyueXhiLTf3ehY8ANnDW5enZkRxfwY1PeLYJEr0SvampxsgCwEAAMgaJycnpg49y/PwkDyAHKGZj94oWpRzIE0UzzMEPc4GMDBU9LZ147t27dq3uhGyIAAAgKygunPNh3UE7yB393gWOgDZZGB2ZIQNWAYiiU+Oz+KqC4SxonfAoHQAAMgaroHnmhO7iOQBQGajeV22wn5f1f/5vC9RvORK3qJtxKIbIgsDAABIO6o3dwTvoksxl/d3FjkAOYrmmQ6XR2uhiWW1sfx59ficKF7qRK/g3Ag729vbLBAAACC1vH371j3wvJzbezsLHIAMR/P8pKv76y+qR6shvVczSqmEQEXPNGLRjVE3SBYKAACQNlRffu3atdwMPEfyAHLMzcf19QHxUlOUAGfWKTVUETvSNFMveju6MaoTGY1YAAAgTXz99dedlZWVXA08R/IAck7haX3bR8DEzryz61Tn59NJM5axDRCI6JlGLNevXzc3TBYOAACQBm7fvu1utLKU+/s5ixqAnIheV+j8RE8RuJvV+ua0dXNOg5XWEHncpw4vtZK34DwBpeMmAACkgvv371vBO1edOfdzJC/xKMrSXTCXFYlZqdb3Co9PGj26C2knQlNRPRT7CyYQs7Jf1K2Xwqlz6ll9wy+6J2lT6qfOwyGpmb3oIPs69aK35DwJ7dy9e5cFBAAAJJZqterupLnGfRzJS7TYKbKiuWYjFtKDEZnLphcVDaJmPyLQQ0Xv2dFaoXrcnvCcOp/q7wZY5wexi546bv5BN86HDx+ykAAAgMTx8uVLK3iCNQiSl+xIy5goyXgUkekKCulyCPQwdG6ols7beXNWJMk8XMik6K11+TOjFQAAIGm8efPGPSphi/s2kpdI1J3wZvX4NIgFt7vWSnVT7F8EesR5t7TypL47y35xBLGmc5fzK9OiV7ZPSV+/fs3CAgAAYufw8NB0gnbuTzXu10heIlGd05iISstpmlE2qXYWNb5QSuFlemGHGikEei4J7p5TvbRVnxRNc45enms1Hh7kTvTMaIVPPvmk8+7dOxYYAAAQG+/fvzcdoB3BO8z7qAQkL6mCp9TBERGjSevBFJFROuGIiEwuux0i0ACBid6+bqgaMssMPQAAiAN1fFbnZ0fwml0WuUcjecmLnGi+mJ84PD05nLXZh9NMZGeY6CHQCDTAjJLXG61w48YNZugBAEDk3Llzxz0Lb5n7M5KXPMG7jBYNCIPEJOQIVgWBRqABZhS9RTtaYWVlBdEDAIDIuHfvnnsWXpH7MpKXOBQZ8kaFJGQSs4DfpzgQfXpyfPFF9WgVgUagAWYUvWUrerdv32ZYOgAARCl4moW3zv0YyUskn1frBwMCErDg9YSk2igMCslxO6vphQg0QCSiV3CepCJ6AAAQKprViuAheWmQkOJgCmF9O9TIlpqI5CTqhEADRCZ6RTssXaLHQgQAAILm0aNHVvD+jOAheQmXEDNU+zspeHzSiOJ9TWt8zwiArMkIAg0Qn+gplYYFCQAAhCB4YoP7LpKXWBRR8gpBVIOkTYdIdZXMsIwg0ACxiN6ak0KD6AEAQCBsb2+7Ba/M/RbJSzTOEGlXrVj9IMr3X3lS3+1vRHJ8ikAj0AABiN66k0rTefDgAQsUAACYmZ2dHQQPyUub5B23+0Tg2dFalO/vJyP6PQQagQYIUvSUYsNCBQAA5hQ8HpgjecnHWy+mhh2xyNDjk4Yn4pSJJyQINEAiRK9sb86IHgAATMPr1687H3/88bfOfWSb+yqSl5ZIk3c4dy3PnwOBBkD0AAAAEDwkL9V4m3MENZh7aiGqHq3G0ZwEgQZA9AAAALy8fPkSwUPyvuN7Xx4tSpTUIt8IlKIolmp9X7+v5hdfVBvLSfi83vltYc1uGy95jWXvXDcEGoEGCFP0NMiWhQwAAHjx1OAheHmVPLWlVwqc38DrUTit9SsSw7g+uxpxxNH5cUjE6bv98+T4Iu0nMQINkGjR+zPjFQAAwItnTAKCl1fJ09BpzR+bRu58ZO88rtb23sYgcUYYvfsx7ScxAg2QaNFbZ44eAAC48Qw6r3C/zKHk3aw2CoWnJ4fzyJ0Prai7L3oHdevnSoSIZEDyEGiAVIjeH3Qzv337dufDhw8scgAAEDzm4OVV8pR250TfhsjacduZT1aWtPWo1kuqyfOKlQ+RnVgDohqxZFpMq/+MpRQi0ACpEL0iogcAkG+U0YHg5VzyjLh55o5Z1Ghj0pQ8Uyd1KXz+stj9s4h+nloS2ut7xw1kYWg3Ag2QKtE71829WCx2vv76axY9AAD5Ezyl8K9zX8yh5BWe1Td8hezxSWPWKI0W4N4ujFGKntPt8ztRfVLfjU2e++oU6weplzwEGiBNorfcpa0b/crKCqIHAJBxlLlx584dBC/vkmdq8PwjeFuBvP7j+vqQ1y+FK64mjbSvLjAmIdoPY7/GG8lDoAHSLHonJycshAAAMip4StF3BO8cwcup5DkjElreDoVBR2YUcfGmb+rXYTbsMD+bRy7jaBDi/bnjrF9DoAFyLXqLXZq68V+7dq3z7t07FkQAABni/fv35kGeS/CK3P9yKnk+aXehpd6ZwdUe6Qo7vc47zy3qiJNpSJPBmjEEGiDVotfQAuDjjz/+9tWrVyyMAAAygB7cXb9+3QpeG8HLseR565kcaiFLTyXKtM2b1fqmN0qpWsEIJaSZhLRGBBoAXKK30KVmu609f/6cBRIAQIp5/fp15+rVq98613VlbCxxv8ux5HkX6Uq5U4Qm9MW5pzOjRCjMiJN3jlpUMjIgIRELZtgg0ACpl70tK3r3799noQQAkEJ2dnbcIxIO9CCPe1yOJW9IFK+UxfceiB4qzTDklv9KXYxLLqMCgQbIhOiVu/xZiwN1YmOWHgBAenj48KFb8Ha4ryF5A90Rw4ymTRJFDLMrop+M6NdhSYHeT7WGeZAQBBogE6K3ZmfpqWBfhfssngAAkoseyN29e9fK3Z8Zco7k9RiQkGf1jVgjiV05CDNVdLB+63IG4Pe+PFoMWvB8m9lENAA+CdE8BBoglaJXsCMWVLhP500AgGSiWafFYtHdQXON+xiSZ5DYeBfJQcvOZOJ13O4XzXAjQIr2eOVLEcygukKa/doVx0HBOznM8gmNQANkRvTUefNUCwcV8KuQnwUVAEBy0IxTTwdNuoojeX2L8rJ3QR7H5/CRrtBzif0kTJEnDWyfNzI5EGFyOj7GIdAJOJYINEA6RW/BKdyn8yYAQIJ48+aNu4OmHshlfn2J5E0veTtJiIQMRIAiWLBLFvxl7PL9JWtTyt3SSrW+5/d6TtpiMS8nNgINkCnZ27Wip7oPGrIAAMRHtVp1N1jZp4MmkjdMrmpx1uNZNLg6juYvTtrfvq/oOaMkJL4a3j7sc5vxAX6RJddrxDEcPE4QaIDMid5GlwvbkOXw8JDFFgBAhKj+Tp2PXYJX4f6E5E0ecQm5Fm6UFHgX7pHuB3UYVTfI4aLWJ6CT/D3bKTSvESYEGiBzolfs0rJ1eq9evWLhBQAQAWqAdePGDRqsIHlTRfJa7kVznAtmr2RF/f6mHf/gUPiZMCIYkzAnDQQaIFOit+iu03v06BELMACAENGA848//tjW3zW78HAbyZtE8vq7WsYped0F/nmcktfbJ105U0rh7HIXT8prkkGgATIne1tW9G7fvm3SiFiMAQAEh+qf79+/707P3KP+DsmbXGg8qXDDUufCxknt6xvlEPe+cVJIy0ZOhqQMmrqzyz+rkDaIQAPkTPR6g9OZpwcAEBwaj+Caf6d66E3uO0jelJG8gZqpUlyRHm+3RE6Q7IJAA2RG9JbsPD2lE718+ZIFGgDAHHjGI5x1WeV+g+RNjXemmRpdxBbhScC8PgAAmFr0Fpw0IvPU+cGDB4xZAACYAdU5u9IzG3qQxn0GyZtNrqr1ireZRSyfQ805+iM5NU4QAIBUyZ7GLPyZMQsAANPx/v17d3qm2OW+guTNhc98uvNYJG9glAO1VwAAKRS9gh2zoPTN58+fs4ADABiB0txd6Zmqc2YNjOQFJFieDptRdy7UoGtvPRat8QEAUit6St/cdXff1FNqFnMAAN+hrsT37t0jPRPJC4+Van0vzpTNwbrA41NODgCA1Mveuu2++emnn3Zev37Nwg4AoMvbt2/dw83VPXOL+waSFzg3H9fXvZG0L748Kkbx3iaKNzgou8LJAQCQCdFT981D+6RaT61pygIAeaZarbqHm7fononkhYqZQRZDNM8bxfv8yfGZZuZxcgAAZEr2tmxTFj291lNsFnsAkCeUtn7r1i2GmyN50aL5eD6zysphvqcGrxPFAwDIjegVbVMWoafZLPwAIA+8evXKO/tunfsCkhcZ3mieBEzdN8N4r8th2P0NX4jiAQBkXvTUlKVmRU8twxm1AABZxae5yiHNVZC8yDHjFAYia8ftoOvzjOA9PTn0iRyWOCkAAHIheyXblOWTTz4xUT1q9QAgS6jZ1LVr19zNVTa5/iN5saEUTa98aXZeUGMV1GhlIGLYRbV5nBAAALkSPTVlObBPuKnVA4AsoNo7jY5xRe9ONUOU6z6SlwTRqw1E2S4jfHO1d1UXT6Vkel9bIxNI0wQAyK3srTs1KmZB9ODBA5PixGIRANLGzs6Od7B5mes8kpd80bukNW1UT+meQ9IzjeAx+BwAIPeit9hlx4qeUpyYqwcAaUG1xaoxdkXv9qm9Q/KSK3pP69tDRM/U6inFUh0y/f6tqe+r1itGCoe8hsY0EMEDAACX7K12adqF0t27d03qE4tIAEgqnrl3dM6E5EueEb1qvWxq8obKXl/tXnOSv+ewwwkAAABDZG/LaVTQ+fTTT00KFItJAEgSqiFeWVlxR++UjbDINRxSIXlCzVJGpG9Ox+OTRtDdOgEAIJOit+y0GzcLKA0RZtwCAMSNaoYfPnzoljtlH6xy3YbUSV5P9qpHq0qxnFXuGJEAAAAzyF7Z3ZhFiysaswBAHGxvb6tm+FvXWIQtrtOQesmzXA4yVxpnV/gu5c23oYrzZxVFAjnYAAAwh+ipMcueuzGLFlssOgEgCt68eeNNzVSWwTLXZ8iU5AEAAMQke8UuDbvQ0qJLiy8WoQAQBkoRv3PnjlvuWjRWASQPAAAgHNkrdWnbhZcWYScnJyxKASAQlBKumZ0uudPMuwrXX0DyAAAAwhW9BacL5x+0CFML80ePHnU+fPjAIhUAZub58+fugeZil66ZgOQBAABEK3tL3nq9ly9fslgFgKl4/fp158aNG+7onVLDC1xnAckDAACIT/b66vWKxSL1egAwlnfv3pkRLS65Uyp4iesqIHkAAADJkb2+ej0t3pA9APCTO09TlXMnBXyBaykgeQAAAMkTPdXrVdzz9ZA9ABA+HTMvnLo7Rn4BkgcAAJBW2dMTfBa7APlCHXjv3buH3AGSBwAAkCHZ23bSsXpjF5A9gFzKnaghd4DkAQAAZEP2FpE9gHzw/v1776w7K3fLXA8ByQMAAMim7O066Vo92Xv79i2LY4AMRO4kd5qdidwBkgcAAJA/2Vvyyp5q9l69esViGSBlKCI/JC0TuQMkDwAAIKeyt+eWvevXr3d2dnY6Hz58YAENkGA0xNwz5w65AyQPAAAAerK36MzJ6nXjvHbtWufRo0emvocFNUAy0MMXPYS5ceOGd87dDg1VAMkDAACAYcJX7tK0C8hPPvmkc//+fVPvwyIbIB6+/vrrTrVaNQ9fXHLX7rLJEHNA8gAAAGBS2VvrcuBOBVOTFgarA0SHHq7oIYunmUqjS4nrFCB5AAAAMKvsFZw6n17dXrFYpG4PIETUBOnu3bveerv9LkWuS4DkAQAAQFCyt+TM2uvV7X366acmynB4eMjCHCCAqN3Dhw+9KZnnTifcZa5DgOQBAABAmMK30eXQHWUgugcwGy9fvuzcvn3bG7VrOfV2i1xzAMkDAACAKGVv" - + "2enq14vuXb169VuiewCj0fdD3xNP1O7CSY1e5foCSB4AAAAkQfiI7gGMwI4/0PeCqB0geQAAAJAm2fON7t27d880k2CxD3lsoqLzXzWsRO0AyQMAAIC0C9+60xGw427WYoWPCB/kTOyI2gGSBwAAAJmRvSVnYdtwL3g1aF1t4tV4AuGDtKMZkkPEru10yCxyPQAkDwAAALIsfE2ED7Igdj4NVBA7QPIAAAAgt8Kn+r3KMOFTk4r3798jE5AoXr9+jdgBIHkAAAAwq/CJlZUVMyT63bt3SAZEjoaUb29vd+7cuWMeQCB2AEgeAAAAzC58p17hU/REdU9K6/z666+REAgtWvfgwYPOjRs3vFLXcR5E7CB2AEgeAAAAzCZ8i84Mvpp7LIN7Fl+1WiXKB2FG686dLrFl1ZTyvQRA8gAAACBY6St22RoV5dNi/fDwEHmBoajWU9HgCaJ1zLEDQPIAAAAgQuEbGeVTK/vbt2+bSJ+6ICI3+UWRXsm/Gvpcv37dT+qI1gEgeQAAAJBA6Ss6tXwHftJn0zvVxEXDquncmU00gkNS/+jRIyP5PumXVuoOnagw0ToAJA8AAABSIn3LTqRvz69rp1CqnlI8nz9/bsSAGX3pQ8dN4zaUeimJ9zvOXVpOxFeRugLfDwAkDwAAALIhfQtd1rpsO1GcCz8hUG3frVu3TCRIdVtv375FphKA6iwVgdVxUYOUIbV0loZznNeV1sv5D4DkAQAAQH7ETymem86ss8Yw8bPz+lTTJclQi311ZES+wmmKouicaikVZR0RnXML3Z6TqkvqJQCSBwAAADAgfsuuiN++XydPb8qnIn9KF5QAKtpE6udoFB21dXOqkdT+m0DmWk69pY3QkXYJgOQBAAAAzCV/ivqVXOme7TFS0mv2YtM/heRGZHXMgyKc9mdUraNNr9Q+GNIExcuZK92yTHQOAMkDAAAAiFr+bOSv7Ir+NYZ1+ByGJMhy//79nhSq9b+VJjdhRAo1asDvvZSeaj+PUNqq+/NO83M6KbENV1Su4uw/InMASB4AAABAKiSw6EhMxRUFbIyrAUwxDRfbzpiCNSJyAEgeAAAAQN5k0EYE15yas20XBx55spwGLGjNIe9z6Pk8JddnJQIHAIb/P9KYNmyq3IR9AAAAAElFTkSuQmCC", - fileName="modelica://SorpLib/Resources/Images/MassTransferDiffusion.png")}), - Documentation(info="<html> - <p> - The Mass Transfer Diffusion model extends the <a href=\"modelica://SorpLib.Components.MassTransfer.Partial.PartialMassTransfer\">SorpLib.Components.MassTransfer.Partial.PartialMassTransfer</a>.<br> - The Mass Transfer Diffusion model describes the mass transfer resistance caused by intra-particle resistances.<br> - The Mass Transfer Diffusion model can be used to model an effective mass transfer resistance (e.g. LDF approach) but also to model detailled diffusion process (e.g., Knudsen diffsion or surface diffusion) - with spatial distribution of the particle using a finite volume approach. - </p> - <h4>Main equations</h4> - <p> - The mass flow <code>ṁ</code> can be proportional to a pressure drop <code>Δ</code>p or to a loading difference (<i>x</i>-<i>x</i><sub>eq</sub>): - <p align=\"center\"><i><code>ṁ</code></i><sub>in</sub> = <i><code>β</code></i> <i><code>Δ</code>p</i></p> - <p align=\"center\"><i><code>ṁ</code></i><sub>in</sub> = <i><code>β</code></i> (<i>x</i>-<i>x</i><sub>eq</sub>)</p> - For the mass transfer coefficient <i><code>β</code></i>, different correlations are implemented based on the partial models - <a href=\"modelica://SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp\">SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp</a> - and <a href=\"modelica://SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dx\">SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dx</a>. - </p> - <h4>Implementation</h4> - <p> - Two adsorbent/adsorbate equilibrium models are used in Mass Transfer Diffusion model to determine the loading <i>x</i> and the equilibirum loading <i>x</i><sub>eq</sub>. - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html> -")); -end MassTransferDiffusion; diff --git a/SorpLib/Components/MassTransfer/MassTransferDiffusionFlow.mo b/SorpLib/Components/MassTransfer/MassTransferDiffusionFlow.mo deleted file mode 100644 index a306038186587ab72eba2b305d3190c1040a47a7..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferDiffusionFlow.mo +++ /dev/null @@ -1,185 +0,0 @@ -within SorpLib.Components.MassTransfer; -model MassTransferDiffusionFlow - extends Partial.PartialMassTransfer(final computeTransportProperties= - massTransfer_diffusion_dp.computeTransportProperties or - massTransfer_diffusion_dx.computeTransportProperties or - massTransfer_flow.computeTransportProperties); - - /************************* VLE models ************************************/ - - TILMedia.VLEFluid_ph vleFluidAds( - p=vlePortB.p, - final vleFluidType=vleFluidType, - computeTransportProperties=false, - computeSurfaceTension=false, - h=inStream(vlePortB.h_outflow), - xi=inStream(vlePortB.xi_outflow)) annotation (Placement(transformation( - extent={{56,-40},{76,-20}}, rotation=0))); - - /********************* AdsorbentAdsorbate ***********************************/ - - replaceable model AdsorbentAdsorbate = - SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater - constrainedby - SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater annotation ( - choicesAllMatching=true, Dialog(group="Adsorbent / Adsorbate")); - - AdsorbentAdsorbate adsorbentAdsorbateStar(x=xStar_eq, T=T) annotation ( - Placement(transformation(extent={{-40,-40},{-20,-20}}, rotation=0))); - - AdsorbentAdsorbate adsorbentAdsorbateB(x=xB, T=T) annotation (Placement( - transformation(extent={{80,-40},{100,-20}}, rotation=0))); - - /***************************** Mass Transfer model **************************/ - - replaceable model MassTransfer_flow = - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp - constrainedby - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp - "Mass Transfer Model" annotation ( - Placement(transformation(extent={{-32,-70},{-12,-50}})), - choices( - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantCoefficient_dp), - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantSpecificCoefficient_dp), - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.MassTransferPhenomena.Laminar_dp), - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.MassTransferPhenomena.DarcyPorousMedia_dp - "Mass transfer in porous media following Darcy's law"), - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.Record.FlowCoefficients.FlowRes_Lanzerath_des - "Coefficients Flow Resistance adsorber -> condenser (Lanzerath 2015)"), - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.Record.FlowCoefficients.FlowRes_Lanzerath_ads - "Coefficients flow resistance evaporator -> adsorber (Lanzerath 2015)")), - Dialog(group="Flow")); - - MassTransfer_flow massTransfer_flow "Mass Transfer model for flow resistance"; - - parameter String inputChoice="dp" "Driving force of diffusion" - annotation (Dialog(group="Diffusion"), choices(choice="dp", choice="dx")); - - replaceable model MassTransfer_diffusion_dp = - MassTransferPhenomena.ConstantCoefficient_dp constrainedby - MassTransferPhenomena.Partial.PartialMassTransfer_dp "Mass Transfer Model" - annotation ( - Placement(transformation(extent={{-32,-70},{-12,-50}})), - choices(choice(redeclare model MassTransfer_diffusion_dp = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantCoefficient_dp), - choice(redeclare model MassTransfer_diffusion_dp = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantSpecificCoefficient_dp)), - Dialog(enable=inputChoice == "dp", group="Diffusion")); - - MassTransfer_diffusion_dp massTransfer_diffusion_dp - "Mass Transfer model for diffusion resistance"; - - replaceable model MassTransfer_diffusion_dx = - MassTransferPhenomena.ConstantCoefficient_dx constrainedby - MassTransferPhenomena.Partial.PartialMassTransfer_dx "Mass Transfer Model" - annotation ( - Placement(transformation(extent={{-32,-70},{-12,-50}})), - choices( - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantCoefficient_dx), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantSpecificCoefficient_dx), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.MassTransferPhenomena.Glueckauf_dx - "Glückauf-approach dx"), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.MassTransferPhenomena.GlueckaufArrhenius_dx - "Glückauf-approach with temperature dependance dx"), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_Zeolite13X_des - "Diffusion coefficient and particle diameter for Zeolith 13X desorption (Lanzerath 2015)"), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_Zeolite13X_ads - "Diffusion coefficient and particle diameter for Zeolith 13X adsorption (Lanzerath 2015)"), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.Record.DiffusionCoefficients.Lanzerath2015_SilicaGel - "Diffusion coefficient and particle diameter for Silica Gel 123 (Lanzerath 2015)"), - choice(redeclare model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.Record.DiffusionCoefficients.SakodaSuzuki1984_SilicaGel - "Diffusion coefficient and particle diameter for Silica-gel Fuji-A-type (Sakoda Suzuki 1984)")), - Dialog(enable=inputChoice == "dx", group="Diffusion")); - - - - MassTransfer_diffusion_dx massTransfer_diffusion_dx - "Mass Transfer model for diffusion resistance"; - - /****************** General parameters *******************/ - - - Modelica.SIunits.Pressure dp_AStar - "calculated pressure drop between A and Star"; - Modelica.SIunits.Pressure dp_StarB - "calculated pressure drop between Star and B"; - - - /************************* Additional variables ***************/ - Modelica.SIunits.Pressure pStar - "Pressure after valve before adsorber (flow resistance)"; - - inner Modelica.SIunits.Temperature T "Temperature of adsorbent"; - Real xB "Loading of adsorbent given pads and Tads"; - Real xStar_eq "Equilibrium loading of adsorbent given pStar and Tads"; - -equation - adsorbentAdsorbateB.p = vlePortB.p; - adsorbentAdsorbateStar.p = pStar; - T = vleFluidAds.T; - - dp_AStar = vlePortA.p - pStar; - dp_StarB = pStar - vlePortB.p; - - if noEvent(valveOpen) and inputChoice == "dp" then - vlePortA.m_flow = massTransfer_flow.beta*(vlePortA.p - pStar); - vlePortA.m_flow = massTransfer_diffusion_dp.beta*(pStar - vlePortB.p); - adsorbentAdsorbateStar.p = pStar; - elseif noEvent(valveOpen) and inputChoice == "dx" then - vlePortA.m_flow = massTransfer_flow.beta*(vlePortA.p - pStar); - vlePortA.m_flow = massTransfer_diffusion_dx.beta*(xStar_eq - xB); - else - vlePortA.m_flow = 0; - pStar = vlePortB.p; - end if; - - annotation (Icon(graphics={Bitmap( - extent={{-90,-64},{84,72}}, - imageSource= - "iVBORw0KGgoAAAANSUhEUgAABH0AAAKJCAYAAAAmxVWBAAAAAXNSR0ICQMB9xQAAAAlwSFlzAAAXEgAAFxIBZ5/SUgAAABl0RVh0U29mdHdhcmUATWljcm9zb2Z0IE9mZmljZX/tNXEAANy7SURBVHja7P19aFx7/ueJ+SbstUj2GoW4GbFOQBGzdsnLhmKaGM0fThSiDFrMLIUDiQwBFxkwStYsZZedq3iWtSZsVg3DWDsBR92zgoJ40op/aa7kn5NWGqlUTRq3+M1tKHDyi/pHOggaGt0/GtQ0NOoOfV2p91fnW1116tTzeT6vAy/utSzXw/c8fb+v83m48s/+2T+7AgAAAAAAAAAA6YJBAAAAAAAAAABIIQwCAAAAAAAAAEAKYRAAAAAAAAAAAFIIgwAAAAAAAAAAkEIYBAAAAAAAAACAFMIgAAAAAAAAAACkEAYBAAAAAAAAACCFMAgAAAAAAAAAACmEQQAAAAAAAAAASCEMAgAAAAAAAABACmEQAAAAAAAAAABSCIMAAAAAAAAAAJBCGAQAAAAAAAAAgBTCIAAAAAAAAAAApBAGAQAAAAAAAAAghTAIAAAAAAAAAAAphEEAAAAAAAAAAEghDAIAAAAAAAAAQAphEAAAAAAAAAAAUgiDAAAAAAAAAACQQhgEAAAAAAAAAIAUwiAAAAAAAAAAAKQQBgEAAAAAAAAAIIUwCAAAAAAAAAAAKYRBAAAAAAAAAABIIQwCAAAAAAAAAEAKYRAAAAAAAAAAAFIIgwAAAAAAAAAAkEIYBAAAAAAAAACAFMIgAAAAAAAAAACkEAYBAAAAAAAAACCFMAgAAAAAAAAAACmEQQAAAAAAAAAASCEMAgAAAMRnYnLlSr1JwwdOmtTaWG+y2mSxyRRjDQAAAJmYWzEIAAAAEItJyZUrUz4Jn2HYb1JsMs3YAwAAQGrnVwwCAAAAxGpychmNsxOS/LlostVkhrEHAACA1M2rGAQAAACI5STlypXdAcLm3EnbclNxUrqOR5A/eq0S4w4AAACpmk8xCAAAABDLScqVKysDRE1tiNdQytiyE81zMYT8qZPyBQAAAKmZTzEIAAAAEMtJymWaVz9BszHi68002RxC/iB+AAAAIB3zKQYBAAAAYjlJGSx9CmO+bq7JKeIHAAAAUj+fYhAAAAAglpOUy+5a/cTM9ASvPT1Ee/hj9gMAAAAkej7FIADAEIujBac46pZTHPXEVfy05hRc1e+UeDoOAD5de9b6CJlTH15f6V5nA8RPkX0BAAAAiZ1PMQgA0GdBVByx+427o8404wgAE1yD+rVt3/HpPQalkEkKTbE/AAAAIJHzKQYBADwWQWtDPP0eWv4wpgAw5rWoX/pVycf3qQy4lm2yPwAAACCR8ykGAQDaFj5TA56s1x0htNiGooE2HMHT699VGF8AGOOa1K/LVt7H91kYIH1O2R8AAACQyPkUgwAAzqJnps9TdaV4LQzx7yt+tVYGgMxfk/J9ricXfqdcDVHUOcd+AQAAgMTNqRgEAHDaF/dK59oYZXHVpwaQFmmzjDcADHktKYbZVcupQ9YII50MAAAAILQ5FYMAkPmF1ZSrG9dEdSwGPJ3fYswBYMhrSSXMGjtDFHTeZb8AAABA4uZUDAIAC6seC5z9CV6zV5rEGWMOABNeR0QhgPebpq4PAAAApG5OxSAAZHpRVezTonhmgtftVwx6lrEHgAHXkEECZjag9+1b14d9AwAAAImbVzEIAJldVOX6dMYpTfjaG30WTouMPwAMuIYs97mGnAX4vrUBsmma/QMAAACJmlcxCACZXVTt9mrL7sNrryN9ACCga8hugO+7SwcvAAAASNW8ikEAyOSCql+x5RUfXr9fAdY8+wAABlxDdqPoojXg2oW0BgAAgOTNqxgEgEwuqDb71PKZ8uH1a6RHAMAE15DzKMQL0gcAAABSN69iEAAyt5ia6VPLZ82n9zjt8frn7AMAGHD9yA0QL1MBvjfSBwAAANI1t2IQADK3oNrss6CZ8eH1Z/q8fp19AAADriHFqK4hQ9T0ybOPAAAAIFFzKwYBIHMLql5pEzWfXr9fAdYt9gEADLiGbPW5hmwG/N6DunfNso8AAAAgUXMrBgEgU4uphT6LmVWf3uOsz3sssB8AYMA1pN7nGlKM8L2pSQYAAADJm1sxCACZWkytB/kEu7kVSO0CgAmuIVNRtkzvU4/MwD4CAACAxM2vGASATC2o6kEJGT0BH7BgIsoHAAZdRxb7XEPOQ3j/iz7vf8I+AgAAgMTNrxgEgMwspmaCrJMxoADqJvsAAIa4jqz1uY7sBvze+QFRRjvsIwAAAEjc/IpBAMjMYqpfR5zChK9d6vPa+0G2WAaAVF2n+snj9QivkWKNfQQAAACJm18xCAAspiYpTjpA+NQRPjAJ3/3yYPpmubqae1Zdny9Xt3JPjmotytUd/bz539Ltcm2W8UrFdeq8z/VkOeD33hogfQrsIwAAAEjc/IpBAMj8Yqo+5uup4OpOv1QIOt3AOMx972AqV64Wb5Wru83/NoblVvmwLgEkUcQ4JvIaNRtl56whOnfNsJ8AAAAgcXMsBgEg84upzTFeb6HPAunCr/bvkD1y5Wrh1tPDs1Fkj4f8OZf8YTwTd51aiar73xBdwyjiDAAAAMmcYzEIAJlYTPlSz8dpyV7rV2g16JbKkE5ulmu53LOj/UlkjwcnuecHi4xvYq5Tm32uLZWA33tlgPRZZx8BAABAIudYDAJA5hdTs33+nSJ6Vp1aF/3asddoyQ7jcvNJddmJzukhbw5P559WN5XyJYnTolwtqKaPk9bVT/4UGedEXKf6pVcVA37v/QHSh+sbAAAAJHOOxSAAZHoxddbn31wMWASdOTKJyB4YGyNynh5eeMkaFW6+/eVBfpjXUSFnRwB5y6Pm3zHesb5GTQ245uQDfO+ZAde6U/YRAAAAJHaexSAApH4xNd0vHavHv8n3+TcXdLEBP8g9r654CponRzWle43zmre/PJgxXb4QP0m7Ti32ueacB/zeawOkzyb7CAAAABI7z2IQADK9mCr1+Derg558O3WCaMcOY2Fq+HhH+Kz58vpPqss9Xr/A+MfyOlXqlz4a8HufDJDcQ3XturLVvNb+gI6FAAAAELN5FoMAkPrF1HqfBc1in3+Xc8TOVp9F0ZmzWEP+wNA4LdlPOmTMpaAp+vk+Sg1zp3vpz0oFYz/E7jq1G0URZac4fT/BvTXU6/zgyvKV71+5aFK/8voKxxcAAADEZ57FIABkejE1NcLrSACd93gdFUGdZrxhGHLlaiWsYsu3ywcL7oifm+XDY/ZD7K5Tp350GBzjfesDpE9+qNf5wZVpI3x+0Pw3P2h+F8QPAAAAxGWexSAApH4x1UvU1Md4rZk+XW7qiB8YhKJvPIRPoO24m69fIs0r1teo2QHiZTqg9y0NeN/dkV4P8QMAAABxnGsxCACpXkzlJk1b8HjNqT7pXogf6MutcnXXJV9OlO4V9Pvmnh3tu9K86uyP2FynCmF3znIE9tmAWj6zI78u4gcAAADiNtdiEABSvZgq9lnUFCd43UU63cCo9IjyKaT9vWHg9WSzz/WkEsF7itWxXxvxAwAAAHGaazEIAKleTFUmrVUxxmsP3e0GsoVapkcZbeOOMtKf2S+xuE4dj9phcML3W3SuU4F1C0P8AAAAQGzmWgwCQKoXU72KlJ778NoLRPvAKKiAckekzfPqSpjv3xXt8/TwIozUMuh7HZkaIGDyPr9frk+ds7HTujzfC/EDAAAAcZhvMQgAqV1MTQf6JPuyJkav1z9jH0A73/3yYNotXPSzsD9Hrnx42imeDhbZP5FepxYHCJgpH99rekCXML3fsq/fT+LnX12pIX4AAAAgsvkWgwCQ2sXUcp/FzbpP73EedscdSCZqyd4hW54c1aL4HPNPq5uuuj4b7J9Ir1PrQcrptveZGpBGJgKJPLvyg+Z7/+DKfkv8/MDf6CUAAACAvnMRBgEgk4upgk/vcRxWWgYkG8mVDtnyrLoe0ecodH6Oo332T6TXqVrQaaJOhM/+AOFTCvR7touf7185R/wAAABAaPMtBgEgtYup/aCjcAYs2FbYD2DJlauVKOv5WG6Wazlat8fmGjWonk/Bh/dYHtCaPXDh0/osl+JnxxE/F83/LnMcAAAAQOBzEAYBILULql6pV6c+vkc96BQySAdK54pDLR13baFbTw+pPxXdNWp5gIyZneC1pwd0L7Q1fEKXj1e+3/xcVvxsXSlyLAAAAECgcw8GASCVi6l8n4XOjo/v068oKosZaJErV0/aZcvtcm02ss/y9PCi/bOwfyK7Tu30uX6cjvmaKjC/OkR0j6T4QmTf3YofsXWFulIAAAAQ3LyDQQBI5WJqNYxUhgGLKlIXoIW7a1aU0udW+fAc6RP5NWpmQGrX7givpaie4oB003aU+joT+Rj84EqpJX4u076mODYAAADA9zkHgwCQygVVv7SGBZ/eY3rAwirPvgCLO73rdvkgkiiLue8dTLlbx7N/IrlG7Q64ftScYvTLTlt3seL8bN3597URRE/Dif6JlYxWXR+nsLPSvY7V4p3jAwAAAHydbzAI/qFaETfL1VV1pZkvV7fMIsdSru7o583/lqJ8wg2ZWVCd9KlhMeXTe6wMWGCxeIEW5hrY2Sq9EMXn0PW383McnrJ/Qr02DVNrx29OnejHWEbSXPnBlZzTyl0RP2dXtq4scqwAxPo6lm+T0cU2Gd3ORpuYnpT1Piy2EXkEIwDE9LrFIEyG89S4eKtc3XUtaPqijjESQBJFjCMEsKjqtfip+/g+Fb/rcUB6mX9a3Wy/BkqQR/E5VEC643r85KjG/gnt2rQfoug5d65RhUSMzQ+a123b0v2SdY4ZgFDnTZImhT7S5iJkWe3HNbD982+0fbei831n2f8ASB8YtHgoVwvq/DKK7PGQP6otUWI8wcfJS6HPJGDTx/c5p3MXjHC9LHVe+6q7kXyOy4jL9utwhf0TynVpNuAFzrGT8rUeZYFmH+TPWkv8KN3rX/LkHsCna9Ciky7aLnSOx7ne5PP5xp07dwz3799vPH78uItyudx48+aNb+j1vN7nwYMHrc8iJoiG1HhsOeOz4ozXNMcOANIns9ws13K5Z0f7k8geD06iamEMqZvYrPe5sa/49B6LQbVahhRfN13COxLp09U6vrrC/gnlujTtSkPwi9RJkSuvryy00r1U74e27gDDXmcW2tKthq75dePGjS6Bs7Gx0RIue3t7jb/7u79LHPv7+63v8Pr169Z3e/jwofm+c3Nzw0qhelu0UMm59lJ4HgDpk+KFy5Pqsrvzi7s+hJPGUDRpBJZytaAnzE5aVz/5w+QOJp309Jvk5Hx6j35Px0iXAW/h4urgFbbovv3lwYz7mkuKLcTyOq50r+9f2W1L91LqV46xATBzkFxbKtZunzqGhmvXrhnJsbS0ZKTH+vq6ESGSIkmUOX7z4cMHMx4SXRofyS+N1/Xr14eNELLRQYmNsgRA+kDbgqVaVKcXL1mjws3NBUV+qIWHColeCiBvedT8O8YbJpgM9cw79+n1CwMmAQX2A3hhCtxHmOLVXVfo8Jj9ArG+nm9dKbZ197pQrR9au0OG5jMzTlTJmlOjq2/kjo3WsalVb9++Rer4GDH04sWLVpTQ1atXB0UG7bZ1YJzleAZA+iRD+DyvrngKmidHNaUtjPOaeursXgQhfmDCCVK+z034YtL8bIXzOjfzXu+xw36AXihS0n2tG1aWT4qJ8umW9iX2C8T+uv4vmwvf7zcXvH+p9XOiVu+MDaRwDpNzOu1V+kXvKC3JRu1sb28TsRMRR0dHRgZpP9y7d68xPz/fTwSdOSJIAm+R4x0A6RO/hYpqUXhH+Kz5thDyfv0C4w8jTphKQUXhOMJnf8ANfZr9AP1wp7iGFe3jjvJREX51X2SfQGKu7z+4suwIn0v586+u1GjvDgmfsyw60SD7Xs0hbFrWo0ePTOoRkTvJQDWQXr16ZWTQgDQxWyeoQLt5AKRPpDgt2U86ZMyloCn6+T562u1O99KflQrGfoARJlCVIYrxTY/xuoOET4MnNzAMpr5ZyLXMbpcPFojygZSIn6krW81Fkk35Qv5AcuYnM87ifrNXXUBF8Cg9SzV3iN5JX1SQRJC6jfWJCDpx5rGK9spz3gAgfcJcoFTCWqB4LUyoOQEjTqpOh+zCkB/hNXNDdMBgAQ1D01XQvnndGzdNdhAq1OwuIE2UD6RA/kyb+j5u+UPaF8RrTrLsSJ6TXq3PFcWjzlIqJowcyQ4fP340qXk2GqhHjSBFf+04HdmIBAJA+gSDom88hE8lYMlUIs0LxpxcTQ/ZetOy26/TgvNUbnPAa5wT4QOj4p0ye3jqd30fI3yeHe1zTYUUy5+pJqUmZ22dvk6NEHpN8VQIfR4y60Rp7LqbSihV6+7du60iy4gPcKP0PRWLVn2gHilhdScdjC5hAEgf/1CtCddC4SSMp8PuRYqeirM/YIjJVmFE6dMubmouLoaMGGJRAeNd59QN0SVjTIqrT23cVbi5K6JInRafVjcZf0ip/FntqPlzWfS5bqQQAgiCmXdMtaVsdUXzKI1HkTzU4oFxu4ZJAkkWEgUEgPQJhB5RPoW0vzckevLVLypn5Yqa/14WW25MyLFzkyU9BiYVP93ps5cRQBMVyVdxfKVwuV9b6bKkdUHq7wVbVxav/KC5GGqXP1YAqR7Qa56Sw0RzjZzTNGLfq/CyojRUdJl0LfA7HUxpgKoJdOPGDaKAAJA+Pi1GnlXXo4y2cUcZhdXhBhI9EetVd+fU9XvLTqG88xFEz4Xzb/KMNQQufpzIylGjfoww907nMsJH6V6MOWTmnqC6P1tXikYAfb95De8UQBdNdk10EFFAMJzoWSeaBxISBXTmPOhc5PwFQPr0RQuEjkXD8+pKmO/fFe3z9PCCJ9TQZ0I21Scla2fARM62THWz7Pwdxx0EK35ckt1d60cpWSp0732truWcWmgnvV5D0pzrJ2RcACn9q3DlXzUXQu4UMFsHSH/3X15ZufIvSZWA3qJHBXeJ5oG4RgF51AI6dSLh85zXgPSBDi67vXQKlyieELs7zvhV6wJSOTnL01kLEi1+ytWiqenTU/50Rl4O83sOG4wvgOue8frKbFsU0LmnBLpMESuRDobosaJHLbe1wEY0QJxRoXAEEADSZ6jFR8ei4clRLYrPoafbLF5gyIlaqY/04eYGiUDFl/uke41G87rtdzcwgNTeQ35wJd9krcm+pwRSOthlS/h1tYVX6hjjhugBSLgA0nGf4zoASJ/sSp+NjsXDs+p6RJ+j0Pk5jvbZP9Bj0rbTpxYPaS2QLPlTPljw6J44tOyh8D3AxBIoZyKBvn+l0iMd7DIa6LIu0LpTPJp7TXLmDNNOa3VED2SGvb29xsOHD70KQes8WKMLGCB9sid9KlHW87E4tSpo3Q7DTOBOe0ifGuMDScVJtS0aAXQpczwLNDt/V1KkEOMGEIgEmjYRPur+pYgfd2Hov0QEnThpYWsSQYxd7OYKC05ThgtEDyCAPAWQHqIuc70ApE8WpI97cRFRLR13bSG1IGb/gMckbrZPahcpgQAAEIQIypnCzz+4sumkfjV6iKC6iRi67BRGfaDw5wieUT35fN4UY0b0QNZR57n79+8bAepK/yL6B5A+qZY+ri4wt8u12cg+y9PDi/bPwv4BjwldoY/0KTBGAAAQkgjKm7Swyy5hx31E0LGRRZfFpKmpEczcoCuq59q1a6a+idpds9gH6OTrr79urK+vN+bm5oj+AaRPNqRPZ9esKKWPu5sN+wc8JnabfaTPNGMEAACR3aNeX1kwUT6X9YHqPSTQuVMfaI1ooInmA55RPXfv3jXpWyzsASaO/tlQhD3XG0D6pEH6uNK7VFQ0is8x972DKXfrePYPeEzyjnsIn1PGBwAAYnffuiz8vObU/znzFEGd3cIoEt1/HpBzonr+aOcA6lb06NGjxtHREYt4AP+jf/aJ/gGkT9KlT7m64yoWWojicyjCqPNzHLKIB/dEb6o9dNtFhTECAIDY38teX5ltSws76ZMStk4kUMccYLHJbvu9X0WZt7e3WbADhBP9U29S5HoESJ8EMv+0utnZHaa6Gol8en6w6G5FzP4B14RvoU9q1ypjBAAAibu3XXYLK5huYV61gS7TwSpOIenMRQFpkeksNlu1ehTV8+HDBxbnACFE/5TLZRNN1zbnPnMKP09zDQekT0JQ69/OVunV3Ug+x7PquiviiMgNcE/8Sn2kT54xAkgOtkW9rv3z5eqWSTW2KAL18p5QirLOHECkEkiRQD+4cuoRCbQjAZTy+/20c88/s/d5tZt+8eIFHbgAIkId8Obn59vn3oq+36LuDyB9EsDNci3XKX0OzyORPl2t46upntDAWJPA3R7C55zxAUiG6FE0ae7Z0b5L8veleV+qGwH05QHtZCGLEihnUr3chaEVASQx9Do9Cy4tHp2GDb+z93gtMinMDBAflFKpgumuubjm6ItcswHpE2PcHbyUahXm+2si757ka3HAvgHXZPC0h/QhFRAg9veZavHW08OzUWRPF08PLxQBpML/jClk8j6oekA/uFLyqAW0r4LRCb6/551W0a17+9LSUuPNmzcssgFiyt7enqn745qTq+EKD+4B6RNHTGh9hCle3XWFDo/ZL+CaEM72Se1aZ4wA4sntLw/yuqZPJHvckT+X8qjA+EKm74uKALosBn3RIX+aP0+Y7GlF8aporBaR+/v7LKoBEoLqa6nOluptuVq+F7lWA9InRtx8Ul12T6o1UQ9pQTBjnt52vn+J/QKuieFKH+lDG0mAmN5blDLcR+CcNNkwtX1UzN9SrhZMTR932m83G4wzIH+uTF/5/pX//MrWld85aV8Xpij0D+JbZNUteyjODJB8VPRZdbdcRZ9VhL3AtRqQPjHBqZkQerSPO8pHT3AJ3QePCeJmH+kT24ktQGaFj2r39EnRGrZAs5P+W+qTGrbDPQMyfX9UV6/LaJ9NBxv1cxa3gs9esufx48dmsciiGSAdqNg68geQPjHFPFntnkwXg3zP2+WDBaJ8YISJ4qIHC4wPQOzuJ2uegubZ0f643bicbl8bvcQP4w6ZvT/+oHl/tBE+//LKjJP2VWvJn8suYJGKUa80rocPHyJ7ALInf2oUfAakT8S4o30kZNTdK4j3upzAdxaQJsoHACDhwucyPatLzCjyx4/X75MyVmL8IcPiZ98Inq2/1NBwIoDOHSFUb+/y1fz/UB6Y9JI9pHEBIH+QP4D0iQjTvr0r8ubw1O/6Pkb4eLfsLbAfAACSiVKx3GlYEjQSNT6/T74r3at571L0KPsBMip9Sk5kz6br57lWpy8JoK0riyYyyPl/ZA8ARCx/9nW94DoOSJ+QMQU13Z1S9FTVpzbuZlHgjihqoto+jD8AQHJRLbiuCB+fhY9FDym6I34OT4kWhYxKn2Unlavm8XdTTXYc8fPHJt84gsj3tMjmNtOk0l5378GDB8geABgkfySJZ7meA9InXPFT8Sy+Wa6uTTRJV1i+RzFOtfNlog4AkFwUfdNdw6e6HvC9qkCaF4DTwau9ro/YulJs/my9yapT5+d7bUWeW7/rk+yZarLW5Hd2EafW60dHRyxyAaCv/Glr9f7HJhs0aAGkT9Tix7bYHTHqxywGvNO5jPBRuhdjDgCQXLoiOJ8c1cJ43/lydYvacABtdX1sHZ9uTj1+NrEkbW7LTU6t7Ll7925jf3+fRS0ADIUKuiv9sy3q56zJKtd1QPqEJX6eVdd7iB8TRq+UrF41FEx9oHK1ZCRRj9dQKgCTcwCAZKMoTvf13e9acL0wLd3pAgmg4syzV75/5bhN/OyYSJ/vX6n0kEDi1xPInpxTj8Ms1Obm5hrb29ssYgFgLCSLJY1dbd4Xub4D0icM8VOuFnt0SvGQON21evqwwfgCAKTiPlFxC/0w318PINwRpOwXAGfyu3Vlo4/0ESPV3VLqRZNNuzBTaoZSNFi0AoAfSB5LIlPvB5A+IWOepPZO9xqNJ0e1sJ4AAwBAGNLn8LTjOu9T4f+R7lGuaB/9jH0DmZ/4XtbzafTl+1c+jiB8Vj/77LNv7GJMKRlKzWChCgB+41HvZ5N6P4D0CWNiXT5Y8OrOMqzsoSU7AEDK7guuAs6KDI1EPF3eY9rvO0X2D2Rc+CwPFD6WrSv3BsieRSfVgro9ABAaHvV+zpuUuMYD0icEVHj5Mu2ruusx0W6F1zt/V+KJKwBAOlFXR9f1v5LlzwEQiwnvZX2fi6Glz/evnPWQPdPtLdip2wMAUeBR7+e4yQLXe0D6AAAABIy7e9bNcjWSjhuKRI2iexhAbCe9l23cC1f+1ZWtK9+/cjKE/Cm4hE/RpnJRtwcA4oCk840bN9rlj1q80xQIkD4AAABB4U75VSevaKRPbdbdYZL9A9A2CVb0z9aVotPV68wj2kcdv6aaC6iZ9q5cS0tLjQ8fPrDgBIBY8PHjx8ajR4/axc9Jk2Wu84D0AQAACACTyhtBq3YvOqTP08ML9g9An0nxD67kmpSa/PWV71/5ZMTPwyvvnYKpjevXr5PKBQCx5e3bt+4uXxUKPQPSBwAAwHfR0tm5SxE3UX2WW08Pz9o/C/sHYMgJ8uMrT658v7lo+udN/q0rjfv379OVCwASEfVTLpcbn3/++SdH/JwpNZXrOtJnLGzh4tyz6rqpX6ACxZZydUc/NwWLI5zsAgAAhC5ayof1zpo+tVx0AqqzoQD7B2DAxPiKSefaMIul/+Qyzevh//Ehi0kASBQq9JzP59ujfpSiSiMhpM9wokcFKXPPjvZHaU3uTIDpWAUAAKmn6x75/GAxis+hey41fQBGEj7LTi0Ms0j6R//rf2Skz+f/8nPTJUeFm6nlAwBJQlE/V69eteLnd03WuN4jfXpPYtWO3BUmPjJPDy8UATT3vQMqigMAQDqlT7lacd3/ihFJn3xnxNHhMfsHwFP2dLRh19Pxvb09s2C6/l9cvyzqnL/8Oy2eHj58iPwBgMSg65VHe/cc13+kT8ek0V2UclIceVRgBwAAQOqkz2V6c+ueN/+0uhmRfCp2Rt1Wd9k/AF3CZ8FG90jo6Kl4+2Lp7vpdI33+7e/9241CodBaNNnfVf0MFpUAkAQ2NjYa165da4/6KXIfQPpcUZvZW+XD8z4C56TJhplYPj9YbFGuFsyk97K+Tz8BtMFOAACAVEmfy/tgx70yIumz4/ochHQDdAqfjfboHtXAcC+S/snqP2lc2bys7XP8zXGjXq93yB91ylHHHBaUAJDQqJ8dOnxlWPqY2j19UrSGLdDs1BQo9UkN2yHdCwAA0oLuaeZeGXEHL/dDmygLSgPETPbknPQGs+h59OhRz4gdUwj1f3opfQo/KTTsJkGUy+VaUT+q98OCEgCSgq5ZbbV+1OFrgftDxqSPngZ6CppnR/vjTlydbl8bvcQPOwMAANKCUqmiTPEyEbcUcQbwEj7FJn/UQuf69euNN2/e9FwUSQbp9679t641rv6XV434qf+23hI/FxcXjbW1tdYTc7V1ZzEJAEnBo8MXWThZkT4eYenOE8Lqqh9v2CdlrMQOAQCANNAVLfv08CLMDpbutvFR1RUCiJHsmXFaFpvFzb179xpff/11z8XQ69evWwshLYxKPy91Rfu0R/1MTU0hfgAgcSjK0QpuijxnRPpoQupOw5Kgkajx801VHLor3UsT4vIBYWUAAJB4lOLlvs+FJV66onxCFk4AMRQ+y076giliqmKmg2pefOc73zELoJcvXxqxc/aHs8bU9lRXtA/iBwDSgGqT3bhxw4qfC4o8p1j6uMPRTYSPz8LHotoC3RE/h6fU9wEAgDSgCNaumnjPDxaDfE+lYEclmwBiKHum3K3YvYo1u1EUkH5/YWHBpHDZbe1v1oz0yf8o3/DaED8AkGQU/ahrV1vUzy5FnlMmfRR9013Dp7oe8IS4QJoXAACkEa9oH/05qKgbvd/N8uExUT4ArWLNJ3bx8vjx46FTHWxxU3Xqat8u/nzRmHkzY8RP7Te1geJnfX2dhSQAJA6lt7a1dqfIc5qkjzv/X+3Ww/gA8+XqlntCTLQPAACkAc+HG837q5ob+C18mq9dCfvhDUBMhU+hye+0YFG6wigt1V+9emUWOurM5bVt1Dd61vax2+bmpnmNO3fusIAEgESiNFddwxzxo+L3q9xfEi59lMLlnigq8ieMD2Baurta2xLtAwAQPRITpiDxs+q6EfRPjmotytUd/VzX6yjakScJpVe577F60OLXuJnumJf7pKvjJuMPGRQ+Gza65+7du32LNXvx4MGDjlo+7s3W9hHnfzr3/p2zs1Z6xNHREQtIAEgsriLPO0qb5V6TUOnjfjqo2j5RTogVns7OAQAIHydipOhV460fTrRoye8IlrTgJWUU2Tpp3Tw9oOlK6XJq5LEvIGOyZ7pJbdR0Lje2nsXu7m7PSJ7F94sm2mfnVzs9f2d5edm8TrlcZuEIAIlP9/riiy8+OdfXOt29Eit9Dk87JosBF5r0mLR2RftQgwAAIGQxUa4WujorjohToL/EeHZyGTXlJWcuI3JGja7VPdKdHu2qG5Rn3CFDwiff5NR259re3h57caPoIL1OrVbrKXRe/uKlkT7FnxZ7/k6lUmkVj2bRCABJR/XK5ubmbMSP0mcL3H8SdJ90F3DWhD2SxUb3U9AiOwgAIHjUTVHiYRLZ48FJ2A8Q4o4TRbXTd8yeVddvlw8Weu0nk27nlcrV9hqk20HGhM+KU2/CCJZJ06lsDQt3Eef27fibYyN9Zn842/N3zs/PWwWdSfECgDSgdFnb3dBhg/tQQu6VzQnimmvCWIlE+sTkcwAAZEr4PKkuO9E5PSTC4amTgluUxGmhAsXPqutdTQC6KTLOrvudaiF117LrlzY3ZJRVdZeULsiQ7FE79i27+FAtHnXemnRRo8LPer3T09NGv226Mm3ET6+6PqR4AUBaefHiRbv4qdHWPQH3THd4uJ4iRvFB9GQziu5hAACZlQ8SOT3kg+4Nw6YIKbLEEUDe8ogOUp5jNmrdpL5iiKgqyJbwmWlyrAWH2qtvbGz4tpix0keROv02RflI+pz+/pQULwDIHG/evKGte5Lum+5J56RFJSeZALufLrODssPS+8bM4rtvdxb3Pu0vftXIMyYArnPkrxrTzfNj15wj7xsTF9DLPa+ueEqEJ0c1pRGNdR3vU2cG8dNrPxwsjptadyl7qiuMI2RM+Cx89tln39h27Ht7e74uZOzT60HbMNKHFC8ASDO6rklq09Y9AfdOd2HJKIs/dkxonx5esIOyg1nI7jUal3w6lwRiXAA6zpHjtnPkZJLXMjV8vCN81vz4rHp40OP1C+xLb0zbdds1rUfNHnO/vvy7EnV7IKPCp1W/Z2lpaeR27INQephee3p62hfpo21hYcG8pp6Ks0gEgLSh66bSa9vSvTa5X8Xw/unu3BXlRNLdNYYdlKUFrV3MOrz7lgsGgD0/vmoU3OfIuK/lFBM+cUt2v2vv6AGCO91Lf0ZWAMCYwmfNLioePnwY2FNrvf7s7Kxv0sc+BSfSBwDSjKvOz67qrnHvitE91F0kctywfj9wP9VkB2VY+ux9uiDaB8CeH5/qfkkfFckPq9iyqdXmivhRtAr7FABGFD4Vu5hYX18PbNGiVDFbg2fQNvNmxkifiz9f9JdDs7PmNf2OSgIAiBuvX782ddac6/UxBZ5jdB/tqiUQUTFI1YKgpg/Sh2gfANe54RHlM670UfSNh/AJtFOiUpFI8wKAMWXPdJN9W7B5e3s70AWLUrD0XouLiwOlj4TP1PbU4N9zPjsLQgDIApLn169ft+LntEmO+1kcpE/3U99iRNInz9NgpA/RPgB/YemgMeUV5TOu9PHoFnWidK+gv4f74YIiTNm/ADBA+Mw2qWvhoAWE3wWbJ5E+SumS9FGKV7/t7OysYQtOsxgEgKygdNb5+Xkrfn7XZJH7WtTS51l1vaNN79NqJNEVpnVwx6KgussOyrr0IdoHMn5efNUo9To3Rn2tHlE+hTC+R5TvDQCJFD5526FLC4ew6uEoNUHvWSgU+sqc42+OjfRZfN9fDp2cnNCyHQAyiVJa7969297Zq8j9LUrpo3axrie/EUmfnSC6yEDCpc/ep4vmwneWMYKs4UT5nPklfdyCP+xoG3eUEWIfAHoIn4Lt0HXnzp1Qa+FsbGyYBUqxWOwrcyq/rBjps3K40vf3arWaeT0tfFgEAkAWcXX22uA+F9G91XRycRXajKK7irvLS5QFpSFO0seIHxaHkL1zok+UzzjSx7T77qjfVl0J8/t0Rfs07zthpJYBQKKET8kuDu7fv29aAYe5OBlW+pR+XjLSZ6O+0ff3dnZ2zOtp0cPiDwCyiquz1w6dvSK4v14Kl84nsGGneCnMnyLOSJ++fNXIM06QFQZF+Ywqfb775cG0W7joZ2F/L13b49A4AABiKXy27KLg0aNHkS5MSqVSX5mzsLdgpM/+r/f7y6Hm6+j19Los/AAgy9DZKwbS52a5uupeEKibVlgfwt02Pqq6QhAn6eMuXku0D2TofOiK8vl0MYn0cddMyz05qkXxvXRtd6XxEuYLAK2W7FoQKNomqkXJ48ePzYLk5cuXfWWOunZJ+pz/6bzv7y0vL5vXU4FoFn0AkHVcnb3qiJ+QpY9C7G89PTyLQrx0RfmELJwgptLHq0010T6QATyjfN59uzmh9NnouM4+q65H8d26rvfPjvbZ5wCZlj1TTqh/KC3Z/ZA+9d/Wh+rcpW1mZsa8Xph1iQAA4owK86ujIeInAunjTMZLbvkSdOi9agdFJZsg3tLn8mdE+0AGzwWPKJ+l942ZCaVPJcp6PhbVaqN1OwC0CZ99Tfy/+OKLT1ELH2ELjm5ubg4s4lz4Sf8OX+fn5w3bbp6FHgBAT/Fz2mSW+2JI0scr2kd/DirqRu/XVViUKB+kT7v0IdoHMkavKJ9e58jQ0ufJUS0OtXTctYV0j2G/A2Rb+Fy7ds2E/MdhIWLTDo6Pj3vKnOJPi0b6bH7c7Ct99vf36dwFANBH/MzPzyN+wpY+ZmHQVVD5svaD3wU/Tccw95PnCFMOIJ7S5/Lnn2quqIdjxgtSex7sNtZdx/uZRNDE0qdcPYm6Q2Prs7i6RbLfATInfKadkP5YCR/V3dFnmp3tn7Y1XZk20ufk/KTv7ylaSK/38OFDFngAAB4o9dUlfujeHYb0ER6FNk0Ivl+LBPOk1/3UmdoOLHZ7SZ+vGnmvej+MGaSNyxQuV8HmrxqlQefIcNKns2tWlNKneT85R/oAIHwU2q8nvXFZfEjO6HOtra31FDm139SGrudjizhHWZgaACBh4ue8SZ77ZQjSxywQPKSMwvBvPqkuT/Jmt788yHeldDkt2qNoHwzxlz6Xf/dp193ZizGD1J0DXcWa/xLlM7H0cV3Tb5cPFqL4jk6UZ0dKL/seIDPCZ7bJSRyFj7CLjlqt1rsF+89LRvrov/22s7Mzu4BpfPjwgYUdAEAfPn78aFJhnevm7xA/IUkfCRhvOXMZkSN5M6LsmZkvV7e8Xs+pG8SORfr0lj5E+0DKGRTlM7H0KVd3XNfeSM4fRRi5hT/7HyAzwkeh+0auxK2blcSMPtv09HRfmaMIH0kfRfz027a2tszr3blzhwUdAMB44meZ+2fA0kc4T2R3PMXPJSeqwdPribG6tNwsV1c9U7naXiPKNANIhvS5/HuifSDFx/+AKJ9JpY87bVfX5ii+pwpIu2vGsf8BUi98cnEWPuLFixdmoVEsFnuKHNXwkfBRTZ+LP1/0lT6Li4vm9dbX11nMAQCMIH6Wlpas+LlA/IQgfVqT9GfVdXfhzV6o9s8wv3f5u9VdUrpgaOlDtA+klGGifCaVPs1rbsl9/Y1E+uh+0nkvqHAMAKRa+LQifPQEVxP6OC40hknt2qhvGOmzcrjSV/icnp6a17p69SqpXQAAY3D//n3ET9jSRygaR4uEYYXOQDEUUbtgSK70ufyd7mgfdzQEQOKO/SGifCaVPoq8dF2HzyORPl2t46srHAMACJ8o2d7eHqpr18LegpE+lV9W+v6eCjfTqh0AwDfxQ42fsKRPa8Ku0PxnR/vjyx4m+DC+9Bk2IgIgKYxyTE8ifcz129XBK2z5rtpu7vsC0Z4AqRU+0+0pXXEWPorI0edUi/We0Tu/PzXCZ2p7qnH+p/P+cmhhga5dAAA+0JbqhfgJU/pYTNv1crVoon961OwxhaAv/65E3R7wQ/qY3xsyKgIgEcf9CMfzpNLHXUw/7BSv7rpCh8ccAwCpFT71ONfwcQuffrV82lO7ln+8PFTXLr1uXL83AEBScBV3Vjv3HPfZEKUPQFTSh2gfSM0xb+pUdR3LhUnPkV7cfFJddsv5sDonmiif7tpwnLcAKRY+c3NzsRUfe3t7rZbqg4SPKcz8fnGo1C7btYvULgCAQMSPIkhnud8ifSDl0sf8LtE+kIpjfrSOdJNKH+Euth9WtI87yufW08MzdYjkOABIlfCZalLTxPzGjRuNo6Oj2KcMrKysDBQ+Z384Gzq16+XLl+Z1y+UyizUAAB/Fjy24j/hB+kBGpA/RPpD4432MbnR+SJ9cuVrwSMctBvldb5cPFojyAciE8NlPgvCxUT4zMzON8/PzgdJn62+3hkrt0ra6uko9HwCAAFDkqEv8zHD/RfpAiqWP+X2ifSDRx/toUT5+SR/hjvaRkFF3ryC+52X9t84C0kT5AKRX+Fy7dq2xv78f64WDjfKRmBlmGza1S1uhUDCv/ebNGxZpAADBih+lEk9zH0b6QIqljxPtc9bx7/762w3GEmJ/rI8R5eOn9DHt27sibw5P/a7vY4SPd7fHAscBQKqkT8UKH0XRxDk9wLYAnpqaMkWXB20Xf74waV2SPoNSu4wgWlw0rx/ncQAASDKKJFVEKeIH6QMZkD7O4rnkipa4kAxiPCHex/roUT5+Sh+hlC63jLlVPjz3q427Cjd3RRQ1UW0fjgGAVAmfLdut6u3bt7FdJOizqbC0Puv09HRjZ2dnqCif3dNdI3zyP8oP9fuzs7PmPT58+MDiDAAgHPFzrIhT7slIH0ip9FE6V1e0z7tvWVRCfI/zMaN8/JY+jvipdEXhXEYArU3yuuoSphQu92urRTtpXQCpEj5rVvio/Xlco3sePXrU6tSVz+cbJycnjWG30s9LRvq8/MXLwVFBFxcNG/HEogwAIHjxc/36dXt93+W+jPSBlEofZxFNtA8k6DgfL8onCOnTU/xccjJq1I/Sw3qkcxnho3QvjgGA1AifFStSXr16FbvFgOo+rK+vty8IGmtra0bMjLIpwkfSp/ab2sDflUzS+6jeBAsyAIDgUSqtHjw413ke/CN9IK3Sh2gfSMwx7hXl866xHKX0MeLnWXW9h/gxtX6UkqUOXF7/1tQHKldLRhL1eA21hSfCByBVwmexyR/j1ppcUT0qzqxoHit6xMLCQuP4+Lgx6qYaPrZVu2r7DNpUwFrvp0LRLMYAAMJBkaZt1/xV7tNIH0ih9HEW00T7QAKO8U/HruN0N6xzZKD4KVeLpqZPT/nTUfunPszvOVBcHSBdwifX5HeaXD948CA2k353VI9QUeVKpdIYd7P1fNS9a5jt5cuX5n0fPnzIQgwAIEQk/Nuu/8vcr5E+kELp40T7nLqifbYYV4jN8f1Vo+BRyycfF+kjVHy5T7rXaDw5qvndDQwAIhc+M01ONam+e/duLCb6ao1uCzTbmj0SPefn541Jt+JPi0b6bH7cHOr3c7mc+QxxrW8EAJBmHj9+bO8FF02YgyJ9IG3Sx69FNUBwx/en+iRRPmFIn5b8KR8sKCVrXNlDS3aAVAqfKac1rqlZo1SqKCf36o6lNCoreyRcdnd3G35usz+cNdKn/tv6wN9V+pgt4hz12AAAZJX79+/b+8JZk1nu30gfSJn08WthDeD7se2TkAxL+lhUePky7au668gczwLNzt+VFCnE/gZIrfTZ10RaLXLVMSVq4WNb9ar9usL6/d5sPZ/pyvRQv7+5uWk+jxYcLLwAAKJB0l2RqI74OWkyzT0c6QNpkz5E+0Asj21/ZGTY0gcAwBE+mzaKRZ1Sop7U2xbsSuU6OztrBLHZej7LP14e6vdXVlbMZ3rx4gULLwCACFH3RkWkOuKnpkhV7uVIH0iR9PFzgQ3gy3Hto4hE+gBABMKnpImzWuLGpVaNnczXarVGUFvp5yUjfV7+4uVI9Xzevn3LogsAIGLaI0Kb7HA/R/pA2qQP0T4Qq+PaPwmJ9AGAkIVPwdbMUQpVXJ7g6vNMTU01gtzUsUvSp/abwWLp4uKiVVuIej4AAPFgf3+/8cUXX3xyrs+Z7ybLxAZSJX38XmgDxEVAIn0AIEThk3M6oJiOKHGZxKtbl23HHtR28eeLxtT2lJE+qu0zbBFnRSCx0AIAiA+6Z3z++edW/BSQPgBpkj7vGwtdi+13jWXGGcI9pl3y8d23O3E5RwAA+gifKacApumQFacJfLlcNoJlbW0tMOlz/M2xET75H+Up4gwAkHDW19dtNObv9EAD6QOQEunjLLh3XdE+dcYZQjuev2qUXMffxdL7xkyczhEAgB7SZ1cT5Lm5OZNOFafJ+71798zkfWdnJzDps/lx00gf1fUZZisWixRxBgCIMW2t3E+yWtiZCQ6kU/p81ch7pNYUGGsImqWDxtTi3qczV5TPZtzOEQAAD+FTsp26VA8hbhN3W8S5Xq8HJn0KPykY6VP5ZWWo31cXMYo4AwDEF9Vba+volcnCzkxyIJXS5/I1ifaBCI7lAKJ8kD4AEILwWbQFiV+/fh3Libu6iOnzqXhyUNvMmxkjfU5/f0oRZwCAlHB0dNRe2LmE9AFIi/Qh2gdCJqgoH6QPAAQsfGY/++yzbzQZfvToUSwn7LZz1/T0dGDCR6JHwkfiZ6j6PxRxBgBIDHqgoWt28373Rz3oQPoApED6XL4u0T4Q4nEcUJQP0gcAAhQ+Ktx8rInw3bt3YztZ39vbM5P1hYWFwKTPzq92jPRRitcwW61WM5/pzp07LKgAABKAHmw40T5nTWYyc69nwgOplj4m2ufThauT1wpjDn4TZJQP0gcAApQ+W5oA37hxI3aFm72e0K6srAQmfVS8WdJHxZyRPgAA6UTXbEf8HGelsDMTHki19DGv3Vx4u6IvzrRAZ9zB1+MswCgfpA8ABCR8ipr4qlaOImniPEm3bXdLpVJg0kdt2iV91LZ9qHSw09OGFWYspAAAksGHDx/MddsRP5uZuN8z6YG0Sx8tvLuifZoLdMYdfDvGAo7yQfoAQADCZ8Gpa9B49epVYkLyNzY2AhE+F3++aExtTxn0/0gfAID0oo6Ln3/+uS3snPosECY+kHrpY16faB8I8vh911jrOr58jPJB+gCAz8JnusmpJrsPHz5MxAR9aWnJCJbd3d1ApE/tNzUT5bOwN3zNIKQPAEByefHihY32uWiSQ/oAJFz6EO0DQRHWsYX0AQAfpU8labVo5ubmzOT85OQkEOmjOj6SPqrrg/QBAMgG9+/ft+Knnub6Pkx+IBPSx7wH0T6Q4OMK6QMAPgkfU8fn2rVrjaOjo8RMzJ1JeWD1fFYOV4z0UQcvpA8AQDZQA4Ms1PdhAgSZkT5E+0CSjymkDwD4IHxmmySmjo9FckqfOZfLBV7Euf7b+kj/zsooFk8AAMnEVd9nEekDkGDpY96nu/bKhd+1VyBDx22I0WNIHwCYUPhMOe1pTTh7kibk29vbRqwsLy8HJn1UwFnSZ9gizkgfAID08PjxY3s9P2uSurUhEyHIlPQJo8sSZIOwI8eQPgAwofTZsKlIHz9+TNRkXB279NmLxWIgwufk/MQIn9zb0SOJkD4AAOlAde6ca/ou0gcg4QtaLcyJ9oGJj6OQa0QhfQBgAuGzqImswtcVxp60ifibN2/MRLxQKAQifXZPd430KfykgPQBAMgoSiX+4osvbJpXKVXzACZDkDXpQ7QPTHwMRVAfCukDAGMKnxknXL1RLpcTORHf29szYmVmZiYQ6bNR3zDSZ+1v1kZPC5uaMp8tadFTAADQzevXr1PZxp0JEWRO+pj3I9oHJjl+IugEh/QBgDGlz27S2rN7cf36dTMRr9VqsejcZbfZ2VnzuZLUCQ0AAHrT1sb9JC1t3JkQQSalD9E+MIEwnO2K8nnXWEnbOQIAqRA+Jdue/cOHD4mehD948MBMwldXV2PTuQvpAwCQPhS5OTc3l6o27kyKIJPSx7znu8aqO9pn8X0jNWF8ENSx+mnXddzU03qOAECihU/OtmdXuHrSJ+G2ro9SvM7OzmLRuQvpAwCQTpRW3NbGfRnpA5DgBa0W7K4FfOqqtYOPx8tXjbz7WG3+rID0AYCYCR+1Z68nsT17P2xnlZWVFd+Ej0SPhI/EzziblT77+/sslAAAUsSLFy9S08adyRFkW/o0F+wei/g8+wR6SMJIonyQPgAwovRZT2p79n4omubq1atmEr6zs+OL9Dn9/amRPrM/nB3r3y8uLprPo0gkFkkAAOmirY17BekDvpIrVwu5Z9V1w5OjWgfl6ob5efN35r53kIrCUlEvaIn2gSEFYWRRPkgfABhB+LTSutIoIh4+fOhrJy+kDwAADPOwIclpXkyQ4iJ6nh8s5srVyq3y4Xnzv42heHp40fzvTu55dSXp3z9S6UO0DwwnByOL8kH6AMAI0qeWtrSudmxtH3FxcTGx9Kn9pmakz+L7RaQPAAB00ZbmdZrUbl5MkCLmZrmWyz072h9a9PTm5OaTamLtY9QLWqJ9YIAYjDTKB+kDAEMKn1VNTNXe/Ouvv07tBHx+ft5MwDc3NyOXPqovpM+ysbHB4ggAIKXk8/lEd/OK7I2/++XB9M1ydVWpSvPl6pYrhWnHSWEq3S7XZtM4MdP3n39a3fRB9nTy7Gg/iWMWufQh2gf6S8FIo3yQPgAwhPCZafI7TUpfvXqV6sm3upHZFK9Jo312frVjpM/K4XjFoYvFItIHACDluLp5LSB9+qAaNLlytXirXN0dRWTcKh/WJYAkStIwMZOUUWROn++rFK9KkzWT9tVOcxwuZdHhab9/f7t8kKiDMQ4L2uZCfj/qhT3E8NiMQZQP0gcAhpA+u5qMLi0tZWIC7le0T+WXFSN9ij8tIn0AAKAnjx8/ttE+9aSleYX2Rio8fOvp4dkkUSyODCklW/gcLPSq2+PIsKEXk7e/PMg7csi73k+Cav3EQvrEZHEPcTs2P9VcMnA/q+cIAMRW+KxoIvrFF198+vDhQyYm3zbaZ2pqyrRLH3fb/LhppE/p56Wx/n2pVDKfo1wusygCAEgx6oZpHzioSybSpw0fa9Z01K9R1EvSJmUmUuey+HJ3JNME38fIn8u0OK+xKiJ9RlrgR57GAzE6LmOU9of0AYAewme6yZkmoevr65magN+9e9dMvhcWFsaWPi9/8dJIH/13rH//8qX5DHoCzKIIACDdvH371kqfC3XLRPpI+DypLvfvRnV46tS1KbpSmEzLcietq5/8SYTQMGKmXJvtEelU8av1ukkH84j4SUKqV2ykD9E+0CkBY1PgG+kDAD2kz5YmoCoymbXJt4pV21a6p6enSB8AAAichw8fWvFznHnpY0SOR1SLUOFmRacMK0scAeQtj5p/F/dBltS5WT489vj8a76P+/PqinvcJZua4z2D9Bl6oU+0D8SuuDfSBwA8hM+iJp4SH0pxyuLk+969e2byrTSrSaTP2t+sjfXvVctH769FAIshAID0ozSvGzduWPGzmlnpY8SDl6B5clRTutc4rylpYbp8JVD8ND/jRpif2URKeXT1QvoMvdgn2gdiFeWD9MkGalZgHphktKsljCx8ppqcZD3KZHt72068TdRN2IWcK5WKee/79++zGAIAyAhv3rxpT/OKdXBFINLH1PDxjvDxJapFKWM9Xj+Wi3LJqq7PG4KA6dEOPrbiIm4L2sV33+64FvwnSweNRFVph4nEX6yifJA+6RY9N8vV1VFr39mulnGP4oRApU9JE04VldRTxyxPvm20zTjiB+kDAADjoOu+c+/Zjf2cwc8Xc1qyn3R1kfK59o5Sw9zpXpdtyuP39NMtX5RqFVbreXdxZy0SkD7DsfS+MbO49+nCtegvsdDIiPSJWZQP0ied6N44aVdLc499Vl33qzYcJEb4zDhPF83TRibfneJna2srdOmjNDP2AwBAdlC3TFtXrkmsa+j6PYGthFVsWcWJ3RE0qpsTp8H1jPIJseW809I9EdE+cVzQLr77dtO18D8j2icDwieGUT5In3Sha3OPOm9j48ijWF7fIRDpU9Ekc2lpiYl3G+peZtu41+v1oaTN7umukT4rhytjSZ9arWbe886dO+wDAICM8eLFCyt9Yl0DNmjBUAn4KWkpzlLD3U1Lk/Kwn8beKld3O6N9qrEMP4vjgpZon4xKnxhG+SB90sPgrpYmWnajV1dLdwSnBxuMc+qFT94Wbz46OmLS3SPcfnFxcThp85uakT6L7xeRPgAAMBJJKeocmFzQxDUMweGugxCnFCaPyXnowqBLxj09vIhjGkBcF7RE+2RM+HzVKLr294XkH+cI+CJ8VLunT4rWsCnKJoq0eT/pkxq2Q7pXqqXPsSaXjx49YsLtgdq4X79+3UzAd3d3A5c+Jycn5r3m5uYYfwCADPL69Wsrfc7UZCG10ifKNKK4pjA5XVg6PldUNYdy5cPTjs/y/GAR6TMcRPtkB8k8Sb2Off3u203OEfDnOtwZ+dle2H/ce4Nzn9noJX4Y91QKn4ImlpIaWS/ePEy4/TDRPqe/P51I+pydnZn30pNexh4AIJvk83krfmKzdvBd+jhtZCOLtoljCpMJzY9JBJJHJ6/Yhf/HeUFLtE82kMyLa5QP0ifhwucyPatLzCjyx4/X75MyhqBOl/CZcp4imqLFTLL7h9sr/U21fS4uLoaSPrm3uca4my0gzdgDAGSTvb299hbuuVRKn66ClM+rK2F+iTimMHU9fX1WXY/wsxTCbhmfpgXt0l81puMcAQI+7OOYR/kgfZKLUrHcaVgSNBI1ft8Hu9K9mvdCNT1gP6RG+qzZFu1MsId/6jpMQWdJn6ntqbGlz+zsrHkvpZYx9gAA2STOLdwnfoGuNKbmJDOsluSdYiNeKUxdncxCFmGdUq6Wi3vr9rgvaOMeBQLp379In2TiUe+u4bfwab/Wd0f8HJ5S3ycVwqfVol1PE5lcD0adzTReKrQ8aJt5M2PEz/mfzseSPkoj03u9ffuWsQcAyCiuFu7LsZpH+CA3OtKYVLw4ii8StxSmriLOEUoot5jT02Ckz2gkIRIE0r1vkT7Jw7PmXMBRn12RnaR5pUX67GgSqaeITKxHe+JaqVQGSpv8j/JG+pycn4wlfVZXV817qWU8Yw8AkF3K5XKrhXucijr7McGMRRpT3FKYnLa7kRdxbn0edYdp+zwsaMf4jET7pJKk7FekT/JQVGUUD0Xmy9Utt+gn2ifRwqfVol1PEZlUD8fjx4/NxHtra2ugtCn8pGCkjzp5jbNtbm6a93r48CFjDwCQYVRTznaQbBKbh25+yI1YpDHFLYXJnW4WtfRxh/yzoB0don3SR5L2KdInWSiFq6uD45cH+TDe27R0d4l+on0SLX30tNA8PWRCPfrT1pcvXw6O1PnZqpE+lV9WxpI++/v7tG0HAACDq4V7LB4kTy43YpLGFLcUJve4RFlMU0943XWXWNCO+TmJ9kkVHvvzPK77E+mTLNwPRMLuKulOeVbDBfZLIoUPLdrHRB3ONHZKvRq0vfzFSyN99N9xNnUIm56eNu8nAcT4AwBkGzVdiFMLdz8mtrFJY4pTClPz/XdcT1kLUX0W7RN3YU8WtOPhRIacdn7ebyssTpKH5I4kT8e+/KoR22gIpE/SpE+0zQW8on30M/ZN4qSPifJ58eIFk+gRefPmjZlwr6ysDJQ2ivCR9FHEz7ib3oeILAAAcEX7XMQh2sf3iW2U0idOKUwehaUjW0xqsRGHYttpWdAuftUouD9v82d5FijJQmlcriifM0k9pA/4IFzy7hbtkVz73ZG45WqR/ZMo4UOUzwSoy5nGT521BqZn/XrfSB/V9hl3293dNe937do1ai8BAEDj7t27sYn28X1SGVUaU9xSmCR54lJYWsW1XRP/2EWmJG1Bu7j3qe4SBrtJWUhAK8rnIilRPkifZNG8xq7F4Zobl88BY0sfE+WjNCUmz6NzdHRkJtuzs7MDhU39t3UjfRb2FhqTbDbaRxN99gEAAA8f4hLt48ekMhZpTHFLYXIXlpaEiqp7SnfdpWiKbadK+hDtk2iSFuWD9EkW7u5ZN8vV1WjuiwcLcY/yhJ7CZ0UTRdUEYOI8HoqO0hhOTU0NlDVnfzgz0mfmzcxE0ufs7KwxMzNj3leh/ewHAIBss7S0FIton8knt13FIqOZ3MYxhamrpkMEQszUdXB1kFHRaxa0fnxmon2SSBKjfJA+yUJFmzvui0+qyzwMgRGEz5TT8QNxMCFKtdI4DrNNV6aN+JEAmmSzBaTv37/PPgAAINonFtE+PoiNzjSmsDuUtD5HDFOY3EIsirFJSgeXREofon0SSRKjfJA+yULX2Shatfe4R8e6cyN4Sp8SUT7+cOPGDTPZVgTOoG35x8tG+uye7k4kfer1unlPvTf7AAAA4hDt48PktjONKTYFK2OQwuQu5hn25N+re0uUBaXTuKAl2idZJDXKB+mTLGLV4ODp4VlcGhzAUMKHKB8fyefzZqJ9cnIyUNas/c3aRG3bO6KGnPbt7EMAAIhDtE8gE9xIWtPGNIXJHeYfZkHnrkij5uQ/qrpCqZU+7xsLHtE+BRYvMd1fCY3yQfoki1vlw3pnhGUtF52A6rw3sn9iL32I8vGRO3fumIl2rVYbKGp2frUzcQcvuxUKBTp5AQBAbKJ9/JELrqKVYacxxTmFySvaRx1VQpjoFzzeN7YRDUle0Cq6xyUS6ixe4odnlM+7xmpyjjOkT1KQ3I/yQUjvByLU9Im58CHKJ6BJttqpD9pOzk98KeasbWtry07uGw8fPmRfAABkHD0A+Pzzzz850T75REofFamMKo0pCSlMXdE+AS8ClEqgNLukRPkkXvp81cgT7YOc4xyBNulecV3zi3F46BDXmm7Qkj5E+fiMiilrTCuVSqjFnC8uLho7OzutaB91EmN/AABkGz0EcB4IhF4OxEex0RnOHla0TxJSmDwlTPPPaqcb0HvVw5RMLGiJ9kHMcY5Am/RxNRbQfSoi+VSMQ6MFGEr4TH/22WffEOUTrfRZ2Fsw0mf/1/sNP7aFhQXz/uroxf4AACDa5+rVq1b85BMpfXqkEwX6dFPSJCmFir2iocxn97HgtJ7quot2xj2tKzXSh2gfpBznCNj74fODRdc1+CQi6bMTdmoxjC19iPKJgfQp/bxkpM9GfcMX6aP31fvfvXuX/QEAAO3RPluJlD6iK8Lk6eFFUAUsVajZXUA67ilMHm3lLRuTFp7WZN5DgCXmyW4aFrRE+yDkOEdA6D7kvh5H0cHLHWEaZUFp6Ct8qOUTE+lT+WXFt2LO2tQqXu+vJ7ukeAEAgKu2T2idvHx9MdO+vUs8HJ76Xd/HCB93ocxLYr+Qk+DxEj8SVjfL1dVRpZUTYXXSQybtxFmCpU76GLnQ1Q68yKIGGcc5kj3ctdzCTvHqjr6liHOMpc+KxMDc3BwTYp+5d+/e0IWctdV/W/etmLPdcrmc+Qxq2cs+AQCAKDp5BTHRLHZHmxye+1VTRoWbvWrWRFUzYewx8ojKaaV8KST/eXXFK/pHEkepYuqY1iOVqxU9xII2gu+R4JbgqRQ+KUq7Q/okC0l897Vd96/wpFPnfTJJ98gMSp+6Jn8vXrxgMuwztmX78fHx0JJGwkfip/abmi/SZ2VlxXyGx48fs08AAMA8BHCkj6J8Q1knBiU1Kj1kxkT1BCQ7vESHOpIkJaKlNUam5kNnelovLkP0R/hdH+sEsaAdDc+24F81Sixsojqu0pNyh/RJFronue9XYYmXriifkIUTjCR8ljXxu379Ouk/AaBx1fgqzWrYbfVnq0b6rP3Nmi/SR1FGtovX0dER+wUAAEytN0f8hLJODHLSWekhJk5GjfoxbWe907mM8Jm0Hk6UiwKJMHfdhXFR9E9SJ/ZpWtAS7ROT/ZCy4tpIn+ShIvrdxfuD7aRoOjhGJJtgLOmzq0lfuVxmEuwzkmga26mpqZEkjSJ8JH1mfzjrW4pXsVg0n+XGjRuN/f199g8AQMZRDT9H+oSSfh/shLd34WJTX0AT0V5ty019oMsJ80nvqJbqbtIifHpIrRmNxYB0rT5RQNWK33WTWNCOD9E+cTmmuqJ8apwjELbYd1/X9eeg5LxJ/y0fHhPlkxjhk7dFflXYkUmwv0iuaHzz+fzIksameB1/c+yL9Lm4uGi1b1fEz5s3b9hHAAAZRx07HfET+EPpMJ50FoeNZPGq1ZOWmjVDj9fzg0VF7OSeHNW8UrrMWJq/M5FUiY1aSPuClmifiMf/q0bBI8oHMQrhX9O7Cio3aV7D/Y5QdSJHuyNsn1XX2Q+xlT4VTfbUvpXJr/9sb2+byXShMHonLtu6Xalefm3n5+eN5eVlO8FvPHr0iJQ+AIAM8+rVK3tPCLz8RCgTGz1l7JPuNRrNyXLSo1og/Qtaon2iPp4+1V3SbZdzBKJCkZxeDzn8auNuOlpePgxwCZ+jfcY/tsJn5rPPPvujJnvUeQkGFcbW+JZKpZEFzenvT430mdqeapz94azh57a2ttYSP0r32tjYYH8BAGQQiX9be67JQuKlT0v+lA8W3G1sR5E9aYpsgfQvaBffNdZc4uFCMoj9HfC4pzDKB+mTfLykjFK91KBgwocq+a6ULieFOqn17jIifTY1yVPb1jAnmFkSTIqg0hhvbW2NJWcKPykY8bNR32j4vSn1bHZ2FvkDAMADCnsvCPQBdSSTHfNU0qR9VXc9n046BZqdvytRjwDpk0SUzqW0ro7v9u5bCqoGfiylL8oH6ZN8dN/zljOXETmjRrCaWnBKBfZKlb6sG5R40Zli4TP12WeffaNJntq2Bj2h1HuoXfjc3FxLMqiVuX4WxvtHha2VIMEyzqZ6PpI+qu9z8eeLRhBbpVLpkD+qP/T111+zEAIAyFC0zxdffPHJuQ/kUiV9ALKyoFVKF9E+oY53KqN8kD7pwKm7s9MnqvVENXj6NTi4Wa6u9npYYl/Dr7QxCEz6lKx4CSKSRzJHry1UJNoKhV5INLx9+zZVk2jbFUWdu1RLZ9wt/6O8ET8vf/GyEeQm+TMzM2M+s2QV4gcAIDvYyFRFASN9AOmTQIj2Cfs4SmeUD9InXZjOlmrf7nODA0XPktKVCOlzosmdxITfET3qDOWWOrlcrrG6utqKeFEnKf2/at1Y0SA5tL6+nroon3Hq+XhF+6i2j+r8BLmdnp62on4QPwAA2UEdPD///HNF+1w0CWQexwQMWNAG/d2I9glrnFMb5YP0SR+Kxhm7xp2XGHp+sMi4JkL4LNoaLn5PGm36lrpV7ezsNOr1+lCtxCVGrCBKQ10ZG+UjoaXvN+lW/GnRiB/V+Al6c4sfinwDAGQD1fhz7sUlpA8gfRII0T5hHUPpjfJB+qQXyRrV9Blf9lRXGMdESZ8dTerK5bKvk0XJAb3u9PT0WLJBxY717xUppCeOSZ44K11N36VYLPoiYtS9a7oybcTP7uluqOJHXV3SlnoHAADdbG9vB9q+nUkYsKAN4/u9a6y6o30W3zdy7Hvfxnela3y/asxyjkBSGLnBAXV7kih8Zpr8UalUfosVRejYKJ9xt+Xl5UZQtYbCxKZ2vXzpXx2erb/dMtJn9oezgRV1bt9Uh2hhYaEVgXXv3r1UF90GAIC/M1HAQbVvZyIGLGhD+47pjkSJiqxEUiF9ABIvfUpBtWm/f/++mShubm6OH9FydmYihfQ6er0kTpjVBcUWr1bEjJ9bWEWd21PvJK5UjLq9tbuOnzTVXwIAgEvUiMG53leQPoD0Sep3THnNmQjHNRM1k5A+AImXPqaAs0K4/Z4oKjpHr12r1SYSDSrwbCVDEsXPq1evzGdXlIzfW/239dCKOrdvJycnJlXNCjmL9jnFngEA0oOigJ1rvO8FnZmIAQvaUL8n0T5+kqV6SUgfgEQLn4WgCjgLW8fm+Ph4YsnQLn7URjZJE2ab2jVJxFO/rfTzkhE/ivoJI82rSzzV66ZIt+26Rs0fAIB0EVRBZyZjwII2zO9JtI/f45mZzmhIH4BES59KEAWcLbYOgF8pTe3ix+/W8kHhd9cuz5SrP180cm9zRvysHK40otpU82dxcbEV9fPo0SOifgAAUoC9lyk6GOkDLGgT/V2J9vGDrHVFQ/oAJFb4TAdVwDko6aNN0TJJ6ugVdJRPK93q/MSkeEn8bH4M9r0GbbaAt436efHihalrxMIJACCZ6Bqu67lzbV9E+gAL2qR+V6J9/BrHzET5IH0AEi19AivgHKT00aZuYHrdBw8eZD7Kp31T63ZJH1H5ZSVS8aOUPpve1y5/iPwBAEgmit50ruk7SB9gQZvo7/tp3yUs6hwHw5O1KB+kD0CipU89qALOQUsfdfSyaV5x7RglufGd73zHfMatra3QZIu6eMVF/GhTrZ9cLteSP4osU6t3Fbcm+gcAIDkoxbqtoLMvD7SZkAEL2ii+71eNvEe0T4FjYejxy1SUD9IHILHCJx9kAeegpY+2SqXSEgmKIInb5Ni2q1eNm7C3dvGz86udyMWPNi0WlpeXOzp9IYAAAJKF7crpV0FnJmXAgjay7/xpl2if0ZHc6Y7yaaxxjgBADKXPVpAFnMOQPtpsfR+hVCLVkjk6Oop8Umxr2igaKajvPor4ibrGT/um8dB+a0/9sijVUGNHChgAQDyRpPezoDOTMmBBG9V3JtpnvHF79+2mS5adKd2LcwQAYiZ8ppr8TpO2oAshBy19tNVqtcb09HSHPNCkNGrhE3Zal9e2Ud9oiZ/Vn63GRvwMI4D0M9WPUPohUUAAAPFA12M1UnCu1QtIH2BBm+jvTbTPKDhRPhcuUVbiHAGAGEqfgiZrCtEOenIYhvTRpiLJSvdaWVlpFQ2OQhS0C5+XL1/GQqwovct29Vp8v9g4+8NZ7OTPIAEk7t69a+o3JaFjGwBAmrHpy002kD7AgjbJ35ton9HGK6NRPkgfgERKn52wCiDPzc2ZiWG9Xg9NHtjOXmFIrfYnn21dTWIjfOxW/229MfNmxogf/Xf/1/uxFD92Oz8/NzWA1tbWGgsLC10CSPsWAQQAEA2KwHSux6dIH2BBm3yRseMSGSdZERmjkOUoH6QPQOKEz5TTdSOUBbOK9IYtQRQxYtO9JJ0UfRPkd3z79m1jfn4+tsKnJVL+dN5Y/vFyK91r7W/WGhd/vojlZ3Vv6tamSC6vQtB64qx0PgQQAEB4DzoUUetHiheTM2BBi8xIihzLbJQP0gcgcdJnJcwoGFvwUS27w9xU52d2drYlBzQ5ffjwoRFAe3t7E30nRaC8efPGvJ5NXxMzMzPm7+K+qaizTffKvc3FPurHSwCpVpKN6HJLIB3b2jcqUq79xAINAMB/Hjx4YK+9m0gfYEGL0ECMcY4AQHykz25YqV32aaAW4mGneNlN0SG9asRI2EgQCE1eHz9+3IXkgf2dtqeaHUj2lEolk5KUlE3pXhI+Nupn5XAltrV+Bgkg1QFaXFw0ndK89o8KjhINBADgL5LqznX2DOkDLGiRGkgxzhEAiIfwmQ4ztcsicaL3VGpOVNvx8bGJ8lGhZ0UdecmBYVGNGUkG1ZtRRFFSN6V2qbuXjfqZrkybPycl5avXpn0iESQR12tfS+C1yz7Vp1CaHgs5AIDhaXsYsoj0ARa0iA2EGOcIAEQvfYphFzgWEkw22keiJDbS4+LCCAKLpJDq8bSjdC3792ndTn9/2lHrR4Wet/52KzXf7+TkxOxbibpeUV/tqA7U0tKS" - + - "kUF6kq3j9+uvvzb/387R0RGLPgDING0pXltIH2BBi9xI6bHxbYW29pwjAAmSPvthpna109bpw9RiUVoOW7y23dPdRv5H+Zb8mf3hrPlZGjcr/JT+J7mnY9KrS9iktKcQeiG5RBcyAEgqipCcNMWLCRqwoI3TOBDt0zketLTnHAFIlvCZafLHsFO73OJH9VX0GdRdS1E/iqTRApwtPlvllxUjfNrljyJ/1P0rC5sig3Z3d83xqeigXrQXCveDu3fvmugi1R6iADUAJIW2hgaLSB9gQZtwJHgkejrG4923m9k9Lj7tEuXDOQKQIOmzGkVql1eqlxa3XnVykEDxlj+q/VP8abFxcn7C4Ay5nZ6edqQQuunVhcxde+jRo0cmRQ0ZBABxQ9enSVK8mKQBC9q4jcVXjZJLdFwo9SuD40CUD+cIQNKkTy2q1K5eIeGaKPaqsaKfK+1Gi2a2aLedX+00Ft8vtuSPWNhbMNE/Sez4FcdNnd8kPHXMF4vFvt3IbN2he/fumfNZ/46FJwAkNcWLSRqwoI0ZRPvYY4IoH84RgEQJnxm7WIxj7RC1dVfqVy8JpJ+trq6aBbFqsChCgppA4W+K8FGkj+32ZSn8pGCigrKS/hW2DLJFxnUOSAb1igiSBFJ6mMWmiQmdYyxOASCOKV5M1IAFbRzHI+PRPkT5cI4AJFD6rNqaIUmYPGqBqgWrFrGD6qCoJbetsWLFkFDL7vY0GjYfRcSfzk2Ujzv6xwogRQYhgAIWcCcnRoAqKmjU2kKKElLKmO1OxoIVAHxM8Ro5GICJGrCgjSFZj/YhyodzBCCB0mdXk7EXL14kbiJpW2VLAmmRqvawWrBq4TpuwVxFDkkSlUqljrbsbKNvSu/qJYCUArb5cZMaQCFKICs9xcrKSkuIDupMpnNC55UtJi2UOkakEAAMg64TzvXkFOkDLGjTMiYZjfYhyodzBCCBwmeqybkmY2ms/aF0NbswldSyC9aHDx92tMZuCz0fuPhV9ISNFGLzRwCpIPTqz1Yb+7/eZ6Ai3pQypu5kkp7jtKm351R7OhlyCABsd84ms0gfYEGbApxon5POsfm2kv5jgSgfzhGAxEmfRU3CJD2YlF5ydHRkFqiKZNCCdWlpqWdBaSuCtEDWQplaQkOKhT+dmzQv1QCarkx3SaDlHy83NuobjeNvjhmsGGztqZDt0ULqLKZIoX7nRz8x1B451C6HRBzriwHA+Ohe6lwDSkgfYEGblnH5qlHwiHrJp/b7vmssZ+n7co4ApEb6bGgSprQoJqWDURcSySCNV6+F7vLyskmlobX88JvkTunnpUbuba5LAEkKqRaQooRIBYv/1t6G3p1KNk66pRaKKlStVE539J4bCVuuUwDxROexc17vIn2ABW2qxuZT3RX5sst35RxhTABiJX3qmoS9fv2aSekEtQrK5bKJWrh69WprsaqW2mtra8ifETelgdkoIKV9uSXQzJsZ83fqCHb6+1MGLOFiqL3WkCLmbJ2hUaOHehWkFioiq0giXeeIIgKILorWOT8vlFqO9AEWtGkZm4xE+2QtqolzZDi+++XB9M1ydTX3rLo+X65u5Z4c1VqUqzv6efO/pdvl2izHCUQkfEyrdokKam34g6IR9DRTC832DmL1ep2V/riC4PenJspn5XDFMxVM0UGqB0RXsPRtSpfc2trqiBJSNzIrhtyMUoNofn7eyKA01jIDiCs670Zt3c6EDVjQJmJ80h8BQ5QP54hl7nsHU7lytXirXN1t/rcxLLfKh3UJIIkijhkIUfoUbX0NJqPBpILZaIXp6WnEj09b/bd10/VLdX+mtqe6JFD+R/nG2t+sURSarSuaaHV11TPNTOepZC0RQADB0ta6fQPpAyxo0zQ+KY+CIcqHc8SSK1cLt54eno0iezzkz7nkD8cNhCR9Kpp8KTWJyWgwKIJKaV8a55mZGVK9AthUD+jlL156dgVrLwotWcTGpk3noQqvSwJJyHpFALXXEQIAf2hr3T50sxsmbMCCNjFjlN5IGKJ8OEdulmu53LOj/UlkjwcnuecHixw/ELD0Ma3a9/b2mIwGLH5sSLtSVdgCXMz/+cJE+KgotCJ+vIpCK01M9YBUO4iNTdvOzo4pNq06XF6FpF+9esW1DMCn++EXX3zxaZTW7UzYgAVtUsboq0beIxqmkILvRZRPxs+Rm0+qy050Tg95c3g6/7S6qZQvSZwW5WpBNX2ctK5+8qfIMQQBCZ8FWrWHhxaNGm8tLNnC2wYVhbapYLSGZ7ObIoCKxaKJzGuXP4rYI/0LYHLaWrcPNcdl0gYsaBM1Tp92XREx9RR8J6J8MnyOGJHz9PDCS9aocPPtLw+GEoAq5OwIIG951Pw7jiMIQPqsa9J1//59JqEhoGKxtnYIW3SbWr6rHtDC3oJnVzBFCJEGxmY3dRlTmpdNAbt27RpRPwATsr6+bqXPDtJnuAWHeVJsaO8Kc9kZZsPpDFNQYVEmuCxoIx+nlEX7dEf5fLogyic750jueXXFU9A0r79K9xrnNW9/eTBjunwhfiAc6VOjVXt4qDaI7TzEFo9Nnb5sFJCEj7sjmOoA0RKeTdvJyUlHZzDJcur9AIxHW+v2c6RPz4WGSQuo9E8ncHH5JHpHixQmuixoox2rdET7LB00ppqf/azju7z7dpN9nI1zxNTw8Y7wWfPl9Z9Ul3u8fmIlKcRO+EzbVu0sXMJDY66aIWzx3Gq/qZnW724BpELQqgGkekFs2d4U9WPr/ly/ft0UwaflO8DozM3NWfEz8IF5piZoPhYKPdGCgkkvC9pIxiol0T7Nz1xyR/ksvW/MsI/Tf444LdlPPMR60c/3UWqYW+7rz0oF45gCH6TPsu1Sw+QzPJQaonFnS44AUuHn9iLQ+plSxNiyuynqx932XQtYoiYBhufhw4f2/CkhfZp898uDaacIaMNXnh3ts3hgQRvNeCU72ocon2yfI4q0DKvY8u3ywYI74udm+fCYYwp8kD6mno8mXUw+w0NFszXuqhPCloxN0T2K8nHXAFL0z+7pLgOU4a1Wq3V1/FIkENc6gMHoXHHOm4H1UFM/KTPFPd1PlF1PfZ0FyFpHV5jLFLDSpSw6PO3377WoYALMgjbU8XrfyJn6Nx3SpLGamM9PlE9mzxFF33hcSysBS6YSaV4QgPShnk8E2LbtihRgS96mCB939I86gqkwtOoDsWV3W1tbQ/wAjMAodX1SLnwOFnrV7blVru6OMul3FiqVnvV+qPXDgjbsMXv37aZLnJwpgibun5son2yfI861tyNdNoxC+e7UXrV557iCCYTPVJMLTbao5xMud+7cMZNcRQiwJXeT4Nn6262OFvASQWr9rhbxbNncXr582RI/qvXDNQ9guOjXJrlMSh8TqeNRxFMTff3dRE+pLzt7NcJKT2BBC57y5H1jpiva56tGKfb7miifzJ4jPaJ8Cml/b0il9MnbGhRMOsNlaWnJTHBV+JUtHdv+r/cbi+8XW/JnanvKtH1H/iB+8vm8iWbg2gfgjbrgOedLMXPSRyldt54ennmlEPj1RNmkg3lE/JDqhfQJddwSFu1DlE+2zxG1TI8y2sYdZaQ/c2zBmNKnZFsOM+mMZoJbqVRYHadsO/7muFH4SaEj8uflL17S8SuDm6TuzMyMOddVvH1vb4/rH4AH6+vrVvpUMiV9JHVUpDOoNsAdC5jn1RV3NJFk0+0vD4haQPqEI1ESFu1DlE+2z5Gua3PIabFd0T7N63cYqWWQSumzS92JaLDdSjY3N1kZp1j+tEf+5H+Uj3W3L6Uaiq2tLROlUiqVTGcqSy6X6+hS5UX771tU40avJyQ57ftkJbXx/PzcFHnW+CiFhVRagG4kRJ3ryGmmpE9zIr/R3WWruh7g+xW8unoxKUb6hDZ2CYn28Yzy2W2ssw+zcY6oi6JbuOhn4d8jXIX5J0j3hUxLn3NNskg7CJ/Hjx+bCa4Wwmzp3pT2NfNmppXypWLPcRI97pbjYaNImNXV1cbx8XGqjwM7znRKBPBG0XDOdWE6E9JHETZddXxCEDA92sEXmBgjfUKRKV7RPu8aa7HbxwktPM054psgL3ZcI58c1aL4HB7X6w2OLxhR+MzaJ89MNpE+bMFuKvis1u7tbd6jrvWjKDMrXrTYUnFx8ejRI3N8vnjxovHmzZsWSlUadFwriqX934jt7W3zehbVs7Lvdf369a5IobTWuVKnPtvSHdEO0I2tddekkAnp457MK9UqrCfJ7uLOdIZB+oQ6fjFPm0pq0WnOEV+lz0ZYEZgDPkeByEyYUPoUNbnSJIvJZvhoQe239Lm4uOhInbHU63WsS0y2yi8rJtrHtng//f1pJJ+jWCy2RIsiT6JMOVJahz5D21P+VvRP2lLA7LiTUgvQ+77YZDP10sczyqdcLYX4/nSGQfpEJ1ViXiCZKB/OERXSj7Kej+VmuZZD0MOE0qeiyZUmWUw2w0eLPo2/FoHjbloQa2E8TK2V5eXlxtkZXaTisKmuj+r7WPGjKKAoxMPVq1cbr169is05IfGkSKC21s0dAkgRQKqPk+RNNY0ong/gjSIDnfO+nnrp4+6mpSifsAt00hkG6RPpGMY02ocoH84Rc412RUNGVUvHXVtI9wqOLxhR+pxqckU3mWRKHxXbdYud9hSddmwExfT0NN3CYrJJ9Fjxo/+GJX4kT6zwUdpVXM8PG/3jFkBWAkliKkouaZFAp6enDdJqAbz5+PGjuTY1z5GLJlPplj7uBUWIUT4WOsMgfSKVKzGN9iHKh3PEEfMn7dfH2+XabGSfxRUVyvEFIwifaSsJmGgmU/rk83nz7x88eNB4+/Zt3/f68OFD4+7du61Fs7oyscVAAPz+1ET6hCV+bJRJ3IWPG0X4KAJIAtNZEHpGAiVFAM3OzjYQ7gDe6Dx3zu3F1Eqfrq4wES4o6AyD9Il0HGMW7UOUD+dIr2tjlNLnVvnwHOkDY0qfZU2qJAKYZEaDFt2TSB8tdPXv9WR02PdUKo9dNE+SVsYWjPhRe/fA3uf01ER6ad+Xy+VEnzuSQDqWJTzdhaCTIIAkXfVZVTCbayFAJzovnPN5LbXSx90VJsoaDXSGQfpESdyifYjy4RxpXadd0Zi3ywcLUXwORV+6IzI5vmAE6bNG6+BosbULxpUvNmJj1PdVVJBN91K0EVs8xI9t6b7zq51A3mNhYcHscz1FT+O55JUKZgVQ3GpZqbA6KV4AvR9OOOfwTpqlTyy6wjifhc4wSJ9ox/KrRtEd7dP8WT50AUWUD+dI57VxJw6F7hVh1Pk5Dk85vmAE6bNDB5l4SB+1qB51U+vnSRaNem8b8XN8fIx1icGmrl6SPpI/fqd5KTLGpnMq1S/N55VXLSBFOO3s7MRqf9vW7VwLAbrP4X7FnNMifWLRFUbQGQbpE4/x/FR3iZ/Qi4ovvvt2y/UZTojyye454o6CvFmurkZyv3h+sNhxv3hyVOP4ghGkT52aEsmVPipgO2kHINVI0Wuo85davbNFvym9S+Jn7W/WfH1d260ra+lEur6117JaWVlp7O7uRr6fdb5RUw3Am/ZizumVPjHpCiPoDIP0icV4ftUouMc0zGgfvZfH+xfYN9k9R1RcPw7dDRUJ6oo4qnB8wQjS52LUejAQH+ljW7RPUoxX+35+ft68ztraWuQLYbZGY//X+6027n5utv7ToILfaUURjTal0Ub+SIRFIYDUct5KuKWlJa6FAB7Ye1OTfDqlT4y6wpjPQ2cYpE8sxjS6aB+9l+u9iXjL+DniEQV5Ho+HBNFFhkLihE9Ok6m5uTkmlxHy+vXrsWr62JbPWsROKu0kAfRaSjWJW92TLG4Xf75o1fap/abmy2va+jEqeJzl8+3o6Miz7k8YAkjpmJubm6bNvH1fRTIQaQngzb179+y5spJS6ROfrjCCzjBIn1iMaUTRPkT5cI4Me60OOyrz9pcHM+5Oj4rO5PiCIaXPiiZTmlQxuYw2+mCc9ulanPoZJaDXIdonPtvqz1aN9Nmo+1NkW7Jh0lTAtCHZovRGiW+3AFIK2NbWlhE1k2yK6FEapm3P3o7OOYQPQG/UYdA5XzbSKX1i0hVG0BkG6ROvcQ0/2ocoH86RXsyXq1tRpnh11xU6PObYghGkz0Ya2jYnHVtTZ9QOWupGpH/34sULXz6HTTPL5/MYlxhsu6e7RvoUflLw5fUKhUKDou29UZFrLwFku38p/VIiSALHoqLQaglvUTSVW/ZIINnXUVSeJLv2wddff824A/zdcJGwTXbTKX1i0hXGPEmmMwzSJ07j6hXt876xEOD7EeXDOdKTm0+qy+5Im9tfHuRDuTYryseVeqs6QxxbMIL02dVkSpMqJpfR8eDBAzOprVQqIy3ibeSAX5ECbUUzTeoYW7TbyfmJkT65tzlfXs/KB6U3cd4NFkDr6+tG0HhJoFFRXRKuswCjoy6Dznl0mkrp4356G+VEns4wSJ/4jW14kTdE+XCODEIdDaOI9nHfJ1RkX5GZHFswgvQ50WRKCxwml9Fh06oUKTDspt8Noj6L7XCktBa26LfpyrQRP6rxM+lmBQTn3OgoKkeRcCqYrmggi6TQnTt3OmiXRMgegMlpK74+nTrp4+4Kk3t2tB/ZZ6EzDNInbmMbUvQNUT6cI0NerwvuaJ8mxSDfUym/RPnAhMJnmlbB8cB2JxmldohN1fE7Nc/WFxqnkxib/1v+R3kjfeq/rSN9ACCTKOXYuX4tpE76uLvCaHIf1RNcOsMgfeI5vsFH4BDlwzkyLO5oH12zdR0P4r1UqNldQJooHxhD+izY+i1MKuPxFFM1QIbZjo+PW11/FPrudyi9/Tyjppux+b+pno+kj+r7IH0AIIvYFOgmq6mTPpdPj11dYSKo60NnGBa0sR3fgKNwVCcozNpBnCPJPkeMqO+KvDk89bu+jxE+z472PSKLChxTMKL0WdUkSpMpJpXRoTo6tlX60NEfzlNPtZ0O4jPZaB8Vr6V9e7Tb2t+sGemz+XET6QMAmUT1tZzr12YqpU9XvYaQu8J4fQY6wyB94jXGwUXiRNEljHMk6aK+WnTLmFvlw3O/2rhLwndFFDXRdZrjCcaQPpt+dn6C8VA9Je2HXG64Yr3ttXwkjIL6XLa2jzqEsUW3bf3tlpE+at+O9AGALPL27Vt7/TpOpfTRE+KousLYBQY1I1jQxnqMA4r28ewQ1nwvxpxzZAjxU+mKwrm8jq5N8rrqEqYULvdrS8ST1gVjSp99TaJUnJRJZXTYNunD1tAplUqB1PLpJaPU8eni4iLubiSUTePQ3p47jA5n+7/eN9Jn+cfLE7+WIre0T/1OCQQACBIVUnekz1kqpY9QdE9UBZ3pDMOCNhnj/G3FFZFzunTQmJrsNYny4RzxWfxccjJq1I+R/97pXEb4kG4LE0ifE9o3J0/6KCJIv68nn0F/NtuFSAIoC0JH3/Ply5eGlZUVs0/sePdCqXbqdBaUADr9/alvbdtnZ2dp2Q4AiaStg9dUKqWPV7TPpE+Mh1y0eHWjKTFRZkEbN5beN2YW9z5duKJyxj5WifLhHPHlGtrd9bCj1o+kujpwef1bp5B/yUiiHq+hBwJIeJhQ+lyQ6pEs6SMxYQs4B5naZVFLar2fOoWlVfSoWLXthDYICZ721txef7+5uem7AJranjLi5/xP50gfAMgktstlk1wqpY/oivYxHbT8qRHhKZrKtVlTh4IoHxa0SRnrd99uuiJzzsaN9iHKh3PER3ledF9Le0uc7lo9fdjg+IEJhc+MJk83btxgMhkxtmhysVgcuGi3Xbs0+Q3jsykNSIJJ71mv11Mje1ScWrWKlLrmljaPHj0ysksyTiitoF/Kgfbf0tJSoAJoYW/BSB+lek2yLS8vm8+2vb3NuQcAiaLtOrucWunjKWGaf+71lNiH96qHKZlY0MKk+BXtQ5QP54jv19TLDoiVEYROb54c1cKs6waplj6mXbuiFZhMJkf6SCKE3XFNHcKsxEhDJy9F9rTLHn0vdYaZtM7NIAGk9x13K/28ZKTPy1+8nOi723pQFG8HgKRh70XtbdtTOUFTEU/P4qDPqys+Lk7yXoVCSetiQZuI8fYh2ocoH86R4OT9wYJn1OaQsoeW7OCz9Clq8nT//v2OSZUiGxTpoMmVCgXrzxR9jY/00e/odyUpwvp82v/qFKb3lTRIcnSPjXQR6k4WVJpTLwG0sLAwVuRP5ZcVI30U8TOp8PI67wEA4o5ktXMt3Ui19BF9akRsTFrMU3WCPDp1RdImngUtjMOk0T5E+XCOhIGu1ZdpX9VdR+Z4Fmh2/q6kSCGOFQhA+qxr8qQ0Fk2mlO6hVK9etUyU4qOoIMkgLWbDqCeTFSTXNMZra2sDF+22qPDe3l6on/H169fmfdX9KenRPSoGqmM4rLGTAHr16lVLnA1bsLt9Uy0fW9fn5Pxk7HFQil6Y6YEAAH6heYozJ9lNvfRx5MyGZz2Ip4dnN8vV1VHr7jgFm3sVC92hjg8L2kSNuVe0z181BgpRRQQ1f/ek4982X4sx5RwBSKn0qWjypMWoOhbZui0q9Cr5oDQi/VcLVNvmuR0tYKkL4g+2WLI6Rg3aoizEa6Vgkjp5KbpHx7A9bhXhElXkmvaZ7T6zu7s78ncp/KQwcYqXCldPTU2Z850IPgBIErr3ONfyeiakjyNqil5ROa2Ur3J1R2lfXtE/kjhKFZsvV7d6pHJRKJQFbWJx5M3ZqPJGEUEuWXShyCHGlHMEIKXSp6bJ07/+1/+61Za7X+qOFou1Ws3IILuI1r9jIpod6aO0P723ImZOTk4acd/ao3viIilteoLSzEbddn6102rdfvHni7HHRa3oqesDAElDEcaO9DnPjPQx4uf5waLa/g7ZFeZ8pN/1sU4QC1oWtKGP+4gCZ1xRBJwjAAmWPqeaPP3Tf/pPW4VmJXaG3Wz0T9hpRmnEFqeUUIuz9NGEW3VwrPiJczev9hbsiu7p14Er7DG0UXXjiLP8j/JG/Gx+3Bx7bCRvrQgj2gcAkoRNk20ynRnpIxS1o1o8w7YEHoSif6gfwYI26YwqcYjy4RwByKD0MYtPu4hXjZNRNtsFyNYEgvGRlNBYDtPdKUrp4/68En9+tCP3e7OFseOagqjOa8PWcHJvu6e7RvrMvJmZKNrHFrTW+R8XIQYAMAg9oHKkTz5T0sciUTP/tLo5IF2rTxRQtUIbYBa0qRr7IUUOUT6cIwAZFD6ztn6PjYYYtRW3za2XONL/MxnNjvQRtiuVulHFaVP0jGrW6LOp81wc9/fbt29b0XXjbIvvF434Kf60OPY4SdbZcVKaJvW5ACAJ3Lt3z85bCpmUPu0o7UsRO5edX7pTuozkuewKU6EFMAvatDKszCHKh3MEIIPSZ9kuOidZuNsUGi0a6eY1+SR2Z2cnMdJH0SE2zH5rays20kfHsj6Tomniur9tXQpJl7GEze9PG9OV6YnTvJSe1y5+1UWO8xEA4oytLdeklHnpAyxoYTihQ5QP5whARqXPqiZN/+Af/IOBBZz7befn561Fo6JVmJCOx507d8wYqtbKoM3WUopDLRbbPlfyYtRIsSA2dcSyaV1xl5C2ePq4BbH3f71vpI/auB9/czz2mOkcVgFxG7VHjS4AiDM2fbfJJtIHWNBCu9Rxt2HfGVYKAecIQEqlz7omTfPz80OnFfWLFrBpIpqMMSkNVvrYqIy4fHab5jWuOPRzs13lktCVapTorl6bWrdL/Mz+cNZE/0yy2Rpdiv4jag8A4orSdp374A7SB1jQwpU2sVNw74fmz/JE+XCOAGRY+mzatKxhZUO/TQtXvc61a9ciTztC+oSLIkNsN69Rur/5vSnSyI7N+vp67Pe5Uqn0WRVlM8lW+EmhJX7O/3Q+9uto3+VyuZb4oU4XAMQRWxOtSQ3pAyxowbUfPtVdET27i3/97YbrZ2cSQYwX5whABqRPRZOmv//3/74v0kfbyspKa8HIxHQ0bG2l4+PBaTpxkz7CykOJgqg2m6KUlPpSNkVhUumjDl4LewtG/Kid+yQdvRS1J3lnU72o8QMAcUMPlpz7YB3pAyxooXM/eET7/A92v/2TK/qnxFhxjgBkRPrs29on+q8fbbcVaWHrzbx+/ZrJ6QjcuHFj6P0QR+nz+PHjSFO8JMvsuOgpcBL2uV/SR5sifBTpI/Gz/OPlicSPzmPbzp1aXQAQN9REwLk+nSJ9gAUteOwLd7QPUT6cIwCZlT7HmjT9vb/393yTPu3RFuquweQ0O9LH1lgYtwX5pJuVFEk67vyUPtraO3pNKn60qSi2rdWF+AGAOGHvg0gfYEEL3fvCq7YPUT6cIwDZlD6nmjDZyBy/pI/tnnT37l0mphmSPkqnUjqQPpe6QYW92ZQkPQHOqvQx6Vm/rfsqfpSuh/gBgLih+oHOvXCKSR2woAWP/eEV7UOUD+cIQOakz7kmTKPIhmFTQ2xBZyam2ZE+YpRi1H5uqkNjO9ElaZ8HIX2CFj9JSZ0DgGzcM5vMMqkDFrTQvT++aix6RPl8j7HhHAHImPQxkRl+Sx9tNnqILl6jP7WUNOubwtPcT1bWxe07PHz40Hy2zc3NUKWP3k/vq/dP0j5Xh7EgpE8Q4md1ddV81hcvXnC+AkDk2OYHTfJM6oAFLXTvj3ffbnpE+tQZG84RgAwJnxkrDmx0xjBdo4bdbH2VJLTNjgs2emfQFmfpYyNXJAjC3OzxlrTi4bb4tcYtiO3k/KRV3FldvSZp527TNhVNlYTOaACQbuzcpckiEztgQQsdLL1vzCzufbroUdOnwBhxjgBkRPrM2qK7qr3jd0rO1taWeU1NypicZkf67O3thV7MWfWDbOpRkur5iAcPHpjPXalUAhsfFXe24kf/1Z/H3eyT9bm5OZPyxXkLAFGhGmPOfXOFiR2woAXXvvi026d7F9E+nCMAWZE+i1bK2ImTnuT7tSlFyS7ESfHKjvSxxZy178PaJEySKhjv3btnPrsESqBi7E/nJtJH4mfmzYxJ/RorcujkpCV+lI6oCCXOXQCIUpo3WWViByxo4S/74atGvrfwIdqHcwQgU9KnYLvx2Dosfkcb2JQbaoBkR/oIpf/o86m4chibPc7K5XLi9nkQqZX9xM/C3oIRP1PbU43d0/Ek78XFRau+j+3S9+HDB85hAAgVmx7bZJ2JHbCghbb94I7yURev7p8xVpwjABmQPkVNlvSkTItl/X+pVCICIyKUlqSxUtvxQZvtVKUUmzhHr/gZOdZPQCQ5okz70O8i6n3H688XjeJPi0b8iM2Pm2O/1s7OjjlerfzRea7vo/8+evQIEQQAgaIHSs71Z5OJHbCghct94BXl81Wj0OvnjBnnCEDKpc+aJkt6UvbmzZtA6rDY1u1K90larZWwkbDQWM3Ozg4cV9VeirNM04I/rA5etnaUjt0k7nfbsS3sbaO+0RI/qz8bv+i26im1R/24kVRG/gBAENjGAU0qTOyABS04+6B3RA/RPpwjABmUPuu2u5atw6I/axHn57awsGBed3t7m0lqRqSPbUMeRgcvm9r16tWrxO1znXf67DMzM40otp1f7Zg0L9vSfZLOXopU0nGpKDTVJyoWiy3xo2sLKZ4A4DeaVzjXmX0mdsCCFq4MiuZp/v9sV0evrxpFxo5zBCDt0scWYrW1RfxOyVHKWFLrrYTJKNFWcZc+b9++NZ9Pwi/ozaYXJTGSzIq+XC7XiGpTQWcVdrYt3Sfp7OUlglZWVlryR8e2osC0UKPlOwD4dd9sUmNiByxoQZE8NVckz3HX77z7dtP1O2dLB40pxo9zBCCl0merXfrY3Pig6vqozguT1N7YgpTDjL9qqcR5TNvrE6nmTlCbih/rfVQ4Oon73MqxxcXFRpSbRE97Z6/jb/wtKm2vAe0o+kcF5En9AgCkD7CghcnHXnV7uqN88u7fW3rfmPGI9ikxhpwjACmVPpV26aOUjGHTi0aKJIh50eG4MEqklV1Eq/NaXL+PLVAcZF0fW89B8iCJ+9yecypEHaQcG2ZTalfhJ4VWZ6+tv93y9/XPz02E2suXL1spn+3yJ4lFuAEA6QPAgjY2Y68OXR0RPLs9f5doH84RgIxKH2Fbbfvdut12V+Kpfm/sIniYmkpJkD6vX79u1asJSmjY1MH2YzhpKOUprE5nQ43pz0sdBZ7V7SuITTK4UCh0RP/o+qOIQ64TAID0ARa0MPy4DxnlYyHah3MEIGvSR5MmO4GykRNKy1HnLb82pa/odSnm6s3e3t5ItV2SIH3aJaI6bAWx2XoxSS4SbtP6VJA6Llt7gWe/6/x4yR/tRyuGbfSPav/Q8Q8A+mHrojU5ZWIHLGgzPe7DR/m0/g3RPpwjANmQPvtu6SPu3r3r+yLUSoqkttUOGivbtPgdZlOKjH5fwiDO38tG+wxTnHoSmajaOEnd94pq+c53vhNIPa2JZMxv643ZH84a8TNdmW7UflML9P0UDaZaVXafCrWzp+sfACB9gAUt9B7zEaN8LET7cI4AZET61LykjxahWmz5mXKilCX7JJ/aHd0oYmeU+jdJkT7i+vXr5rMqosPvTZFRaTim1G7eig61Oo/Lpjo/i+8XW+leL3/xMpT3Ve0fm/Zm64HpWCfyBwCQPsCCFlxjPnqUT+vfEu3DOQKQUekjbCcvP7sKKXKI1u3e2KLHw4qRJEkfK7T0mf3eVC9Ir52GY0DnoZWtOleiLuzcvrXX+Vn+8bKRQYELp/NzI8Da074kEIn8AQCkD7Cghcvx/qpRckmbi+bPZof990T7cI4AZFn6KNpHdTWGLSw8zEaKlze2vbkWt0Mvwp0CxkkQaLbQZhApXjYFKC3Hgmo73bhxoyV+/Dr3/Nja6/yorXvQ6V7tmyIO2zt+SSRS7BkAdB1wrgtnTOyABW3GUESOInM6xvzdt5s+iKMzySDGmHMEICXSp94vNca2EPerk1d7ihdpGn/B1r0ZJapKERBJ6lplRcbx8bFvIuD09NS8pl47bU+u7XhJlOn803eNw3ZyftJY2FtoRf2s/c1aYN29vDalP6rIvJV9kp5cSwCyTasDIBM7YEGbsbH2iPIZR9b4JY+AcwQgptLntJ/0sSlewxYXHmazT+tJ0fgLDx8+HDn9KWnSx3ao8rNezcnJSWojxyQybOczy+zsrBm/OEggyR4rfnJvc439X++H9t7qKtje6l3y58GDB54RiwCA9AFgQZtC/BY1fgkk4BwBSJr0sbnyerLu12bTkpJQiyYs7OJexWvTKn329/d9P5Y0XnpNdZtL43Eh8SPxurS01Kr145ZAq6urJvUpijSw42+OjfCx8mflcCXQ1u7uTfWv2uWPrfmDAAJA+gCwoE37OPssaYj24RwByKr0EX6n5djFP3V9LrFdm5T2NkrhXlsUO0kRU/ZYGkVu9dvU3tvWd8nCsaJ6P5JAkly23pZFx4+Eqs4vjW+YEmijvtGq9aP/qujz2R/OQnt/RXzpu9ui3u0CiKLxAEgfABa0KSMoQUO0D+cIQEqlz9kg6aOn5n52XpLYsDU5VMsmyxNVFaD8zne+Y8Zia2trpHFU/Z9eRbjjyjhpbP02jZle79GjR5k8ft6+fWukhq295YXSKSUINeaqhyMh5Jd06xAv5yeNwk8Kraif6cq0ae8eZr0fG/2l6Kd2ASTBLBnG4hgA6QPAgjYNY7zbWHfJmXM/5AzRPpwjACmVPgMjfcYpMjzsYl1P4j9+/JjZieq9e/fGHltbG0kL/6R8X0Ul6TMrJcePLUlt68MQQBoHRT1JAunc6iWC3ORyOXNOqlbOpJtSvhbfL7bkj7p8bX7cbESxSfS0yx9FmmmM6PoFgPQBYEGbUIJusU60D+cIQBalT3s7cT9TRvT03dZjyaL40cJTKToa13GK8qqey6B9FzfaU/v82Gx9qKTUNYoCpYQpGkwRQRIeEkLCptq50b7RuE6azqnCzvkf5VvyZ/aHs6ble9ibrlmK/Gn/jjrvFHWWpHMHAJA+wIIWNL7vvt3saq9+0JjyTSoR7cM5ApBB6SNs+ojfnZesuJD4yVrb5Uk7o0kW6d8nSZjps1qB6MeWtGLWcd0n6+vrpli0u06QjQJSWti43cIkeiR8rPyRCAqz01fHZ9nZadXCsigyCvkDgPQBYEGbAIKO8mntQ6J9OEcAMih9FKFhF4T6f782LSSt+FEHqyyJH4kufW+13x51U10k26o6ad/bRpj4kUqUxGLWcUdjqTpec3NzngJobW3NdM0adVOKl1K9rPxRCphSwaLYdN2xwhD5A4D0AWBBm5SxDTjKp3M/fqq7on122AecIwAJlT51TZSUAjJoUqX0EP2uamSM0mVq0KbFv031khDIwsJL0RVWoo0jP7RoteOVtO9uo8b86AaXxGLWSTtO1V1OtafcUUASQIqwGuX4VVFndfpSkWcrf1T8OcxOX8gfgNRKn3MmdsCCNsWEFeXT2o9fNQrufdn8WZ59wTkCkEDpUxtl0WzljGpk+Lmp7oZdwCvCIO0RP7ag8bjFsSVM9O8lUJL23W3xaj8ixpA+4aJxVqe09iggdeLb3d0d7Xz/07np7NXe5l0yKOxOX73kTxJlKkBWUX0859w9ZWIHLGjTPK4hRvn8ZV+6on32Pu2yLzhHANIufRQRZJ/4+932WdFDtiOV5FKaizsrfcbWohln0yJb/14CJWnf3bZtHyetDekTH9QtzAo8obo/I0f5/eGssXK40or6yb3NRZbyZeWPTTcdJvoRAKJHkXlIH2BBm/Yx/aqR94i6KYTwvkT7cI4AZE76CHUA0r/R4mjc4q49F4FnZ61Fl8RIGieoklmqxTNJXRsJk6SOkT1+xhVeSJ94oSLQVvyMGvFjt9pvakb4WPlT/GnRRANFsdmIHxVaZ/8CIH0AWNDGYkw/7boibuohvjfRPpwjAJmTPpIWKrpsI3L8bONuU5dsZ6o0LuZVI0XfTUWIx91evnxpXkMCJWnfX7LHr05wSJ940F7va1yRqdSutb9Za4kfFX2OosuXFarqZsa+BUD6ALCgjXo8I4ryaXt/on1SfI5898uD6Vy5Wsw9q67Pl6tbuSdHtRbl6o5+3vxv6Xa5Nsu+gwRLnx1NliQiRplkqeaO7cLkZxt3t9RQ7ZA0pXnpu9h6KGofPe5WKpUS26pcaUG2bfukBcGRPvHBdqNbWVmZTPp+c9wR9bP6s9VQa/3YIulKY01ziilACqXPMRM7YEGbyvGMLsqn7TMQ7ZOic0Si52a5upp7drSfK1cbw3KrfFg3AujLgxn2IyRM+lTGlQdBtXE3T/0vLlpFo1U4Ni2TU30X2/loEuFhax8lte6IH+JLW6FQaIwjLcF/VEzVXg90PZkk9dMd9RN2rR977VHBdfYtQGKkT42JHbCgTdtYRhzl0/Y5iPZJyTmiqJ5bTw/PRpE9XTw9vFAE0Nz3DqbYn5B26SNsWse4Xaj6PvF3OlSlpaiqjXDxo125omSSHIlg6/pM2gXO1l9JYsRTGmmv72PrfknMnZyc+BL1IxEURtTP2tpaquuKAaQJRXoifYAFbWrHMvoon7bPcky0T3LPkdtfHuRvlg+PJ5I97sifS3lUYJ9C2qWP0rz8StXpt/hSKlmS27hLWtnizfpOk2z1et28juoqJXk8bE2oSTZJI72OZAOLn3igqCvVw7HHu631M263tiiifuw5JrFKFy8ApA8A0ieKcfyqsegRXbMY4eeJRdQR58jo3HxSXb5VPjzvI3BOmmyY2j7PDxZblKsFU9Pnsr5PPwG0wX6FNEsfYYs6+93C3Sz42tq4q2ZIEiNb2oWPijdPKse2trYSH4Wg/agFtWThJFuSC1pnAaV93rlzpyV/JPl0/I5T7DnsqB8rFJWKKImlFBL2KQDSBwDpE9o4xq+OTpwijzhHhhQ+qt3TJ0Vr2ALNquOjej59UsN2SPeCGEufjUkXzQ8fPjQTLi3Ag9i0QFSkgBU/SYn40YJX4+qn8ElTdIuVhYqqQPqkm9evX7cKv1t0Poya9hVm1I/OVaWn2c+raw/7EiB+qPaWc57uMLEDpE9axjCmNXSI9knWOZIrV9c8Bc2zo/1xu3E53b42eokf9i/EVPqsTVosWQu6oOr62E1FYe0CTLJARWPjGtUjAWELFbcvcP1Kf7NFZpOednL//v2Jizlvbm5SeyVB0V0SlbbLl00LVZThqJtauaulu8TP1HbzNeobgVx32uuKCV3r2JcA8ULXEOcc3WJiB0if1IxhfLtlEe2TjHPESc/qEjOK/PHj9fukjJXYxxBD6VPUZEkL8EkWczZVJ4i6Pu0RP1Z4KHomLp119DkkHdyRDNPT06bQ8O7urq/RB2lpJ/3ixYuJaxypTsykxy+Ej6L1rPSz3ewUtTVKx6/zP503ij8ttqJ+FvYWGifnJ75fd9oWlEbm0sYdIJ73kibrTOwA6ZOG8Yt5pyyifeJ/jigVy52GJUEjUePz++S70r2eHl7cLh8ssJ8hZtJnWZMl1ayYZNJln96vrKwYyRGU/NHr6j3sIizKtB5142qvV2IL1voterwiD5JcxNkdIab9Oe6mcfbj+IXoziF3VJy6fY1y/XBH/VR+WfH9vFNEmU0x1QKTfQcQH2w3yCYlJnaA9EnF+MU3yqftMxLtE+Nz5Fa5utsV4eOz8LHcLNdy3RE/h6fU94GYSZ9FTZYkLyaNdnFHuaimTVCbFmGKLLKfPew6P2pVr2gb+11LpdLEbdizls5kW9irUPe4m4qH+3H8QnQockYdv+7du9dR8Pn8/HzsqJ/lHy83zv5w5uu5p+uZjTKMa3opQBbR/dC5dhSZ2AHSJ+ljF/Mon7bPSbRPTM8RRd901/Cprgf5fUyXL9K8IN7SZ9a2RJ904qUaM6oNZAv0SoaMWqh11KgXW+dH0QJBdtfRwlQdQlS0uj2NS0WVR1mcTrqpNtCk3dbighbO+i7ah5NKH0kCFj/JR2LFRv5IBo4aMdge9TNdmTZ/9nNTFJI+m64D7C+AeNAmjJeZ2AHSJ8EsHTSmFvc+nXWM37tvN+O7n4n2ieM5cqt8WO+QL0+OamF8p/lydasjnezp4RnRPhAj6TOtydL169d9nYTZdC8tkoLc2uv8SMb4KX4ksZTK0V54tj2NK8hIpl7f1UY3JaWD2SDseI67qQaMX9IS4oGObSt+JARVt2mUTVE/hZ8UOlq7+7Wp05ytqUW0D0A8aEuzXmRiB0ifJI/bV42SS6JcLL1vzMT2875v5PQZifaJzzmiFC53xI0if8L4Tqalu9rAE+0D8RU/ZsLkdxSHbVWuGjdBRsPotdvFz7hRMDaax6v7lo0mCbJez6BNBY/TVr/GRk2NUsAX6ZN+JG/bI+rGkT+bHzc7ijz7le5lo30UXcC+AogeG11sIpeZ1AHSJ5kkLcqnta+bn9Elqs70Xdin0ZwjuXK10lm8uRpqPaj5p9XNzk5hh8fsb4iR9DkNInpEdTps3RtFxigVJ8goGHUAsotEK3/0GSRx2tFTQYuX3GmvS6Qiw1pshpnC1SvCwEb5JL1Vu5/SR/vF1llh8ZMuJGEVaacoRHeh52HF6/E3xx3pXvXf1n2L9qFrHEC87iMmcplJHSB9EjpmCYvyacmq5mf0iPYhuiMy6XN42hFp8/xgMczv5RXto5+xzyEm0udEE6YgauLoNW16lKRF0MWOJWhsnZ9RkTRaXFyMNJrHa1NdExvJpJpJaQzLn0QIBhGpBvGTP21P8w0qnj6UEP7DmYn0sd29dk8nP7eV2mklLOIHIFrswyUzn2FSB0if5JHUKJ/W/ibaJxbniLuAszpqRfHdVEPIleJVZJ9DTKRPTRMmpTYFNSmz3TUkVoJq596+7ezsmKLHitR5+fJlB1qwSTIIRQjFedPnU0FbW6xaC2CkT+dmF99pGxvoRtGIEkBW/AxbV+vizxeNlcOVVrqXUr/8FD+vX79m/wBEJIWd68EZ0geQPkkdr4RG+bSkFdE+sThHcuXqmku2VCKRPjH5HAAe0mdHkya1XQ9yYmZTqdTxim3wpvbsSjGz6WppSuvyU/rYyK4gu7dBvFCapq2zNcqmos5W/Lz8xcuJz1GlkFLfByA6dN13pM8p0geQPgnEESbnHWO221hP3D4n2ifyc8TdPetmuboaxXe7XT5YiKJ7GMAQ0mcrjDbgb9++bT2hVxqVnpJLbLB1b7YVuU0fSUu3Ljf6bvqOoxbpRfrwdN9KZF23Rtkqv6z4Jn5sIXGllxBpBhA+ehji3CtrSB9A+iRxrFIiS4j2if4cUdHmDunzpLocjfSpzXZG+hyess8hJtJnXZMmpU0EPUFbX19v5d/bOj/jFvFN86Y0NI2P0uLSPGH3Q/pIIAadngjxQ/vbXkNOTk4iEz+2m1cY108A8L4ONNlH+gDSB1GCwMrwOaJOWVG0aveiQ/o8Pbxgn0NMpE8pzCLBqoVh03ps1A+bt8hIe60QpA9Mgq0VprpXo9YKaxc/G/WNsY8/FX23HeSINgMIF3XodOYSFaQPIH2QJEisDJ8j7s5diriJ6vvdenp41v5Z2OcQE+lTiKIuhcKybTtm1flRK+Ssb2pBru5hVoilNa3LYmuzKLJp0kgLiulmj/Y0r2G7efUSP/u/3h/7GLTnrGoMsV8AwqNcLtv75TrSB5A+CJLo9/1uY71LZP1VY5p9Hvw5cqt8WO+s6VPLRfX9XIWcM3kN+O6XB9PqXJZ7Vl039ZbU1cxSru7o583/lqKUcxmUPvmoFixtT+kMqs8ybEeetG2KVFDHMTsWKt6c9gm7H9LHLriDrkkF8UTXC5syOk7EmDp5SfpMV6Ybp78/HesYVJe9mZkZ8xl0TLNfAMLBRos2KSJ9AOmTpDFKaSpU0tvPJ/kcyT072u+QLc8PFqP4bre/PJjJak0fiR4V0O7aFwNwhF1JY8f5Eaj0mdKkSVE3UUzalJajiZvSI/Q51LFKEkBRL1nabMSKZI/qg2QhXQnpA36gKC9b30cRP1tbWyMdQ7ad+8LegmnvPs7WXnxdRevZLwDB05Yqvoj0AaRPUsbnq8ZsmtOgkt6CPrHSp1ytuGRCMSLpk++MODo8zsI+1Xi709pG5unhhSKA5r53QC2s4MTPWdTpRKqHcffu3dbCSfJHaV+TtPNOyqZCtFmsC+KH9FlbWzOvoTB/FkHZxR5LllEKxEv05N7mjPgp/bw09rGo65XeWylndPMCCB49JHHO+RmkDyB9EjM+n3ZdUqSepu9HtE9E0ucyXaglEOafViMZc5PS1BHFUt1N876U5HIX0Z4URx4VOFcCkT7Hmjipzk4cntrPz893LOCUOqGCqWndbLcuRTxlcaE+ifRRSk8Wxw68rx12EThqK/f6b+tG+kxtTzVOzk/GOhaVoqkU1TAL4wNkGWeO0GqMwoQOkD7xj4LJu8en+bPULe6I9olA+jw/WHTJg5OIpM+O63OspXU/3nxSXb5VPjzvI3BOmmwYEab9YylXC0bSXdb36SeANjhffJc+O3Erhqv0JnXnscWebaevtBV8VhqbrQeyvb2N9BlxOz4+Nq+hMH8WQSDZY2uUjdrRq/CTghE/+u+4G2leAOGgqFjnXDtB+gDSJzFjk+4oHwvRPuGfI0oJMulBEXfwckuQKAtKByp8VLunT4rWsGPv1EAq9UkN2yHdy1fps6HJk2rJxPUJfrv8GfUpflw3FaHV4tTW8slaSogf0kdFdKOsSQXxQimq9lqhwuijiB9F+CjSR+JHkT/jbqorRJoXQPAPhpw5wT7SB5A+yYh+yUSUT9v3Jdon5HNEqVRRpniZCJYMFHFW9JKnoHl2tD+uaHO6fW30Ej+cN75Jn1VNnh4+fBjbCZ4WT+11O7SgS2KxZ4melZUVU3S2vVNXlmr5+Cl9tKn+UxZa3MNwKE3VFoYfVfyops+k0T56v1wuR5oXQIDYqL4mW0gfQPokYlyyEeVjIdon/HOkK/rk6eFFmB2h3G3jo6orFKjw6U6jcyKaqqu+7MPeKWMlzh1fpM+yJk9LS0uxn+gpZcKd8qVuPYr4iPOm2jM2qqdd9ii6Kquywi/ps7Cw0IhLTSqIn/gZ5fg6+8NZK9rn+JvjsY9Jm3ZImhdAMEioOufYGtIHkD5xH5OMRfm0fW+ifUI8R5QG5E4TCku8dEX5hCycwkDfxz2+EjQSNT6/T74r3UvjWT5Y4Ho6sfTJafKkAspJmOxJkkhQtQsUobbnOzs7sZI96iJkpUS76MliZE9Q0keRU3qdV69esRiCFqqRZTsBjiKFbbRP/kf5iY5L21kuKddVgCRx7949e19dQfoA0if2Y/Lp2CU/aln43k60T90V7bPF8RDcOaKIkK4aM88PFgOVIeXabFSyKUzc6XMmwsdn4WNRLaTuiJ/DU+r7TCx9pjR5unr1aqImfR8+fGisr693CSClVuhJe5Sb3l8tnG2RZkUnxbVmUtKlj+1+Rtt2cKMC3zbNa5Ron+nKtBE/u6e7E6V52dRDpXWyPwD8oy1yNo/0AaRPnMfjq0bBI8onz/fnHAniHPGK9tGfg4q60ft1tSxPZ5RPvruGT3U9yPfsrpFEmpdP4udMEyiJlCROAFXzRzn+Kp5q5Y+etCvSJsxNCz3JHncaV9Y6c4UpfWzbdnV7Y1zBLYa/853vmONjc3Nz6GNq8+OmkT7LP16e6NgsFosISYAAaEvznkb6ANIn1uPhinTZ+7TLGGRvDMI8RzxlwZOjmooF+y18mq9dCVuGRIG7XpHGM4z3nS9Xt9wCj2ifiaVPLS31J7TAUtSSlS6zs7MmBUi1f4Iq/qz0EaWW6b30nqonosLY1PMIXvrYNtlJqEkF4WPTvFQ8fdgIQEX7SPqovs/5n8a/ZuiaYK8H1JwC8O8hj3N/P++YxzCZA6QPUS6MA+eIkQVPq5tuGSNx4Vcbd9Nt6slRzauDVdr2l1K43N9TkT9hvLdp6a4UPaJ9/JQ+lTTVRdECSxLAFnO1aOGn2j8SDUq5kDAQJycnI0XzaDGn11DaiO3UY1HYOekcg1FkjsZLMm6STfvOjjvjCv0Eo6TssOJ38f2iET87vxq/TpiuFbpG2Ig/WrgD+HN/d+63daQPIH1iPRZEuDAW0Z0jXlJGkSKT1qGR8OhK6XJqzvgdTRQH3NFMqu0T5vu7BZ7GnnvNRNKnlNYWw5ogqp6Ore8xDBI56gzWjtLF3O3WLZJLkkyvX79mUj4k9+/fN2On9KxJo6zsoppxhV7cvXvXHCcqrD5MG3eb4rVyuDJxyqct5k4KIsDk6OGUc+/dQfoA0ieu40B0C+MR8TkiAeMtZy4jckaNVlHUiTvdyFU3KJX7UzKr4/sGXBjba9zd0T5pq5kUsvQxbdu1MErzZNEWf9aTfy3AJIKEOuwMK4RsRx69hlJHSNuIVvpoS2IhcggXdf2z57mibwaJn9Pfnxrpo6LOF3++mOj4VG0xK4vfvHnD/gCYAK927UgfQPrECM+uVRmvY3N5bDAmYZ8jTt2dHU/xc8mJavD0ageuLlI3y9VVz1SuttfwK20sbrgLOKujViTiqXv8i9xvxpY+M7bLFJPKvzPpWVqctaNaQbRbj6f0sV3SSJ+BfujcVUSYTQccJH4W9haM+Kn9pjbxMapC87RwB5gcG7Wnh1VIH0D6xDOqpeSSGxdL7xuZfzJPtE9054jEjkdtGE+6ihb3/d3qbhpTulrjVq6uub5zJcufI0Xix3Tw0hNxJpaQJOlj2/ci5GAQivazXf6Ustlve/mLl0b6rP5sdeJjVILJyknSQAHGp61z10yqpc9lakJ1VYsVk1KgJ50WPbnWIqZcLaX1CTML2mTiRPmcdYzDu283OTbs8UG0T1TniK6VkjTDCp2BYijkNKcocKez6Z4UxedQJFYU3cNSLH32NZGivTgkTfqo5lJaus9B8NhCsNPT0/2LhJ+fGOkz+8PZhh+b2sYT7QMwPnoo5dW5KzXSx0lFKI66MHGeTJfS/MSZBW1iolmI8uk/PnmPaJ/Uy4M4nSOSNarpM77sqa5kZV+570WTFsGeRNi5i2ZzPZlI+mxqMqUUJiaXkCTpowLbCEsYBVvfZ1DnvtzbnBE/9d/WifYBiBiJfUf6HKdO+jQnsgUVA53w6fM57WyRPlFBlM+wx8inXZcYq3OOhI9pu24le4+aPaYQ9OXfZTKq0l0IO8pi1R375unhBdeSiaTPiiZTWowzuYQkSZ9SqdRAWMIo3Lt3zxwztVr/ej2ln5eM9Nn62y1fon1sbZ80dkoECBpd4x3ps5ka6aNCoeM+de5bnDQDqQcsaGMXxUKUz3Dj5BXtU+Acgfg9jOjs3BWl+HI/FGH/TCR98qQeQBKlj15Dr7W0tMTYgq/Hn2SPpI/kjx/b7u5uA7kOMB7quulIn9VUSB+FyjvROT3kzeHp/NPqpp5Gm5QES7laUE2fIQqOFpngsqANA6J8Rj1Oshvtg/RJDu57jB5SRCegOu9v7J+JpM8Ura8hLCRodLzt7OxMvJBWS2y91rVr1xhbGIqHDx8OJX3UuUvSZ/nHy75In+PjY/O+d+7cYT8AjIgt2t9kIfHSx4icHt1kVDxz2DB6U+vgUgB5y6Pm3zHJZUEb+Pf+6283XBLjjCifPuOV4WgfpE+C7lPuKNSIIkib98MZavr4Ln7qmlCp0CkTTAgSCRodaxI2fmy2VgodvGAYHj9+bI6Xly9f9j2uzv5wZqTPzJsZX45TKyjVQYz9ADDefaPJdKKljwqBegqaJ0e1cZ+kalLs7rSC+GFBGwaSO0rlcgmMEsfDoGMlm9E+SJ9EPZyoxCF6VA9B3LWW2D8TS58dTahevXrFBBMCY39/30zcZ2f96YqkrVAomNdUzRTGGAZha4MMkj7apivTRvyc/+ncl2OVqDSA8e8bTc485y9JmWiZGj7eET5rvrz+k+pyj9fPRBQBC9oIvvO7bze7onwOGlMcDwPGLaPRPkifBEmfZ9X1jijUp9VIUjZNZGxH04LqLvtnYumzRpFRCBpbzLZYLPomfWw7bGqlgN/H4MLegpE+x98c+xqV9vHjR/YFwJCo450jfXYTK32cluwn7i4kfj891VNRd7qX/pzF7jMsaIOFKJ9Jj5fsRfsgfRIkfS5ryHU0CYhI+uwE8ZAk49JnWZOqu3fvMsmEwPCziLPd6vV6g0LkMCyKZtTxsrKyMvDYWv3Zqq8dvGxdElIRAYanXC5b6bORWOnjESofWLj87fLBgjvih5B4FrS+f1+ifCYbvwxG+yB9koN5UOG6j0Tx8MD9ECPKgtIpkj4zpB5A0EjM6DiTqPFru7i4aExNTZnX/frrrxln6MubN2/MsbK4uDg4iuzjpq8dvJaXl8176zOwLwCGwxb/b7KSSOnjrkngUAlYMpVI82JBGxRE+QQmzk7TLM6QPslCqVRRpniZbpUUcQ5K/JzyFBqCRB3idIxJ1Pi5LSwsmNd9+/Yt4wx90TGiY0XHzKBt/9f7vnbwUkoZtdMARqOtiPNsIqWPe+KsMHk9RQ18wuzqvqIWvEx2WdD6JCu2iPJBnnGOpJub5eqqOyVZjQPCu3d2to2Pqq5QSqVPhYK4EBSSiTq+crlcw+9NURtEUMAox+EwxcRt2/bF94u+HKerq6sUHQcYAXUUdYRPzwd8sZ5Y9YjyKaT9vZE+6V3QZrnleEACLTNpckifZKGHE7eeHp5FIV66onxCFk4ZkD6rFMSFoLBpNUpxQfpAEqTP6e9PjfTJvfVHVKpjmN5bNUrYFwCDsYXX9VAqkdLH3QEl7Ggbd5QRnU9Y0E7+PbPZbjwoshTtg/RJHl2pwqrz8/xgMdAHFuXabFSyKUPSJ09BXAh68l4qlXyXPrZArp4KM9bQD9V90rEyPT09tPSZ/eGsr9Ln8ePH7AuAIbDF/5uUEil9VEC5Y8L8vLoS5vt3Rfs0J+xhpJYhfdK5oCXKJ6BxzUi0D9IneXhF++jPQUXd6P267ptE+QQlfs4piAtBoIWuji0tfP3eFLVBPSoYFmcROfC4OvvDma/Sx4rPR48esR8AhuDGjRv2fM0nTvp898uDaffEVT8L/0nt4WmneAr2KS3SJ8XShyifQMhKtA/SJ5l0F1Ru8uSo5vf9zHQM8+p0+ay6zn4IRPrsa4L1+vVrJpzgKw8fPvS9XTvSB4KUPtokfaYr074cpzr2SaEFGA6biqmHUX3nLTGeKBfdk+QoPofC4l2T6A0mvCxoR/5+RPkEO74ZiPZB+iQXj/uISVf2q427eUjSvEd2C5+jfcY/MOmzrkmWFuhMOsFP7t27Zybw+/v7SB+IFNsN6OzsbCjpI5A+AOGih0+O9NlNqvTZiMPTyq6ntEyiWdCO9f2I8gmSLET7IH2SjZeUUarXzSfV5UleV2nIXSldTov2KKJjMyR9FjXJunPnDpNO8BUdUzq26vU60gcixaaMnJ6eDjy2FOWD9AEIHxsdqodRSZU+lSjr+Vhulms5WrezoJ3ou71rLHtE+Syy330e57/+diPN0T5In2QjAeMtZy4fJkjejCh7ZubL1S2v13PqBuUZ90Clz5QmWVevXm18/PiRiSf4vtAeJroC6QNxkT6q54P0AQgfNZVwpM9iMqWP+6loRLV03LWFNJlmwsuCdrTv9qnukhF0gQsACR6Jno6x/utvU5OOifRJPk7dnR1P8XPJiaJab5cPFno9hLhZrq56pnK1vYZfaWMwUPzUaX8NfiOROGwdFaQPBIVk9ijpXUT6AISP7bLX5EIPo5IpfTT5bZvIRjmJNW122z4Lk10WtEN/r68aBY8oH57ABzfeJZdgu1DqF+cIxOr+9qy67r6v9ELRpcP83uXvVndJ6QpV+mxqsvXixQsmn+DrBF5yBukDUbK9vW2OlVwuN3Qh56ntKV+O083NzQY10wCGP0/1EGrgnCW+0qeza1aU0qc56T5H+rCgHe97EeUTJp7RPu++3eQcgbihe5okzbBCZ6AYorNkFNJnRZOtpaUlJp/gCyrerGMqn88HIn1mZmbM63/48IHxhr4oykbHytra2sDjyu+W7S9fvjTv/fjxY/YFQB90jjjSZ+BaJ77SxxW+3ivcPWiccPyO1vFMdlnQDhl1QpRPNOOeymgfpE86kaxRTZ/xZU809e7ASJ9ZTbaUAsHkE/xAqYI6ppaXlwORPrYFN2MN/WhP7To+Ph54XJ3+/tRIn/yP/JGVEk1673K5zP4A6IMt/N+kkFzp0133oBDF59DTWHdHFCa7LGiH+05E+URBWqN9kD7pxqkfVzTRPz1q9phC0Jd/V6JuT2zEz6kmXG/fvmUCChOzvr5uJvDFYhHpA5FhU0aGTTOs/aZmpM/i+0VfjlMd/3r/jY0N9gdAD5QObGvANZlOrPSZf1rd7JzsVlcjewrbPvFuTriZ6LKgHfh93jVWiPKJcPxTGO2D9AGIpfTZJA0B/EApV9/5znfMBH5nZwfpA5ExSmqXtv1f7xvps3K44stxWigUzPtLPrE/ALx5/fq1vaYfDzVfietESk8y3QUqI/kcKrjZ+bS1wkSXBW0/0lxXhn3AOQIAHdJn2dZgYRIKk3Dv3r1AU7vOz88bpCPCIEZN7dJW+WXFSJ/iT/2JUFtcXGwQQQkwnJxtsp5o6aPWtK7aBeeRSJ+u1vHUT2BBO+C7pLiDFPuBcwQAOqTPlNMq1YRaMxGFcbDpNNPT00O1xx5nOz09Ne9x48YNxhwGHoujdJDbqG8Y6fPyFy99OVbpMgcwGF3LHemzmGjpY4SLq4NX2N1Jbn95MOOuqUA7XBa0/SDKJ3b74iQt+wLpAxBb8bNP/QmYBHWAs8dQUBvSB0aJHhg2tcukY/2kYKTP7umuL8eq5CdpiAC9sZ0emwwdFBPridR8uboVZYpXd12hw2MmuCxo+34Ponzitj9S00EN6QMQW+lT0uRLiyUmozAqSqexxTiDivIxxXZrtQapiDDoWBw1tctImsq0kT7q4jXpdnFxYd7/+vXr7BOAHrx48cJKn51USJ+bT6rL7kib218ehLJgM1E+Tw8vXO9fYoLLgrYXRPnE9dhKRxc1pA9AbKUPrdthbGw6jWRMkJuVPmrxy7hDv2NxlNQu26599oezvhynNiJtfn6efQLQg7ZW7cVUSB9xq3xYjyLaxx3lc+vp4dnc9w6mmOCyoO35HYjyiet+SUW0D9IHINbih9btMBbjpNOMs+3u7pr3USoZ4w5eUT4Sj6Mei7aIs1K8/JSTd+/eZb8A9DhX21q1z6ZG+uTK1YI72qdJMcj3vF0+WCDKhwXtKEjuLO59Ou/4HruNdfZtXI6v5Ef7IH0AYi19aN0OY03ex0mnGWerVCoN0hChF7p26fiYmZkZKc2w9POSkT6bHzc5TgFCoK1Ve32keUoSJlPuaB8JGXX3CuK9VKjZXUCaKB8WtAM//7tvN11S4UzpXuzbmOyfFET7IH0AYi19lklJgFEZJ51m3G1zc9O818OHDxl76LWINJE2o2z5H+WN9Dn+xh9pqSgjBDpAb3QNd87XjdRJH9O+vSvy5vDU7/o+Rvg8O9r3iCwqMKllQdsLJ8rnwiUUSuzXuB1jyY72QfoAxFr6tFq3f/jwgYkpDEVYqV3aXr58yWIaunjz5k0r2mzU7nEXf74wwmdqe8r8vx+bTTGTEGX/AHQzaqv2REkfoZQut4y5VT4896uNuwo3d0UUNVFtHya0LGj7fnaifJKxnxIe7YP0AYi9+KF1OwxNmKldJg2nVDLvpa4vjD/s7e21F4NtFAqj1+Sx9XwW3y/6coyen5+bz6J6JTo/2E8AnRwdHdlzVg+ZRlprJmpClStXK11ROJcRQGuTvK66hCmFy/3aatFOWhcL2n4Q5ZO04yy50T5IH4DYSx/Tuv3evXtMTmEgYaZ2aSsWiw2kJFjhqJboOh6mp6dHjvCx2/KPl4302frbLV+O0a2tLTrMAfShrVX7yOuXxE2qPMXPJSejRv0oPaxHOpcRPkr3YiLLgrbv5ybKJ1nH2VeNxa5on/eNBc4RAPBB+uR4Sg3DEmZql7bFxUXzfkrnYfyzja3hs7CwMFLR5vbt7A9nrdQu/b8fmz6PPpc+H/sJoJu26LzV1EsfI36eVdd7iB9T60cpWerA5fVvTX2gcrVkJFGP11BbeCJ8WNAOIRBmifJJ4rH2adcl6uqcIwDgk/g51oTs1atXTFChb6RFmKld7bVS9vf32QcZxxaCVXHvsdMFna5divbxY6vX6+YzKQIJaQ7QjeoF2nTMJjOZkD5G/JSrRVPTp6f86aj9Ux/m9xw2mLiyoE2zPMj8sfZVI+9R26fAOQIAPkifNVK8YBAPHjwwE3eJmLA2pZHpPb/++mv2AdECEwlHRfYowkfSZ/d015fjk+5yAP1ZX1+3wmd/rPlJkidXKr7cJ91rNJ4c1fzuBgbpXdAmVRxAcoUd0gcgEdJnlhQv6IfSq3SMTE1NhRblc3FxYd5T0UXsA7D1fMZN7fI7ysfUB1pepuYUwBCytkkxc9KnJX/KBwtKyRpX9tCSnQVtFqQBJFvaIX0AEiN+SPECTyQCbbtdtVAPa7OpM4osYj+ATREZZzs5P2lF+dR/W/fl+KxUKqR2AfShLbVLXbumMyt9LCq8fJn2Vd11ZI5ngWbn70qKFGKCyoI2C8IAki/ukD4AiZE+pHiBJzatSwVrw9x2dnbM++r92Q+IRxtpNnLE2J8vGgt7C0b4FH5S8FX4CKWvsI8AumlL7Rq76zATNGBBm3JZAOmQd0gfgMRIH1K8oIv2tK6Tk5NQpc/q6qp5b7X7ZV9km6OjI3MsqMbTqNvLX7w0wmfmzYwvHbvahc/jx4/ZPwA9sIX4m6wgfQDpgyiAFAs8pA9AosQPKV7QEV1h07pUsyTsbWZmhnbtMJH0Of7m2Agfv4o3I3wARjtnndSusbuLMzkDFrSjSYJjlySosf8SfNwlSOIhfQASJX1MitfS0hKTVoikW5fdarVaq14K+wL29/fN8ZDL5YavCfXbemO6Mm2Ej4o4I3wAwqNcLtvzZWeieQmTM2BBO7QgKHgIgjz7L+HH3rtvt9zRPksHjSnOEQCYQPq0UrxokZ1t2tO6VFA57M2mdlHPByR85ubmzPGwsrIysvBRty7V9UH4AIRHW2rXMtIHkD6hfMZPdZcc2GXfJZ+l942Z5r68cMm8EucIAEwofo5pQZxdlNKlRa3EX9jduuymVu2kdoE6/zx8+LAlWxTlc35+jvABiDltqV3nk6R2IX2ABe2wn48on3Qff+++3XQJvbO4RfsgfQASJ31Mitfdu3eZvGaMvb29VkSFWFtba0Sx2VQe1RNiv2RzwagILyseRbFYHEr47Pxqp9WaHeEDEA1tqV2VieckTMyABe0wn48onzSThGgfpA9A4qQPKV4ZFT7Xrl1rRVQcHx83otpKpZL5HI8ePWLfZIi3b9+aemJWsth0rmHSCyV3Vn+22irarBo+kwgfdapTlBvCB2B02lK7FpE+gPQJ+rMR5ZONYzDm0T5IH4BEip9jWmVnU/gookLpVVFui4uL5rNsb2+zfzIQ1aOoANslTkxPTxvxd3p6OtTxog5dubc5I3sU5aNon0kieyQ928UTwgdgtPuJc+6c+TIfYVIGLGh7o0U/UT7ZIO7RPkgfgERKn6ImbfPz80xiM7Do/s53vtMSPlFvEk4qHq3PQ6RZOlHdKNUMUwppu1xRO/bNzc2h0ri0nf3hrFH8abEV3SPxo3o+42x6z+Xl5dZnkQS9f/++iT5inwEMT1sdrg2kDyB9gv5czUW/S/hcSA6wz1J6HMY42gfpA5BI6TPlFGA0T+2YyKZ38W1r+BQKhciFj6nJsrPTahPPPkoXKsotkdJeq0eCT7JxlHRCpW1tftxsFWtWdM/LX7wcOZ1LglGRPe2yR59NkUfsL4Dx7ilffPHFJ+d8mkX6ANInQJwon7OOz/bu2032V3qJc7QP0gcgseJnk5bZ6Ub71tbwiTqly262FgSphelARblVm6k9fUssLCwY4TJsVE+77Jl5M9OK7lGx5tPfn450jKlez+rqqkkja/9Md+7cMZ+X/QYwHorgc86nfd/mIkzIgAVtj89ElE82j8WYRvsgfQASK33y9sm3nt4xoU0Xr1+/bkVaaBEch213d9d8puvXr3PMJRi1Wl9fXzfpoe1SZWZmxnSEG/V4O//TeZfsyf8o39g93R0pfWtra6urXo9SzF69ekUqIYAPtBVwLiB9YGhyzw8Wc8+q64YnR7UOytUN8/NytTD3vYPIFrZxW9AS5ZNdlv6qMd2173cb60gfAJhA/JiCznp6x4Q2XYtyW7hZ0RZx2YjySS696vRc/W9cbfzj4j82ETSjbifnJ6Zmj23BLhbfLzb2fz38ayltTOljtk6UUNSRijOrnhX7DsAf2gs4K0Uc6QN9ufmkupwrVyu3yofnzf82huLp4cWtcnW3+f/FsAVQ3Ba0RPlkmzjuf6QPQKKlT5H6KunDtsWOSx0fbTYtQAtyonySgwodq06PlYgWdWB7XXnd+Pff/vum3s5IdZ1+tWPkjhU9No2r9pva0LV6vKJ67t27R0c4gIBoK+Dsa7ABk7GUcbt8sHCzfHg8tOjpwa2nh2e559WVLC5oifKBOB4DSB+AREsfFXT+nSZy1LpIB1r02rbYZ2dnsRA+OrZsJAaL8vjyf639m8Y/f3PQ+Cf/ux82/kf/q/+i8e/9h08a/853/3Hji3/nZqs2lLpvqdW6UrKUgmVTsQYeA7/eN1E9tjizLdC8+rNVE/Ezbq0epQqqMLOi29iHAMHgKuCcQ/pAt+z58mAmV67uTCp73Egg3SzXckF//jgtaBf/+tuNrpouf9WY5jjLFnGL9kH6ACRe/JiCznqKx+Q2PVE+WpzHYdPnsAt0iobHk39T/382/hf/+f+l8d1HP+jJ/+zlTuP07NzsUxVWnv3hbEekjlex5eNvjo3Uaa/VI/RvN+obRhwNFRm0s2Mii7xq9bD/AIKnrYBzzfc5CBOxVAiffK58eNo3aqdcrTRZM/V92ilXS/NPq5t9//1lilghCwvaOHdvgpCPhZhF+yB9ABIvffIU100HinawxZvjEOXTLnyQivHk//R/+9D4h//L7/cV" - + - "PpZ/+B9tN37wf/9/dAkfsfW3W606PaWfl7p+R+JHP6//tj7UsaPj9+XLl6Y4tD2GlGKm44haPQDh0lbA2fdsGyZiCUcyRrV4egibHYmdYV9LET1GAPV+vcDkR1wWtHHt3AQRHQ8xivZB+gCkQvyYgs48OU82NrVreXk5cuGjAtJ2sa5OT+yfeCHB+/I/+17ju//kfz+U8Gnnv/4v/jtd0keSJ/c21yV6FOkzbK2e9sLM7VE9c3NzJtIAKQ0QPm0FnM/9LOCM9EmD8HleXemVkqXaPuO+7u1ybTb37GjfU/w8q66ndUFLlA90HRMxivZB+gCkQvoUbcoEk9zkoq5Y2o+lUilS4aOFu63hQ2e4eKHW5epspci+f/c/+I9HFj5ivvSfNP4rW/9Wl/gRqtmj2j2jtFu3knBhYaGrMLMKSbPfAKIjqALOSJ+EY1K6PCJyFKnj13vcLFdXe0T9FNK4oCXKBzyPi5hE+yB9AFIhfVoFnUmdSC6qmaN9qBooUW1Ky7EpOZIL7Jf48ObNm1YXrmv/7X9vLOFj+c5/9t/vEj5K37r488VIx4o7hUsy6tGjRxRmBogBrgLOeaQPGL775cF0Vw2ep4cXkjR+v5fSw7ravpv38re4c9QLWqJ8oOexEZNoH6QPQGrEDwWdE86dO3fMwlmRNlFtahNP1Fj8sKl/tt3681f/54mkz+yLYpf0WTlcGTuFa35+nhQugJhho0eVAh7Y3IMJWPK4Va7udqd0+S98LEoV84j4OZn73oFvUTBRL2ibi/gtVzTHKVE+0Do+vmoU3NE+zZ/lQ/0MSB+AtEifmc8+++yPV69e5Sl7Qrlx44aZoEdRxPn8/Ly1kOcYih9KlWpP/Sv/H34ykfRRipdXale/SB9SuACSeU9pUkD6wKWAMZ26XCld5epW0O9rUr0CLOwc5YJWi3f3+2uRz/EGncfop7pL/OwifQBgTPGzqwleuVxmwptAbOeusLdardZK0ZHwoXBz/FAxZO2fev2ye9Y/evZmIukjvGr67P96vyuFa21tjRQugITx+vVre86eBDrvYPKVLNxRPrfKh3U/I25Geu+nh2d+vXek0qe5eHct5usca+AhBwsecjCP9AGAMaQP7dsTimoxad/Nzs6GXsNnenq6ldJFTah4YlP/rPR59C/eTyR8/ofP/lXj5S9eNhbfL3a0Z1e3Lm37+/uNlZUVUrgAEorOV+fcLSF9wOAV5RNEUeU+7z/jkeblywEa1YKWKB8YURBGFu2D9AFInfipaaKnXH4mvslBXZm03yRgqOEDbpaWlsx+kozR9i/e/nwi6aP0MPf2/u/eNx5vPTbi0YoeRX7dv3+fFC6ABKHz1TmHz4Jo0470SSjqzOWO8on6M6g9fKKlD1E+MJokjCzaB+kDkDrpU7BP5Zn8JgtFaGnfqb5OGJs6L5lOUNeukaoTc2zb5c3NTbPvfvJvfjWR9Kns1zvS+1TPSamFVvaoFojSRDkuAJIriZtsBD7nYOKVHLo6doUY5WPxivbRz5K4oCXKB8YUhZFE+yB9AFIpfuqa8CmnnwlwcrApPEG2bFc6l6JFVldXW5Ec6gzF+McbW59jeXnZ7Mc//f/+3Pif/KdvxxI+qgf0//7/nJpUrfaoHhvxxfEAkFz29vbs+XyhBg9IH7CyJe9umx5WLZ8u+fTkqOaST8VESh+ifGA8WRhJtA/SByCV0qekSV8+n2cSnCAUWaH9ppQrvzdFiLQX47W8evWKsU8AqqOjiCzts9PTU7NPP/5/vxlL+vyPV/6jjmOAqB6A9GCjAptshTLfYNKVDHLl6lpnald1Ny6fpUklaQvaxXeN5a6F+/vGAscaDCkMQ4/2QfoApFL6TDm5/OapHxPhZKBFtyJvtN9yuZwppCtZo/SbcbeTkxMj/+wCX+JAEUWPHz82ET+Me/IWc2qbfnFx2Vr9B3/9i5GEz7/7H/zHreOAWj0A6b2HqLED0gdaqC17Zy2d6mpUn+V2+WChQ/o8OaolTvpE3H4bEi59vKRhwNE+SB+A1IqfdU38lNvPZDg5KI3HRnT4iaI5SNtJNir2bVu3Ky1LaYCq//Th//XrgS3c88XNxn/z5j801wNFd9GBCyB9PHr0yF7zQ1t/MuFKCO526TefVJejkz612c5In8PTJC1oo269DSkRP93pgcfBvh/SByCl0mfGyemnDXcCUYSWaq48ePCgI1JnVPTUV6/BIj8dKDqrrRVzi//q5/+1xkx+2UTy/Hf/5/+8JXpu/uNy47/3H642/jf/6f/WSCPGECCd6Bp//fr1T841IbT1PBOuhKAuWa7iyZFKCnd9oURJH6J8wB95GGohcKQPQKrFz6YmgEoLYVIMkB5evHhh0vTaUjlaSBLqib8iu5B9ANm5JjjXgFBryTLZSgjuzl2Ktony89x6enjW/nmSsqAlygd8FoihFQNH+gCkWvrkbbQHRVoBAABSG+VjpU8h1HkGk61kcKt8WO+s6VPLRSuhOgo5J0f6EOUD/krE0KJ9kD4AqRc/u0T7AAAAEOWD9MkouWdH+x2i5fnBYlSf5faXBzNJrOnTXIwXXcLngigf8EEkhhLtg/QBSL30yX/22Wd/JNoHAACAKB+kTxalT7lacUXXFCOUPvnOqKPDiQvYBr2gXTpoTDUX42cd7/Pu202OLfBBJoYS7YP0AciE+NmkkxcAAABRPkifLEqfZ9X1dtGiFu4RCqhi+2dRZ7G4L2ibi/CSO8pn6X1jhmML/BEywUf7IH0AMiF9Wp281BWKiTIAAEAqonw+RRXlk0rp890vD6ZvlqurkiQSI7knR7UW5eqOI09KURdCHhW1aPc7pWoC6bPjijpai/OCligfCFz6hBDtg/QByIz4IdoHAAAgJZTL5UijfFIjfea+dzCl6BNFnLgLDPfDKY5ckihKwndsft7zzg5eBwtRfBb35/CjqHSQC1qifCAU8fPu250go32QPgCZkT5E+wAAAKQA1ehTrT5H+uSRPmOSK1cL7vbho+JIjFICvmtHhM380+pmBJ+hFETEUVALWqJ8ICwkEk1x8M5oH9+uK0gfgEyJH6J9AAAAEo46cjrCJ9KO0YmdECm6pKuj1eScRNkVaxjB1fF5nx5eqJNWWO9voo1cgs0v8RTUgpYoHwgTCUXX8XYm8Yj0AYARpQ/RPgAAAET5ZFf6qL6NO8XIHX0iGWEKDj8/WGwhafKsuu6kdfWTP8W4fnf3Zw8z2qcrysdH6RTEgtYz8uJdY40FBQRFkNE+SB+AzIkfE+0zPz/P5BkAAIAon+xIHyNynh5eeMkaFW5WO/FhXkeFnB0B5C2Pmn8X0+9f8Pi8hcBFW7mWc4+Vn8IpiAVtkFEXAGEfd0gfgMxJH0X7/E4TxtevXzOBBgAASFCUz+eff/4pDlE+iZM+uefVFU9B8+SoNm4xYUWqmC5fCRI/7mgfyRg/iin3QoWuTepbgKllfi9og66vAhD2sYf0Acik+CkR7QMAAJDYKJ9KLOYTSZn4mBo+3hE+vqTrmJbo3q9fiJ/8MqlqXfWIgmhDbzqjeddO8lWg+L2gJcoHoiSI4w/pA5BJ6TPV5EwTx1evXjGRBgAAiDmqxedE+ag2XyxqySZi0uO0ZO+KNPG79o5Sw9wpTPpzEDJlYvHT1UWr+VmfHp752cZd37tH/SPfjaWfC1qifCBqgjgGkT4AmRU/Jtrn+vXrjY8fPzKhBgAAiDHqvOlE+cSmY3QiJjySDGEVW5Y0cUf83CwfHsd0XHa6xuXys69JlE342gV3py47FpO+dtALWqJ8IA74fRwifQAyLX7qmkA+fvyYCTUAAEBMUQ0+R/goSjc268/YT3QUfRNGpIlLeJSSkOZlWqiXq7te9YgcYVMca7yfHNU8X7N8WFd9n0AWyD4taBffN3IeHbtWWTRA2DjRPmd+RfsgfQAyLX0WNYlU61cVh2RiDQAAEC8UjTs3N2elT6zWn7Gf6HhIjZMgIk26xI+rjo2ER1zHqPn5Nnq1n3fkjyKlCl7CRmOpekaXLe4PT/u0sd8Jctx9kz57n3Zd0RWx3W+QfiR5XMfjhWQQ0gcAxhA/u5pI3rt3j8k1AABAzHjx4oUVPrFbf8Z6gtMjyqeQ9vceS/w8r670bD/fHbFzPkDwdKaLhdDFzI8FbXOBnXe/TvNnsd1nkH6UztUV7fPu282ozhEASLT0mXGKQpoikUywAQAA4oGicL/44gvbon0R6TOKyHhWXY8y2sYdZaQ/x3m8nNbqGz26kI2Mvm9YRax9kT5E+UAM8SvaB+kDAM1tgxbuAAAA8aKtRXssfUGsJzcqGtwhIp5XV8J8/65on6eHF2Gklk38ucu1WaV0DRv54y17/OsCFsaCligfiCt+RfsgfQCAFu4AAADxQtG3jvBRNO4s0mcEnKiVDuESVBHhfnSlQT0/WEzSBFGfd75c3bosztyd0mXE0GXh5oqkWlRSa2LpQ5QPxBg/on2QPgDgiJ8VWrgDAADEgzt37sSuRXtipI86T3UIiidHtSg+x2WB4w5RssGkM17ShygfiDt+RPsgfQCgTfwc08IdAAAgWuLaoj1J0qezI1UIxYR7fI5C5+c42mfCGTPps/ep7oqiYB9B/I7xCaN9kD4A0CZ98rRwBwAAiA5F2964cSOWLdqTJH0qUdbzsdws13JJad2eRemjiB6PKJ88YwpxY9JoH6QPRHAfLpiGCkJpwO3owcxls4VCEmrdpVT8VGjhDgAAEA3lcjm2LdqTI30uJ5WR19Jx1xa69fTwjMlmjKRPd5RPrDusQcaP83eNFXe0z+JXjVmkD8Tm3tu8147cCOCyY+ROVA9nMix91ML9d5pwbm9vMwEHAAAIiaOjo8bnn38e2xbtyZE+5epJ+6QyrNbhnp/F1QKdyWY8pA9RPpDMY308UYn0gSAxUa3PjvbH6fjo4uTmk+oyYxqa+FmlqDMAAEC4tBVvriRivhBf6dPZaSpK6eN+4slEMybShygfSOKxPqasRPpAECia1aNhweQ8O9qP8r6dMfFT08TzwYMHTMQBAAACZn19vb148zTSZxLp40rvul0+WIjic6hWgTuMnUlm9NKHKB9I9vE+urBE+oDfSMq4o2pdNezOnfp6aybtq51ytXQpizof0Lj/fVT37oxJn1yTP2oC+vbtWybkAAAAAaHmCV988YVN60pMWnt8pY/qA3ROIAsRTorbPsfhKZPMaKWPUxD3xFUQd4dxhMQc72NIS6QP+HtvO1joVbfnVrm6O8o99/aXB/mu5gvt9X6o9ROG+FnXBHRubo40LwAAgIBYWlqyUT6JyjCJ7Qdzh5vfLFcjaYPmPNH8ywT2yVGNCWa00mfS1tcA8TjmR4v2QfqAr/c1V606251ykqYJRv64mzD8hSJjH6j0mVL3EE1EHz9+zMQcAADAZ169emWFz7maKSB9/JiUlqsl95PHSD7HZUva9olrIoo1pVX6TNr2GiA2x/yI0T5IH/ADRa+qC6WHlKn41XrdpIN5RPyQ6hW4+FnQZFTdRPb29pigAwAA+ITSuq5fv27TulYTN0eI6wcznURctQEikT5dreMJU49S+hDlA+k67oeP9kH6wKRI6twsHx57CJ813++dzXulO5pIsun2lwdcr4MVP5uakObzeSbpAAAAPnH//n0b5ZPIrJ9Yf7iuApEThJ2P9US0OTl1T47V6YSJZTTShygfSN1xP0K0D9IHJr+nVje6u2xV1wN8v4JXVy/2RaDSR2lep5qYvnjxgok6AADAhGxvb1vhc6HmCUgfn5kvV7eiTPHqrit0eMykMjrpQ5QPpPPY/7TvOq5rSB/wG/MQw13HJwQB06MdfIF9Eqj4Wdbk9OrVq42joyMm7AAAAGOi5gg3btyw0mctsXODOH+4m0+qy+7JogpFRjZBLldLTCijkT5E+UBqj/2vGnmPaJ8C0geClC9KtQorctWdJq2C0eyTwMXPjiaod+/eZdIOAAAwJg8ePLDCJ9Fzl9h/QNNNJIJoH68Jsl9FLmF06SPB44qGOFv6q8Y0YwfpOP4/7bqO7zrSB/wi6ocYTkt3on3ClT4zn3322TeaqG5sbDBxBwAAGJE3b95Y4fPHJnmkT5BPCL1qAgTc+lUdRojyiY/0UQqXUrlckRDsD0jP8T9EtA/SBya4j65F/RBDD2zi0JEzY+JnxaZ57e/vM4EHAAAYkq+//lrduqz0WU/8nCAJH9Id7SMho+5eQbyXwt3dBaSJ8olW+nhG+Rw02B+QsnOgf7QP0gfGlj7uLpQRPMToivZp3se5r4Yifiq2m5fqEjCRBwAAGMzS0pIVPqmo6ZuID2nat3dF3hye+l3fxwifZ0f7hKHHR/oQ5QOZOQcGRPsgfWDs+5q7Nl65NhuJfIq4I2dGpU+rm9ejR4+YyAMAAAxAadGO8Pldk9lUzAcS86SyXC26J663yofnfk0aVfOgK6KoiWr7MHGMTvoQ5QPZOg96R/sgfcCPe2eURZQ9OnltsI9CET8LTj0CU5+ACT0AAIA36nqptGhH+hRTMxdI2OS10hWFcxkBNFH7NHUJUwqX+7XVop3w8+ikD1E+kLnzoE+0D9IHxrxvbnS2aa+uR/hZCmG3jIeW+FnXBFb1CVSngIk9AABAJ0qDVjq0I3wqqZoHJHACW/FIvxIno0b9mBoD3ulcRviE1c4WvBe0i3vfVlxRD6dE+UD6zwXvaB+kD/hyz3xeXYnqs5hUbVq3Ryl+aprIqk4Bk3sAAIBOHj9+bIWP0qJT5QGSOYl9Vl3vIX5MrR+FkKsDV59JZ8lIoh6voa4iRPhEK32G6WYEkEZ6RLgVkT4w1v3SXcQ5wjo67vpCirBlH4UqfWad+gS0cQcAAGjD1Z59IXVzgAQ/vSyamj495U/n08Rhfo8aAzGSPgM6GQGk+nzwqGWF9IEx75UncSji3Po8rqYM7KPQxU+RNu4AAAB/QWnPN27cSE179lRJH6Hiy33SvUbjyVHN725gMIn0IcoHsotntA/SB8aSPp0ds6KWPu6HNeyjSMQPbdwBAAAc7t+/b4VPLbX3/jR8CaVyKSVrXNlDS/a4Sx+ifCCD50RXtA/SB8aQPq70rl6pz2GgtGl3Iwb2USTSZ5o27gAAAOlsz55a6WNx6gUUjQBy1zFoK9Ds/F1JkUJMABMgfYjygQwyKNqHMYKhpE+5uuO6D0Z2PVWUkbsGH/soMvGz4ExyG69fv2biDwAAmUNpzp9//vkn5364kur7PpMfiLf0IcoHMnxe9In2YXxgGNTYwCV9SpEJqOcHi+5IW/ZRpOJnTRPdL7744hP1fQAAIEuojs/c3JyN8tlK/T2fiQ/EWvq8b6SuejrAsPSL9mF8YCjRctmt8i+i5dnRfmSfpbvzZoV9FLn42dWEVxNf6vsAAEBWWFpassLnuEnqu3Yz6YEYS59Pu4wNZP7c6BHtw9jAMNws13LuOjqqrROJ9OlqH19NdSh1QqTPVJMTTXw1AWYhAAAAaadcLlvhc57mOj5IH0iG9PmqkWdsIOs40T7nSB8YW7a4OnhFUdfH6bbZUWNPdfjYP7EQP7NOAcvGixcvWBAAAEBqefPmjRU+YjEz93omPBBP6UOUD0Dr/PiqUUL6wLi46/qo2UHUn0FNFdg3sRI/BTsJ1oSYhQEAAKSNo6MjU8fOud+tZ+o+z2QH4iF9PtWJ8gHwZumgMdU8R87apOgZ4wLDcvvLg7w7ykY/C/H9Z5RWFpeC0tBT/KxrInz9+vVPmhizQAAAgLSgunX5fN5G+GQuuICJDsRD+nzVKLRSWL5qFBkTANc58q6xfFnUucm7xipjAqOg6J6oCjp3RRo9PTyLqq4QDBQ/prCzJsYUdgYAgLRw//59K3xOm0wjfQAAACBVeEX7NFkL+n1VP8jjfUvsk9hKn2lb2FkTZBYKAACQdFSvzhE+F03ymby/M8kBAABIP13RPqaD1sFiYKKpXJu9VT48J8onceIn50yMG+vr6ywYAAAgsbx9+7bx+eef2zo+xcze25ngAAAApB9PCdP88+3ywUJA71UPUzKBr+LHFHbWRFkTZhYOAACQNFSf7vr16zbKZyvT93UmNwAAANng5pPqcpeIUZHl59UV34TPlwd5RfSQ1pV48bOhibI6nVDYGQAAksTXX3/dmJ+ft8LnuEmmo4yZ2AAAAGSI3LPquoeQERvf/fJgeqLXLlfXPDp1RdImHnwRP6aw840bN8wEmoUEAAAkgbt377YXbp7J/P2cSQ0AAEDGxE+5uuElfhShc7NcXR217o5TsPmkh0zaoY5PYqXPlPOElI5eAACQCB48eGCFz7nq1HE/R/rEHj11bU6Yi3oyO1+ubuWeHNVaNCfSzhPbkuonMF4AADCCqCl6ReW0Ur50j3leXfGK/pHEUaqY7ks9Urla0UOMdeLFz4zzpLRx7949FhQAABBbyuVye6euRe7jSJ9Yix49ac09O9rvM5HufkJ7WTSzdPvLg8yHsAEAINiHED/PDxZz5cPTIe8x5yP9ro91giBy8aOOXr/TRPrRo0csLAAAIHa8evXKCh/BHATpE+8nrwOemg5GT2ibCxTC6QEAEOyD0L1CtXjcnb3GRdKMhw+pFD+LTf5IK3cAAIgbb968aW/NvsZ9G+kTS9Tt5Gb58NiPCXd7bQbVWWB8AQAQ7EPch2bmn1Y3xxkXRxhVdC/j+Eq1+Cnap6jb29ssNAAAIHL29/dNp0nn/lThfo30iSWqizDgCeuJU3SzaELxLSqcqZSDy/SDBjUVAAAQ7L5IseY9ppXm5pHSZe5Zl/eeCg8XMid+TCv3q1evNvb29lhwAABAZHz48MF0mHSEz37WW7MjfeIqfJRa0OcJ8rD1I/SEVukGfZ7Q0j0FABDsCHYAP8TPjibY169fbxwdHbHwAACA0FFHSXWWdIRPvck092ikT/yepJara54Lh2dH++MWC3WKkW70Ej+MOwAg2BHsABNKn1Yr97m5ucbXX3/NAgQAAEJlaWnJCh91mJzl/oz0iZ/wuXx63LVg0MLElwVO7yfaJcYfABDsCHaACcXPtG3lPj8/j/gBAIDQuH//vhU+503y3JeRPrFDT4rdT4klaCRqfH6ffNfT6KeHF7fLBwvsBwDIhPBBsAMEKX5mrfi5e/euCbVnMQIAACEJn4smy9yPkT6x5Fa5utu1APFZ+LQWJOVarntBcnhK+gEApB0EO0Ao4ifnPGlF/AAAQKA8evQI4YP0ScQiJN+dYlBdD/I9TRFSnkIDQMZAsAOEJn7yTX5nxQ8LEwAA8JvHjx9b4fNHhA/SJ+aLkMN6x6LgyVEtjPc1rXddLYZZjABAWkGwA0QnfhR6zwIFAAACED5ihfsu0ie26Amze0GghUlIC6AZ06WGxQgAZAAEO0Ak4mfRCblH/AAAgC+sr6+3C58i91ukT6xpLgAqnbUlqrthvv/80+pmZyHTw2P2CwCkDQQ7QKTiZ9kJvW88fPiQBQsAAIzNxsYGwgfpkzTpc3jasRB4frAY5vt7LUb0M/YNAKTrWotgB4iL+FFIPgsXAACYUPjwAA3pE3/c9SVU8DOSxdCTo5rrCTTGFABSJn0Q7AAxED9FO1lH/AAAwChsb283Pv/880/OfWSd+yrSJyGLkOqaS7ZUsvw5AAACEi4IdgDEDwAAIHwA6RMu7uKeN8vV1UgWROWDhSiKmwIAhCJbEOwAiB8AAEgkr169Qvggff7Cd788mJY4UQteI1T0VNVSru7o5yqeebtcm43D51VNiQ7p86S6HI30qc12LkQOTzkRACAtINgB4i1+Hj16xMIGAAC6cNXwQfhkVfqo7a1C5N0CZRBO696SRFFUn12FPKPoJONFx/g8PbzgRACAtIBgB4i1+Pkj7dwBAMCNqy07wier0qc5aS7cenp4Nors8ZA/51G1znUXFo0yAsk9jpwIAJAWEOwAsRY/6up1gfgBAACLUn/p0pVx6XOzXMvlnh3tTyJ7PDgJu5uLE23UlnJQy8ViIYL0AYAUgWAHSIT4+Z0m93fv3m18/PiRRQ8AAMJHFLlPZlD6KCzfic7pIW8OT+efVjeV8iWJ06JcLaimj1u0eBDagdUlrkKWThbTSpiUAwBIKQh2gESInzziBwAg2yjiE+GTceljRM7TwwsvWaNCncOG7Ju6CpcCyFseNf8upO9TiUP7Xnc7Y6VCcCIAQFpAsAMkSvyca7Kfz+cbX3/9NYsgAIDsCR+l/C5zX8yg9Mk9r654CponR7Vxn9pqAu7u6hKm+HG6if1FXD2tbkYm0zrqHFV3OREAIDXSB8EOkCTxM9vkVBP/+fl5xA8AQMpRZOfS0hLCJ+vSx9Tw8Y7wWfPl9Z9Ul3u8fiFYkWXSzjrqCkW0INoJYlwBAGIhfRDsAIkWP0dHRyyMAABSKnyU0usIn3OET0alj9OS/cTd8cTvJ7V6AutO99Kfgyz4ab6bSzZFUWDU/b2jrHcBAOC7bEGwAyRR/Ew3qWshcP369cbe3h4LJACAFPHhwwcj9tuET577X0alj0dYfmCh+bfLBwtuCRN0+L2e9Eb5BNoUuKbGBACkGAQ7QKLFT00Lgs8///zT69evWSgBAKQAifwbN25Y4XOK8Mmw9HHXP3CoBCxBSmGmed0sV1fdUUyqNRTiIqQeh7QHAIBgr3UIdoCEip+pJhXbzeXFixcsmAAAEsz29nbjiy+++ORc1xXROcP9LsPSxz1JV0i+ntgGPjl3dXqRGAnqvfR9bj09PItiMdK1CAlZOAEAhAWCHSDx8mfNip8HDx6wcAIASCAbGxvtLdl3Jfa5x2VY+vSI8imk8b27oouUhhBwS2GlNkQlmwAAwgbBDpAK8VNs8kctFtTpRQVAWUQBACSDR48etQufDe5rSJ+ubitBRtt44Y4yCrLLitdiRH8OalGg91OtIhYhAJAlEOwAqRA/i07BT1MAVIVAWUwBAMQXCfp79+5Z2SNxX+R+hvQxdEmJ59WVMN+/K9qnuTgIMrWsu95DkydHte9+eTDtt/DxLI79rLrOwQ8AaQbBDpAa8ZOzLd1VCJTOXgAA8eTrr79u5PP59g5di9zHkD4GiQ73JNlv+TGciDk87RRPwT4R1tNft4xRhJNfXWbMuD45qnULn6N9DnwAyAIIdoDUiB919jrWQkIFQVUYlAUWAEB8ODo6cnfoomsp0qdjUl50T8ij+BweEibw3EMvKaMn0TefVJcneV1FLnU9cXY6yEQh1AAAogLBDpAa8TPlFAKlsxcAQIx48+ZNe4cuCXrWm0ifLumzEYcno11PhEOYsGux4C1nLt9f8mZE2TMzX65ueb2ek9aQ56AHgKyBYAdIlfzZtOJHdSMo8AwAEB3lcrm9YPMOHbqQPr1kSyXKej6Wm+VaLopi0k5awI6n+HFa10uE3S4fLPT63KY9sdeT5rbX8OupNgBA0kCwA6RO/Kw0ubAFnvf391l8AQCEiOr3qLNim/ApcX9C+vSWPm5ZEXAtnX6LAvfEPdRxUAczdZfpLW46hNQwv2c7kfHEGQCyDoIdIHXiJ9/kxNb5ef36NQsxAIAQUEH9ubk5CjYjfUaQHZpot02ao5wwu6VL2O9v2v262sePixFDEQk0AIC4gmAHSJX4mW6v8/P48WMWZAAAAbKxsdH4/PPPbf2eehMediF9hpE+nV2zopQ+zQn+eZTSpzUmzw8WlXIwvuyJJkUOACAJINgBUid/1qz4uXv3rkk7YHEGAOAfqp/24MGD9nSuLer3IH2GFxyuUPleofVB44T+d7SOj3psnJSzolmc9EgpMHUqLv+uRFoBAMAI9x8EO0CaxM+ik2Zg2gYr/YCFGgDA5Kgdez6ft7JH9dRWue8gfUabdHfXWChE8TkkTNzdVzhAAADSD4IdIDXiZ8ZpF2zSD169esWCDQBgAlzt2M+aLHC/QfqMzPzT6mbnxLoaiTk0T3zbJ/nNyT0HCAAAAECixM+Uk3Zgnko/fPiQtu4AAGOgOmlt6Vw1iXXuM0if8WRLuVpyF8OM5HOouGfnk90KBwgAAABAIuWP2rr/kbbuAACj8eHDh/Z0LrHJfQXpMxFqg+uqk3AeifTpah1PrQYAAACABIufnG3rrnSvFy9esKADAOiD0mLb0rlUJ401MdLHJ+Hi6uAVdieU218ezLjrN9B6FwAAACDx4kfpXpvt3b30FJvFHQDAX1DXw/v375POhfQJjvlydSvKFK/uukKHxxwcAAAAAKmRP8u2u9e1a9ca29vbLPQAAJq8ffu2MTc3196da437BtLHd24+qS67I21uf3mQD+O9TZTP08ML1/uXODgAAAAAUiV+1N1r3z7J1lNtijwDQJYpl8sm/dW5Lp7QnQvpEyi3yof1KKJ93FE+t54ens1972CKgwMAAAAglfJnzRZ51tNtPeVm8QcAWUJprnfu3GlP51LXQ9bASJ9gyZWrBXe0T5NikO95u3ywQJQPAAAAQObET94WeRZ62s1CEACywOvXr9uLNZ8p/ZX7AtInNNzRPhIy6u4VxHupULO7gDRRPgAAAACZET8q8lyx4kctimntDgBpxaNY8z7FmpE+oWPat3dF3hye+l3fxwifZ0f7HpFFBQ4KAAAAgEzJn4It8nz16lUT9UOtHwBIEypef/369fZizatc/5E+kaGULreMuVU+PPerjbsKN3dFFDVRbR8OCAAAAIBMih8Ved61T8Cp9QMAaUC1e+7evdse3XPcJMd1H+kTB/FT6YrCuYwAmqh9nLqEKYXL/dpq0U5aFwAAAEDm5c+yU+PCLJAePnxoUiJYPAJA0tjY2Giv3aNoxiLXeaRP/MXPJSejRv0oPaxHOpcRPkr34mAAAAAAgOY23WTDih+lRCg1gkUkACQB1SZTjbK26J4davcgfeIrfp5V13uIH1PrRylZ6sDl9W9NfaBytWQkUY/XUFt4InwAAAAAwEP+LDSp24XTvXv3TKoEi0oAiCuqSfb555/TmQuSI32M+ClXi6amT0/501H7pz7M7zlscAAAAAAAwAD5s+YUPm1cu3bNpEywuASAOKEaZPPz8+3RPYpWnOYaDomQPkLFl/uke43Gk6Oa393AAAAAACDV4mfWaW9sFlR37tyhvTsARI5qjj169Khd9ig6cYHrNiRO+rTkT/lgQSlZ48oeWrIDAAAAwATyp9he6FmLLQo9A0AUrK+vq+bYp7Y27GtcpyHx0seiwsuXaV/VXUfmeBZodv6upEghdjYAAAAA+CB+VOh5q73QsxZfLEIBIAzevHnjTuVSFOIs12dIlfQBAAAAAIhY/uSb1OzCS4swLcZYlAJAECildGlpqV32nFCoGZA+AAAAAADByp9Ck1O7ENOi7OjoiEUqAPiCUkgfPnzYLnvOm5S4/gLSBwAAAAAgHPEz5XT5+p0WZWqZ/Pjx48bHjx9ZtALA2Lx48aLxxRdffGoTPpt05QKkDwAAAABANPJnxl3v59WrVyxeAWAktre3G3Nzc+3RPUolzXGdBaQPAAAAAED08qej3k8+n6feDwAMZG9vr3Hnzp122aPU0QLXVUD6AAAAAADET/501PvRYg75AwBessdVpPncSRmd4loKSB8AAAAAgPiKH9X7KTU5Q/4AQDseHbkunLo9M1w/AekDAAAAAJBw+aMn/Cx+AbKFOvzdv38f2QNIHwAAAACAFMqfdSd9o9XmHfkDkEnZIyrIHkD6AAAAAACkS/5MI38AssGHDx8aDx8+9JI9s1wPAekDAAAAAJBu+bPppHe05M/bt29ZLAOkILJHsufzzz//hOwBpA8AAAAAQHblz4xb/qjmz+vXr1k8AyQMRez1SONC9gDSBwAAAAAg4/Jnq13+3Lhxo7GxsdH4+PEjC2qAGLO9vW1kLbIHkD4AAAAAANBP/ijta62929f169cbjx8/NvVBWGADxAPJWEnZubm5dtGjWl0bFGgGpA8AAAAAAAwSQMUmdbugvHr1auPBgwemXgiLboBo+PrrrxvlctnI2DbZc9pkVV36uHYB0gcAAAAAAEaRP4tNdttTR1T0+c2bNyzCAUJCslXS1VWcudakwHUKkD4AAAAAADCp/Mk5dUJadX/y+Tx1fwACREXV7927567Xs9Mkz3UJkD4AAAAAAOC3/FHR5/X2uj/Xrl0zUQj7+/ss1AF8iOp59OiRO4Xr3Om0N8t1CJA+AAAAAAAQhgBaabLfHoVA9A/AeLx69apx9+5dd1TPiVOvZ5prDiB9AAAAAAAgCvkz63QNakX/fPHFF5+I/gHoj84PnSeuqJ4LJ5VygesLIH0AAAAAACBOAojoH4A+2HbrOi+I6gGkDwAAAAAAJFH+eEb/3L9/3xSnZfEPWSzKrONfNbCI6gGkDwAAAAAApEUALTsdhxrtxZ+tACICCDImeojqAaQPAAAAAACkTv7MOAvdWvsC+OrVq6YttQrZIoAg6bx586aX6Dl1OnDluR4A0gcAAAAAALIggOoIIEiD6PEoyIzoAaQPAAAAAABkXgCp/k+plwBS0dsPHz4gFyBWbG9vI3oAkD4AAAAAADCpABLz8/ONR48eNfb29pAOEDpHR0eN9fX1xtLSkhGSiB4ApA8AAAAAAEwugI7dAkjRFaqbojSwr7/+GikBgUXzPHz4sDE3N+eWPA1HTG4gegCQPgAAAAAAMJkAmm6y4rS3PnMvwPP5fKNcLhMFBEFG85w7XeiKqknFeQmA9AEAAAAAgGAkUL7JWr8oIC3e9/f3kRnQE9WKUrTYENE8C5x3AEgfAAAAAAAIXwD1jQJS6+y7d++aSCB1WUJ2ZBdFgkkGqkD4jRs3vCQP0TwASB8AAAAAAIixBMo7tYB2vSSQTQdTUejXr1/TGSylfPz40Ui+x48fG+nnka5lJc++EzVGNA8A0gcAAAAAABImgWadSKAtr65gQqk9Sgl78eKFEQUSBoiTZKH9trGxYVK1JPW89nOTEyciTJE8Oc4PAKQPAAAA/P/bu3uchIIoDKCtW2ED1JSWtnSUli6BHVi6BENlaflKS0tLS5dAKx/MwITwQBOJ/Jzi1O+9gUwyN9+9A3BZRaCbhdHCtKQ85rsKBJkNNBwOl0mRzH2ZzWaKKycgc5qS0MrvkoHLPbN4qq78zrdpA/T/B0UfAADg2g4oq5aw+4XHUiiY9xUSBoPBciZMig650js3PinGHGfIctI7mcWUFNae9E5b4HkqrX1ateA/91SLAAAAnPShZdUWVhNBz7tuCttuEUsyKO1FKQgljaJVbL+kp+rcncxYyvr9oLjzUeY11QSPNi04tf3TIgAAAGd5mFmlgu6a9rDPA0WK9fDo2i4WKXbEpV4rnwRU/cbMSqrtWFmDnqHK276a9qyJ9A6c0T5pEQAAgIs65GySQZMmHdT13SDWJ0WRajwer4tEuWq8FlFax0gS5WrzXc9KO1t9n0ibW/u+v/nO0kLXNamdh7J+kjtw7vuhRQAAAK7qELRKCI1KcaOmhLpDM4TOWNeYlmvRRxI7cAX7nUUAAADYcVjaJIZGZWbNtPGyVUyp3v64YPPe85zXrfe5a95VQgdY+gZ16LFfC3dAWwAAAABJRU5ErkJggg==", - fileName= - "modelica://SorpLib/Resources/Images/MassTransferDiffusionFlow.png"), - Line( - points={{-50,0},{-50,-44}}, - color={0,0,0}, - thickness=0.5, - enable=inputChoice == "dx")}), Documentation(info="<html> - <p> - The Mass Transfer Diffusion Flow model connects the flow and the diffusion resistance in series.<br> - The Mass Transfer Diffusion Flow model is a combination of - <a href=\"modelica://SorpLib.Components.MassTransfer.MassTransferFlow\">SorpLib.Components.MassTransfer.MassTransferFlow</a> and - <a href=\"modelica://SorpLib.Components.MassTransfer.MassTransferDiffusion\">SorpLib.Components.MassTransfer.MassTransferDiffusion</a> - </p> - <h4>Assumptions and limitations</h4> - <p> - The model has no storage volume. - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html> -")); -end MassTransferDiffusionFlow; diff --git a/SorpLib/Components/MassTransfer/MassTransferFlow.mo b/SorpLib/Components/MassTransfer/MassTransferFlow.mo deleted file mode 100644 index c1cb6ab170add5d1f37d1efbe9575f0ec917905b..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferFlow.mo +++ /dev/null @@ -1,68 +0,0 @@ -within SorpLib.Components.MassTransfer; -model MassTransferFlow - extends Partial.PartialMassTransfer(final computeTransportProperties=massTransfer_flow.computeTransportProperties); - - /***************************** Mass Transfer model ******************************************/ - - replaceable model MassTransfer_flow = - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp - constrainedby - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp - "Mass Transfer Model" annotation (Placement(transformation(extent={{-32,-70}, - {-12,-50}})), choices(choice(redeclare model - MassTransfer_flow = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantCoefficient_dp), - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantSpecificCoefficient_dp), - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.MassTransferPhenomena.Laminar_dp), - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.MassTransferPhenomena.DarcyPorousMedia_dp - "Mass transfer in porous media following Darcy's law"), - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.Record.FlowCoefficients.FlowRes_Lanzerath_des - "Coefficients Flow Resistance adsorber -> condenser (Lanzerath 2015)"), - choice(redeclare model MassTransfer_flow = - SorpLib.Components.MassTransfer.Record.FlowCoefficients.FlowRes_Lanzerath_ads - "Coefficients flow resistance evaporator -> adsorber (Lanzerath 2015)")), - Dialog(group="Mass transfer model")); - - MassTransfer_flow massTransfer_flow "Mass Transfer model for flow resistance"; - -equation - - if noEvent(valveOpen) then - vlePortA.m_flow = massTransfer_flow.beta*(vlePortA.p - vlePortB.p); - else - vlePortA.m_flow = 0; - end if; - - annotation (Icon(graphics={Line( - points={{0,-2},{0,-46}}, - color={0,0,0}, - thickness=0.5), - Bitmap(extent={{-81,-46},{81,84}}, fileName= - "modelica://SorpLib/Resources/Images/MassTransfer.png")}), - Documentation(info="<html> - <p> - The Mass Transfer Flow model extends the <a href=\"modelica://SorpLib.Components.MassTransfer.Partial.PartialMassTransfer\">SorpLib.Components.MassTransfer.Partial.PartialMassTransfer</a>.<br> - The Mass Transfer Flow model describes the mass transfer resistance caused by friction in tubes and connections or an inter-particle mass transfer within the packed bed. - </p> - <h4>Main equations</h4> - <p> - The mass flow <code>ṁ</code> is proportional to a pressure drop <code>Δ</code>p: - <p align=\"center\"><i><code>ṁ</code></i><sub>in</sub> = <i><code>β</code></i> <i><code>Δ</code>p</i></p> - For the mass transfer coefficient <i><code>β</code></i>, different correlations are implemented based on the partial model - <a href=\"modelica://SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp\">SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp</a>. - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html> -")); -end MassTransferFlow; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantCoefficient_dp.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantCoefficient_dp.mo deleted file mode 100644 index 4d2f828164305d8c4b18800d028fc0e7750f8cc3..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantCoefficient_dp.mo +++ /dev/null @@ -1,34 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena; -model ConstantCoefficient_dp - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp( - final computeTransportProperties=false); - - parameter Real constantCoefficient(final unit="m.s")=1e-7 - "Constant mass transfer coefficient (dp)"; -equation - beta = constantCoefficient; - annotation (Documentation(info="<html> -<p> - This simple transfer model calculates the mass flow based on the pressure differnce with a constant transfer coefficient. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"><i><code>ṁ</code></i> = <i><code>β</code></i> <i><code>Δ</code>p</i></p> - <p>where <i><code>β</code></i> is a constant parameter</p> -</p> -<h4>Assumptions and limitations</h4> - <p> - In general, the mass transfer coefficient depends on fluid properties. Thus, a constant coefficient is only an approximation. - </p> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end ConstantCoefficient_dp; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantCoefficient_dx.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantCoefficient_dx.mo deleted file mode 100644 index b69ec2957356e9f0e859edc0b37178632f7906ab..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantCoefficient_dx.mo +++ /dev/null @@ -1,31 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena; -model ConstantCoefficient_dx - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dx( - final computeTransportProperties=false); - - parameter Real constantCoefficient(final unit="kg/s")= 1e-7 - "Constant mass transfer coefficient (dx)"; -equation - beta = constantCoefficient; - annotation (Documentation(info="<html> -<p> - This simple mass transfer model provides a constant mass transfer coefficient. -</p> -<h4>Main equations</h4> -<p> - The mass transfer according to the Linear Driving Force apporach is determined by the following equation: - <p align=\"center\"> <i><code>ṁ</code></i> = <code>β</code> (<i>x</i> - <i>x</i><sub>eq</sub>) </p> - where <code>β</code> is a constant mass transfer coefficient.<br> -</p> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end ConstantCoefficient_dx; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantSpecificCoefficient_dp.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantSpecificCoefficient_dp.mo deleted file mode 100644 index d199fe923323cd676b78323eb41987fcb1a373e3..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantSpecificCoefficient_dp.mo +++ /dev/null @@ -1,34 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena; -model ConstantSpecificCoefficient_dp - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp( - final computeTransportProperties=false); - - parameter Real constantCoefficient(final unit="m.s")=1e-7 - "Constant mass transfer coefficient (dp)"; -equation - beta = constantCoefficient; - annotation (Documentation(info="<html> -<p> - This simple transfer model calculates the mass flow based on the pressure differnce with a constant transfer coefficient. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"><i><code>ṁ</code></i> = <i><code>β</code></i> <i>A</i> <i><code>Δ</code>p</i></p> - <p>where <code>β</code> is a constant specific mass transfer coefficient and <i>A</i> is the mass transfer area.</p> -</p> -<h4>Assumptions and limitations</h4> - <p> - In general, the mass transfer coefficient depends on fluid properties. Thus, a constant coefficient is only an approximation. - </p> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end ConstantSpecificCoefficient_dp; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantSpecificCoefficient_dx.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantSpecificCoefficient_dx.mo deleted file mode 100644 index de2e406ad1c40d23a0da4a08060399d37de2ef85..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/ConstantSpecificCoefficient_dx.mo +++ /dev/null @@ -1,33 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena; -model ConstantSpecificCoefficient_dx - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dx( - final computeTransportProperties=false); - - parameter Real specific_linear_Coefficient(final unit="kg/(s.m2)", start = 1e-7) - "Specific linear mass transfer coefficient (dx)"; - - parameter Modelica.SIunits.Area area(start=1) "Mass transfer area"; -equation - beta = specific_linear_Coefficient*area; - annotation (Documentation(info="<html> -<p> - This simple mass transfer model provides a constant specific mass transfer coefficient. -</p> -<h4>Main equations</h4> -<p> - The mass transfer according to the Linear Driving Force apporach is determined by the following equation: - <p align=\"center\"> <i><code>ṁ</code></i> = <code>β</code> <i>A</i> (<i>x</i> - <i>x</i><sub>eq</sub>) </p> - where <code>β</code> is a constant specific mass transfer coefficient and <i>A</i> is the mass transfer area.<br> -</p> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end ConstantSpecificCoefficient_dx; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/DarcyPackedBed_Spheres_dp.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/DarcyPackedBed_Spheres_dp.mo deleted file mode 100644 index f1b4c6dd42a20a67fa5c8983c30299035d8e170c..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/DarcyPackedBed_Spheres_dp.mo +++ /dev/null @@ -1,51 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena; -model DarcyPackedBed_Spheres_dp - "Mass transfer in a packed bed with spheres following Darcy's law" - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp( - final computeTransportProperties=true); - - outer TILMedia.Internals.PropertyRecord properties "Property record"; - - parameter Real eps_b(start=0.32) "Bed porosity"; - parameter Modelica.SIunits.Area area "Mass transfer area"; - parameter Modelica.SIunits.Length Dp "Diameter of spheres"; - parameter Modelica.SIunits.Length dx "Bed thickness"; - final parameter Real k_D( final unit="m2") = (Dp^2 * eps_b^3)/(150 * (1-eps_b)^2) - "Permeability of bed"; -equation - beta = (k_D/properties.transp.eta)*(2/dx)*area*properties.d; - annotation (Documentation(info="<html> -<p> - For a packed bed of spheres, the convective flow in a porous media can be described by Darcy's law (1856) with a correlation for the permeability proposed by Ergun (1952). -</p> -<h4>Main equations</h4> -<p> - The convective flow can be expressed as: - <p align=\"center\"> <i>v</i> = - <i>K</i> / <code>η</code> d<i>p</i>/d<i>x</i>. </p> - where <i>v</i> is the flow velocity, <i>K</i> is the permeability, <code>η</code> is the dynamic viscosity and d<i>p</i>/d<i>x</i> is the pressure gradient, <br> - This can be translated in the following equation for the mass flow: - <p align=\"center\"> <i><code>ṁ</code></i> = <i>K</i> / <code>η</code> * <i>A</i> * <code>ρ</code> / (<code>Δ</code><i>x</i> / 2) * <code>Δ</code><i>p</i>, </p> - where <i>A</i> is the cross-sectional area, <code>ρ</code> is the density, and <code>Δ</code><i>x</i> is the total bed length.<br> - For packed bed of spheres, the permeability <i>K</i> can be expressed as: - <p align=\"center\"> <i>K</i> = <i>d</i><sup>2</sup> <code>Φ</code><sup>3</sup> / [150 (1 - <code>Φ</code><sup>2</sup>],</p> - where <i>d</i> is the diameter of the spheres and <code>Φ</code> is the bed porosity.<br> - For more information see also Bejan (2013). -</p> -<h4>References</h4> -<ul> - <li>Darcy, H.P.G. Les Fontaines Publiques de la villa de Dijon. Paris, 1856.</li> - <li>Ergun, S. Fluid flow through packed columns. Chem. Eng. Prog., 1952, 48(2), 89-94.</li> - <li>Bejan, A. Convection heat transfer. 4th ed. Hoboken, N.J.: Wiley, 2013. ISBN 1118519760.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end DarcyPackedBed_Spheres_dp; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/DarcyPorousMedia_dp.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/DarcyPorousMedia_dp.mo deleted file mode 100644 index abcca47514210c4c0109bc8d6b7a2d46cf6992a7..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/DarcyPorousMedia_dp.mo +++ /dev/null @@ -1,43 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena; -model DarcyPorousMedia_dp "Mass transfer in porous media following Darcy's law" - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp( - final computeTransportProperties=true); - - outer TILMedia.Internals.PropertyRecord properties "Property record"; - - parameter Modelica.SIunits.Area area "Mass transfer area"; - parameter Modelica.SIunits.Length dx "Bed thickness"; - parameter Real k( final unit="m2",start=1) "Permeability of bed"; -equation - beta = (k/properties.transp.eta)*(2/dx)*area*properties.d; - annotation (Documentation(info="<html> -<p> - The convective flow in a porous media can be described by Darcy's law (1856). -</p> -<h4>Main equations</h4> -<p> - The convective flow can be expressed as: - <p align=\"center\"> <i>v</i> = - <i>K</i> / <code>η</code> d<i>p</i>/d<i>x</i> </p> - where <i>v</i> is the flow velocity, <i>K</i> is the permeability, <code>η</code> is the dynamic viscosity and d<i>p</i>/d<i>x</i> is the pressure gradient. <br> - This can be translated in the following equation for the mass flow: - <p align=\"center\"> <i><code>ṁ</code></i> = <i>K</i> / <code>η</code> * <i>A</i> * <code>ρ</code> / (<code>Δ</code><i>x</i> / 2) * <code>Δ</code><i>p</i> </p> - where <i>A</i> is the cross-sectional area, <code>ρ</code> is the density, and <code>Δ</code> <i>x</i> is the total bed length.<br> - For more information see also Bejan (2013). -</p> -<h4>References</h4> -<ul> - <li>Darcy, H.P.G. Les Fontaines Publiques de la villa de Dijon. Paris, 1856.</li> - <li>Bejan, A. Convection heat transfer. 4th ed. Hoboken, N.J.: Wiley, 2013. ISBN 1118519760.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end DarcyPorousMedia_dp; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/GlueckaufArrhenius_dx.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/GlueckaufArrhenius_dx.mo deleted file mode 100644 index 98901b238fa52b102ccf4944bf1c1a7bec5a8923..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/GlueckaufArrhenius_dx.mo +++ /dev/null @@ -1,52 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena; -model GlueckaufArrhenius_dx "Glückauf-approach with temperature dependance dx" - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dx( - final computeTransportProperties=false); - - parameter Modelica.SIunits.Mass m_ads(start=2) "Mass of sorbent material"; - parameter Real Dso(final unit="m2/s", start = 2.54e-4) "Diffusion coefficient"; - parameter Modelica.SIunits.Length r(start=0.001) "Radius of adsorbent grains"; - parameter Modelica.SIunits.SpecificEnergy Ea(start=2.33e6) "Activation energy"; - parameter Modelica.SIunits.MolarMass M(start=0.018) "Molar mass of fluid"; - final parameter Modelica.SIunits.SpecificHeatCapacity Rm=Modelica.Constants.R/M - "Specific gas constant of fluid [J/kg K]"; - - outer Modelica.SIunits.Temperature T "Adsorbent temperature"; - -equation - beta = 15*m_ads*Dso/r^2*exp(-Ea/(Rm*T)); - annotation (Documentation(info="<html> -<p> - This mass transfer model derived by Glueckauf (1955) for spheres is enhanced by an Arrhenius approach to determine the mass diffusion coefficient <i>D</i>. -</p> -<h4>Main equations</h4> -<p> - The mass transfer according to the Linear Driving Force apporach is determined by the following equation: - <p align=\"center\"> <i><code>ṁ</code></i> = 15 <i>D</i> / <i>r</i><sup>2</sup> * <i>m</i><sub>sor</sub> (<i>x</i> - <i>x</i><sub>eq</sub>) </p> - where <i>D</i> is the diffusion coefficient and <i>r</i> is the particle radius.<br> - Using the Arrhenius approach, the diffusion coefficient can be determined by the following temperature dependent correlation: - <p align=\"center\"> <i>D</i> = <i>D</i><sub>s,0</sub> exp ( -<i>E</i><sub>a</sub> / (<i>R T</i>) ) </p> - where <i>D</i><sub>s,0</sub> is a pre-exponent constant, <i>E</i><sub>a</sub> is the activation energy, <i>R</i> is the gas constant, and <i>T</i> is the temperature. -</p> -<h4>Assumptions and limitations</h4> - <p> - This correlation can be used when Knudsen diffusion is the dominant mass transfer regime Ruthven (1984). <br> - For silica-gel, this approach is used by Sakoda and Suzuki (1984) and by many studies referring to it. - </p> -<h4>References</h4> -<ul> - <li>Ruthven, D.M. Principles of adsorption and adsorption processes. New York: Wiley, 1984. ISBN 0471866067.</li> - <li>Sakoda, A.; Suzuki, M. Fundamental study on a solar powered adsorption cooling system. Journal of Chemical Engineering of Japan, 1984, 17(1), 52-57.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end GlueckaufArrhenius_dx; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Glueckauf_dx.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Glueckauf_dx.mo deleted file mode 100644 index 2849c7d5312731c6a95f346aacf80126f284cde2..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Glueckauf_dx.mo +++ /dev/null @@ -1,41 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena; -model Glueckauf_dx "Glückauf-approach dx" - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dx( - final computeTransportProperties=false); - - parameter Modelica.SIunits.Mass m_ads(start=2) "Mass of adsorbent material"; - parameter Real D(final unit="m2/s", start = 1e-10) "Diffusion coefficient"; - parameter Modelica.SIunits.Length r(start=0.002) "Radius of adsorbent grains"; - -equation - beta = 15*m_ads*D/r^2; - annotation (Documentation(info="<html> -<p> - This mass transfer model was derived by Glueckauf (1955) for spheres. -</p> -<h4>Main equations</h4> -<p> - The mass transfer according to the Linear Driving Force apporach is determined by the following equation: - <p align=\"center\"> <i><code>ṁ</code></i> = 15 <i>D</i> / <i>r</i><sup>2</sup> * <i>m</i><sub>sor</sub> (<i>x</i> - <i>x</i><sub>eq</sub>) </p> - where <i>D</i> is the diffusion coefficient and <i>r</i> is the particle radius.<br> -</p> -<h4>Assumptions and limitations</h4> - <p> - This correlation is derived for spheres. - </p> -<h4>References</h4> -<ul> - <li>Glueckauf, E. Theory of Chromatography. Part 10: Formulae for Diffusion into Spheres and their Application to Chromatography. Transactions of the Faraday Society, 1955, 51(11), 1540-1551.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end Glueckauf_dx; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Laminar_dp.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Laminar_dp.mo deleted file mode 100644 index b9c79572f032fe14cc6ab6961a942767115244c0..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Laminar_dp.mo +++ /dev/null @@ -1,50 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena; -model Laminar_dp - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp( - final computeTransportProperties=true); - - outer TILMedia.Internals.PropertyRecord properties "Property record"; - - parameter Real zeta_lam(min=1)=1 "Additional factor to account for nonideal tube"; - parameter Modelica.SIunits.Length L(start=0.4) "Length of valve"; - parameter Modelica.SIunits.Diameter d(start=0.3) "Inner diameter of valve"; - final parameter Modelica.SIunits.Area A=Modelica.Constants.pi*(d/2)^2 - "Inner Cross sectional area"; - -equation - - beta = A^2/(8*Modelica.Constants.pi*L)*properties.d/properties.transp.eta - *1/zeta_lam; - annotation (Documentation(info="<html> -<p> - This laminar transfer model calculates the mass flow based on the pressure differnce according to the VDI Wärmeatlas (2013). -</p> -<h4>Main equations</h4> -<p> - For a laminar flow, the correlation between mass flow and pressure drop can be expressed as: - <p align=\"center\"> <i><code>Δ</code>p</i> = <code>ζ</code></i><sub>lam</sub> * 8 <code>π</code> <i>L</i> / <i>A</i><sup>2</sup> * <code>η</code> / <code>ρ</code> <i><code>ṁ</code></i> </p> - where <i>A</i> is the cross-sectional area, <code>η</code> is the viscosity, <code>ρ</code> is the density and <code>ζ</code></i><sub>lam</sub> is an additional factor to account for a non-ideal tube.<br> - This correlation is implemented as: - <p align=\"center\"><i><code>ṁ</code></i> = <i>A</i><sup>2</sup> / (8 <code>π</code> <i>L</i>) * <code>ρ</code> / <code>η</code> * 1 / <code>ζ</code></i><sub>lam</sub> <i><code>Δ</code>p</i></p> -</p> -<h4>Assumptions and limitations</h4> - <p> - The additional factor <code>ζ</code></i><sub>lam</sub> can be experimentally determined as done by Lanzerath (2015). - </p> -<h4>References</h4> -<ul> - <li>VDI e.V., VDI Wärmeatlas 11., bearbeitete und erweiterte Auflage, Chapter L1, Darmstadt: Springer Berlin Heidelberg, 2011. </li> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257. </li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end Laminar_dp; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/PartialMassTransfer_dp.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/PartialMassTransfer_dp.mo deleted file mode 100644 index bf24e8edb758d748b2cf71003204ab14368d4170..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/PartialMassTransfer_dp.mo +++ /dev/null @@ -1,28 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial; -partial model PartialMassTransfer_dp - - Real beta(final unit="m.s") "Mass transfer coefficient (dp)"; - - constant Boolean computeTransportProperties = false; - - annotation (Icon(graphics={Bitmap( - extent={{-111,-100},{111,100}}, - imageSource="iVBORw0KGgoAAAANSUhEUgAAAd0AAAHdCAYAAABYPaNuAAAAAXNSR0ICQMB9xQAAAAlwSFlzAAAXEgAAFxIBZ5/SUgAAABl0RVh0U29mdHdhcmUATWljcm9zb2Z0IE9mZmljZX/tNXEAADn7SURBVHja7Z1taF1ltsfDMEgRkSBFgoiEIhJEJIhIEBn66dIP86FtEiYdUAKOolOQFESL9EMshQYJJ2ejWGrBjEIpeju0c8sQKI6h3NEiBSteSse5QhWHCeMwzRWReoe55OZ/Tk57zn45r/tlPc/+PfDzQ2zTc569z/6ftZ61/mvo1VdfHQKA/BiaruxsYnZoamk+wt7g1NBUdXVwgmOR3z0d7Lr57z97fBvXBCDHzz+bAJDCB2lPMFETscngYF3cqitN4nd1kw3zTFcv3nzNk8HRLYGeqQt0MMJ1BkB0AXKKThfHt6LDuboYVc/Uxal6wwlBTY+rLRE0ogyA6AL0L64Lwzcj1snq8lb0VyZR7Z/6F5C6IOvLCelrAEQX4ObNX08Jz9ZTqbW06nrWwnTbkyc2hvefvsno4YsRxo9/kxoPvPZ55Pff9cLZm//+T395LA8xXqvvryLjzf3e3HfuP0B0AXyPYCcru2sCm0H0esczJ2sidu+hCzVhe/jNr24K389++6+NnWc3zDNx8rubr/nB6he193HPKx/W3te22bezOkNeqqWo9y2Ocp8CogvgbhQ7Vo9iq8tpFDI1IlSJkMRIoiRxeuL9H50Q1LSFuRFB3/3iSnoRsyJiVW0rNU00DIgugOVItlboNFcrcKqnM/t++N/5/HsbIy+f39hx5FIphbVftE/aL+2b9k9inEJEXK+kng52cZ8DogtQmMiq4CmYqUWyfYqsojMJw33zH9Ui10eXv0U8M+Cxd65vPPT6lzfPk29/+t3+C7VqX6qC50hHA6ILkPXNqsKnervOxX7PXZUelsAqTYogFhsV69xbX3gGiIivbp0JEwUDogsweDQbjNTOZevuTOu9RrGKqhrVwK4UM5WZRmp6+4FzvZ8RN0fB9AwDogvQS9pY1oi1Fp6eRFZFPWOVK7V0JiLmR1pa11Pnwypk6+MsGAEGRBcgchM+e3xbTWjrLk89pYuVnnzkxBoiVQJ05q5IWIVuCDAgugA9C20wU0sdd2ml2BzNPn7qB4So5GfCKs7SGX2PPcQIMCC6UKb0cbBrq3e2qzNaVboSzUI3qej7Fz7ttShrtZ5hWRjmswmILvhzk+1bHK31WnbZ2iOhVQEUZ7PQD8qCyLyjawFWpkVfBDHkAEQX3E4fd18QpRShIlqEFtJErWGKgHX+33UbUi39TPQLiC64cEPVemk19q1z+lhCK69iTCkgLwFWBqUrc45G9EsPMCC6YO4mUj+tooMuPI5VDKXiF4QWij4DVmalq1akyeq12qhHiq8A0YVCbx6d1Sqq7aL6WG0eqjrGpAKsIYcyVcX3cPY7xucfEF3IMbJdHN9yieo4mUfRBJaL4EoBlvqAu/SGXiH1DIguZHuzaB5tF4VRsl9U9MCDHFxFLWpywvrJL97oXHilgsFnj2/jGQGILqQU2daqkK8S1ULZkAmHjkU6Vj/X2uE0jINzX0B0oZ8bo97yM9ept1YVyOqJ5KwWfEdTkTr2/jbOfRk9CIgupCm2evjIho+HMZQNVd4r9dz53Dc4RuQLiC4k3wxq++kgtqryxJIRoN73qz7ztue+9cr+JcQXEF24dRPozFa9iAkPDj1U9HDhvBYg/txXphtte35r4qszX5yuEF02ocSRba0a+Wo7Iws9TPRQ4eEK0B7VNchysoPhxjrii+hCGcV2snq5XWSrSmTEFiAj8dUxjmonaDVCdMHnNPLieLs+20YamVm1AHmKbzDD8wnRBa/ENhjZGkKA2AIUdOar45r2s30Xx3leIbrg8sVV+4+M2ttM/FHrA2ILYEV8aTNCdMHlc9tr7Vp/qEYGKEZ8VTPRptVoXV+WeY4huuDBua2m/dBnC1A8+tK7/cC5Dr7ODFVAdMHJc1sVczCEAMAespfsMNlohXGCiC6YEtzaQIL1du0/eCMD2EaVzonnvTVP5+AgLUaILhR58Ta//da+BSd8Q1bqinNbALfOe9VJ0DblvCeY4PmH6ELeF07feuu+rpEPpsaQjR//hocYgKM89s712lzqNv29y7haIbqQT3Q7keQmpdTUjiOXeGgBeIImeSWaa2CsgehChheq3nN7NOmbr74V028L4GfK+Z5XPmxfaMX8XkQXUrxI08GupJF7im7HKld4OAF4jlr9EquctwqteF4iujBodNumDUhuUgwlACgP6kLQEVKiscZ09SJRL6ILfUW3NZOLq0k9t+rt4yEEUE5UaCWjm0RHK856EV3o4aK0qUxWOwHRLQAIHS216e2lwhnRhQ5ntyNJfbeKbrFvBIAwKqBs015EXy+iC4nFUgmuUpzdAkAn2p71UmSF6ELnYikqkwGgFx5d/radj/MqYwMRXYqlEoqlVCSBhSMA9IoqnNv09a5r7CfPX0S3jOnkmaRiKVylAGBQ1OGQWGQ1tTTPcxjRLX06WWkhiqUAIC06FFmtUt2M6Poe3Y7UmtcplgKAHEksspqsXtMxF89nRNdDwa3sjKtO1gfhgdc+58EAAJmiLFrs8IS6heRzPKcRXX82WWYXMdHtttm3a9WGPBAAIK908/D+0wnp5uCYjr94ZiO6Dke3C8ND09UzcTe4bnzSyQBQBHK2S/Rupq0I0XVTcJPbgUYPX+SDDwCF8mD1iyQzjXUdh/EcR3SdP79V+b6GUvOBBwAL6HhLx1yx57wMTUB0HRHc2bj+2zueOYnZBQCYQ8dc2w+cwz4S0XVwM6eW5uNu3LtfXKm5xPABBwCr6NgraVoRz3dE19YmyvBCY7Q4vwUAh2lzzruCkQaia6dCWc4uMf23DCsAANcYP/5NvH3kZPXy0L7FUZ77iG5xm7d5A9ZuxJiCKfme8gEGABd57J3rSQVWOFghukVFuIvjmzfgGoYXAOAjMtJQAWh8S1GwCx1AdHMU3GAXFcoA4DsqAE0cmDBdmUUPEN3CBFc3Jg5TAOAjifN5EV5EtwjB1YQgWoIAwGc0qYheXkQ3R8GNN72gJQgAyoI6MuKHJSzNoxOIbrqCSw8uAEC7Xt4l9ALRRXABAFJGLZGxwot7FaI7oODOxQkuQ+cBAOFNFl7m8iK6vW9Mgo8yLlMAAHXkSRDrXiXbSIQX0UVwAQAQXkTX0oZMBgfjfJSZgwsAkCy8tz15Iiq8e4NT6Aqi21PRlAQXH2UAgPbIjS/Br5niKkQXwQUAQHgRXQQXAMBhNKEo/owXAw1E99Vka0eKpgAA+iO5uArhRXARXACA/IS35F7NCC6CCwCQCYkGGiWeTlRSwa0NoEdwAQAKE95gBtEtwxvetzi6KbhreCkDAOQnvDEVzTc2I96diK7XEe7C8ObFvorgAgDkS8JYwPWhPcEYouvjG332+LaaLVnoot976AIfCACAHLh/4dO4iPeaAiJE17c3qskXoYt91wtn+SAAAOSIAp3o+W71Yll8mksiuFE/5TueObnxs9/+iw8BAEDObD9wLk54zyC6frQGzYQvrmzKHj/1Azc/AEABKOC58/n34s54lxBdpwW3sjPcGqRmbdmUceMDABTHE+//GO/TPF2ZQ3RdbQ1SZVzIT3n8+Dfc8AAABtCAhHjXqspuRNe9SuWrmF8AANjmkRNrUfMMZSg9bSXyNK1cPUMvLgCAGzz0+pdx57tXfaxo9vEcdy588e5+cYUbGwDAMLE9vB5WNPtXOBW6aLc//S6tQQAADqAAyffCKr8Kp0Keyjqg10E9NzMAgH0UIClQ8tmj2Z/CKTmahL4h6ZyAGxkAwB3U0hmpaFZANR2MILpW3sRUcIzCKQAAP4gtrPLEKtKHc9xZPJUBAPzivvmPvHSscvvF7wkmwo5TcjiR0wk3LQCA2wzvPx0T8QYziG5R57gaCRVynFKjNTcrAID7yCM/YhWpQGvf4iiim/cLjxnVh+MUAIBfxDpWOXy+6+g5bnRy0MjL57lBAQA8JNY4Y2ppHtHNR3BHwoMMMMAAAPCb+Bm87vXvOtgeVF3lHBcAoFzofPe2J0+Ez3evDU0vDCO62bUHRXyVdxy5xA0JAFACHn7zq2i0uzc4hehmIriL4+H2IJWTcyMCAJSHew9diEszzyK6abcHhebjyiZM6QZuQgCA8pDoz+xIG5Er57hL+CoDAIB4dPlbZ9uIXKhW3kV7EAAANONqG5FzrlO0BwEAgIjYRCrNvCcYQ3T7dp0KjtIeBAAAcaiuJzIGcKq6iuj2W60cSh1o6gQ3GgAANJD9byTNPBk8h+j27q18mbQyAAB0QuNcQ8K7bnXovdW08sHwN5fx499wcwEAQISJk99Fq5mNmmbYe0H7FkfDJhj3vPIhNxYAACQSW808WdmN6PborSyvTYbSAwBAJ+58/r1wNfOatd5da97Ks5hgAABAP8SaZkwFxxDdeBOMkdq3kqbNuvvFFW4kAADomtHDF6Np5j3BBKIbrVZexlsZAAAGIcGb+TKi26EnV71X3EAAANArMlGy2rtrRHSrF5s3545nTnLjAABA36jrxWJRlYWz3JnwNxIdhnPTAABAvyRYRC6VWnS3BhpQPAUAAKkT6d01MHe34J7cpfnwQAOKpwAAIA1ii6qmq2dKKbpbLUItzlMq9eZGAQCAtJDXQ6Soarqys3yiuzc4FXaeYqABAACkTWQgQoEtRMX8o3uCifA3jwerX3BzAABA6qg410oLkYmxfbQIAQBAltx76IKJFqICBLeymxYhAADIEystREW0CF2mRQgAAPImtoUo52H3eU8RmqNFCAAAikDFuiraLTLaLdQIQzl2bgQAAChLtEuUCwAApYp2I4YZOUa7RLkAAFAqIoYZOUa7RLkAAFA61KraGu0Gx7wQXaJcAAAwH+3W7CEXx90XXYYaAACAC9FuDsMQch9qQJQLAABljXYzjnKrS0S5AABAtJux6HKWCwAATka7e4Ix90SXimUAAHAx2s2wbzfLSULXiHIBAMC5aDfDvt1cJgkR5QIAgFViPZkng6MOiS6ThAAAwB1iPJkzmbebwVnu4jjzcgHc5lerGxtzf2zljf/a2PjNn9rT/OfZR3At2lVWtrWSuTLngOhWzzS/6O0HznFBAQwhQdz8Ur9x8s8bG5f/vrHxjx83Ml/6dz75W12YJd56DU99wLUAW6j2KBztmhbdoX2Lo+Eo9+E3v+JiAhQUrR6+VBc6Cd7X32+YW//7f3VB/vcv618Efn2B6wbFodqjSLQ7WdltV3RDZhgqw+ZCAuTDzPmNjcpndRFzeX3/z42NP/ylLsJ7V7iukC+qQQpFu5dNim6c5aPKsLmIANmhFK0i2f/+H7eFtt3Se1NKGgGGPFANUtQaMthlUHRbzTC2zb7NBQTIAJ2HKh279oO/Qpu0lCZXBPxv/8F9ANlx1wtnW0V3b3DKnuiG2oRUfs3FA0gHRXkS2jyKnlxY2oe3rmxs/Pz33BuQPlmaZaQjuHuCibAZxhPv/8jFA0hJbFVwxIo//1V6HfGFtImYZaTUPpRWlLuMGQZAeqgo6nfXENtexFdpZ+4dSIvRwxczKahKa5rQDdqEANIR25WvEdF+15Xr9VYp7iUYFLUPZTFrN4UoN3iOAioAxNbSUrUz9xUMSqSgaio4ZkB0WwuoFJJzsQC6RwVBpJHTX//5V856YTBiZu2uD+rHnLrP8sTJ77hYAF2gIim1wLCyW3LhIt0M/RI7fWg6mClOdEMOVArFuVAAnVHRj4p/WNkv7TPCC/1y3/xH4Wh3tRDRrRVQKdRuejEPVr/gIgG0QelOpT1ZCC+4gbK3kYKqfYuj+YvudGW2+UUoBFcozkUCiOelj+2bWzQGEGgCkYYlhMf7iUOf1HtjXfN4lvAy2Qj6YXj/6ZDwLs3nL7pT1ZXmF6GRSFwcgHjUc2tZjPT6+pmBq8hdqXJXLCl1xouFJPSKsrihnt1ruYru0PTCcLg395ETa1wcgBB6wFstlpJQpmUoofep6NeFKmxNMOLehF5QFvenvzzWKrx7gokcRbc1tUxvLkB8FCizBmtLKW71sWYR8anf2IWoVyMQuUehF0ZePh+KdoOj+YluKLVMby5AVHwsjtvLo3fVBeHVFw9GBUIvyGkxlGJey0V041LLj71znYsCsIWKdayJTt7exBJe6y1RGiTB/QrdEptinq7szF50Q7aPtz/9LhcEYAu1pVgTG30BkAjmvRcSeeuLNiLohUiKuQ9byH5Sy6vN/+iOI5e4GABn6y1B1gqJlOIuMo1q3XGLoirohTRSzD2mloMRbB8BoqjdxtqS4BbtPawI2/LSlyTOdqFb4lPMwa7sRDeUWr7z+fe4EFB6LJ5fWhDcBtZNNNTqxH0M3RKtYq4uZye6pJYBWpCwyXDB0tIZrqXozfrZriqZuZehWyIp5h4nDw2UWtaQXy4ClBlrZ5YSkCKKptqhfmDrphkUVEG3DJpi7tsQQ16UXAAoM2o5sbb6sXLMA+tDHhh6D70wSIq5B9Gtnmn+R+5f+JTNh9IiRyNry/LZpF6b5aVzZ+5r6JaYKuZrqYpu3Bi/R5e/ZfOhlCiatJYutS4amkxkeel6cm9DtyjF/JNfvBH2Yh5LT3SnKzvxWgawWansgqWhXp/1xdg/6IW7XjgbdqeaS090J4Ojzb9c+Ww2HcqIxQEGedo7DoL1WcKKxrnHoVt0xBoqLl5NUXSrl5t/uWYLsulQNt66Yk8oXDqLtD4EQdeX+xy6RcZQoXPdG920DnUW3H2Lo+FWoSfe/5FNh1KhtLK1c1y9HpdSotb6mcNr5Wvuc+gNHbW2Cm9l9+CiS6sQgElXJdciM+vOVPgwQ6/ce+hCOMW8lILotrYKMTsXyoZFRyWdj2YxhL7MokvbEPRKP61DPbcKPXJijc2G0qCqW4tzYV0pnkJ0wWdiW4f2LY72L7qhViFZX7HRUCaUcrS2NMzAxb1EdMFHth8411PrUE+tQne/uMImQ2mwauigub2ILqILNnjgtc9Dols907/ohqYKjVWusMlQCjQ9yGJfqatRrrDY44zowqA89s71yNShASLd6g2sH6GMWBxmoOWygYP1Pl1EF/olMnWozblum/PcxXHOc6GMqHjK4ig6l6NcF0SXPl3ol5hz3dk+RLcy1/xL9EvZXCDKJcrtF+sL0YV+2XHkUtej/pJFd29wqvmX6JeyuUCUW8xysS+3GTl6WV8n/8z9D/0xfvyb8Lnu1d5Fd7J6rfmX6JeyuUCUW8xyfcj6ry/YF10Xe5/BBurXDdslD00vDHctumG/ZTX/6peyuUCUm//Sa7I+uq8Thy/ZF119MeBzAP1yxzMnu/JhTohyK7vxWwaiXBvLB09gRerWl+tfbKBYuvVhTurPXWr+y/plbCoQ5Raz5v7o/v5adPZqXrL65HMAg6CRtyGTjIs9RLqt83Mfev1LNhWIcgtYGofnw/5aH+v3yd/4DMBgdDtfN37IQcgUg/m5QJRbzHK9gErI3cv6+s2f+BzA4Nz25Ilwv+7OzqIbMsW4/el32UzwGqvnjT4UUAmlx60vH1L4UDzdDD+IG3LwHKYYUCaspj59SXm+dcW+6LrcAw120Lz51mKq4Fhn0Q0VUWGKAT5jOQpTm40Pe8x0ISgLqn/qVEwVJ7orFFFBWbBaVatqWh+iLxfOcyuf8TmAdOhm4lBc5fJa81/SL2EzwUcsF1D54gMslyfri/5cSBOZSbWbOBQqogpGmCwEZcGyYYMvhT3W+3NJLUPa3Pn8e22dqcKiu6v5D+svs4ngK1YLqHwxalBq2WomgdQyZMU9r3wYEt3gYBvRbR3np7/MJoKPWC6g8iW1LEGzvHw5Nwdb3L/waavo7g1OJYvuVHCs+Q/rL7OJ4COW056+VC3/9//YFl25kPFZgLSJjPmbrF5OFt2Q/eMjJ9bYRPAOywVUel1Ky7q+x79atS24vhiPgD3k4Bi2g2wnutg/gvdYLqDypbDnP/9qW3R9mNwEdonaQS6OR0R3aE8w1vyHts2+zeaBl1y5blcMfCjscSHKfeoDPgeQHXe9cDYkusFMVHRDlcv6S2we+MbMeduCoNdHlJvt4iwXsiYyW7epgjnRc5nKZfARy6nltR+IcrNe//iRs1zInkgFc5MHc7PoHsVzGXzHsg+wDxGY9SjXh1GJYJ+IB/NUdSUqunuDU81/6MHqF2weeIV1H+BDn7i9v3r9lpfO8unLhTx4dPnbsOhejTnTrV6kXQh8xrIPsIp7XBYEfaFR6tby/vpwXg5u0K5tKHHQweOnfmDzwCs0n9bqcr1V6HfXbEe5+sLFZwDyJNo2FIzcFN2hZ49va/6fmpLApoFPKIq07AOsQe+u7q31tDI9uVAEkcEHe4KJW6Ib6tG9/el32TTwClkrWl6q+nVxX5WylYex1aWhFj44fIF73P3iSmyvLj26UAo0RMDqcnWqkLIHlo1GtK+c40JR3Df/UWyvLj264D0SB8vRmKvnuWpxsrp0lODLTGJwkwde+zy2V5ceXfCelz62nVr+zZ/c21O9ZsuLwikomoff/Cq2V7dRubzc/D/V2MumgS9Yjsi0XIvIEFyAzjz2zvXYXt2tObrV1eb/qXmAbBr4guW5rq7151o+G0dwwRIxvbprzZFuyxxdKTSbBj5g3YXKpfNcBBegN0KR7kaz6F7DGAN8xHoPqSvnuQguQO9oRG5r29DCcCO93PI/2CzwBevnuS74LVtvt1KhHPc6WESeFy36um9xdKimvE0/lHUVmwW+YPk8V8uycYNG4Fm2ztQoRFdNRaAcDO8/HYp0KzuHasrb9EOFw2wW+ID181y5JVndO43As9zbLFMO5uKCdWJcqXbJAnKi+YdSZjYLfMD6ea7Sttb27KkPbLtMaZ38MyP6wA1kNBWKdGcjFpDbD5xjs8ALrJ/nVj6ztV8aumB5KIRGB3J+Cy4xevhixApyqKa8TT8cefk8mwVeYP0818p5pAvRrc6WGVwArnH/wqehtqGl+aGa8jb9UMrMZoHrWD/PVURZ9B5J9JXith7d0g4ErjJWuRI2yFjGdxm8xPp5blGmGDoLlYhZj2y1fneN6BbcRu6OrWe61TMR32UpM5sFrmP9PFfFQHnuh0bcScQsVyQ3lo4Ffn2Bexjc55ETa2FXqlVEF7zE+nluHqYYihIPX7Lda0sqGXxm4uR3iC74j/XzXK0s0qY6o1VFtM5p1QPsypLYqi+YNiDwXnSnqxeZMATeoVF5lpeclAZ9jxIovU95NyuStVwMlbSU6tbrR2yhNKKrOQeILviG9XmvaZhiWD+z7iaypUgKEF1EFzzgP/9qW3QkOIO+Rxeqj+MifM5sAdFFdMEzrFfoDmqKoXSsS+lkpb9dmKYEkDYakxsVXR3sNv1QJc5sFriKWmMsrzRMMdRO40IKWW1Ruh7cl1BmQqK7Fhlgr3CYjQJXUfrS8krDFEPpaavrD38hqgVIFF2B6IJPlMEUw9qZtV6PvuxQGAWA6ELJKIMphgqSEFoARBegUFRgZH0NOnjdwpm17CS53wBSEl1VW7FR4CJlMMWwMMghjZYnAESXSBccx3KBkZaKjAZ9jxbOrFWBLYMPhhIAILpQYjDFyH/J41nva9C0OQCiC+AY6g21vHw3xVAk/9LH3IcA7UV3qnoV0QXXccEUY1BjfxdMMRrRL726AMmi22ID+ejyt2wUOIfmxlpevptiJL3nQaN7AJd54v0fw6K7jvcyeIF1Uwy9vkHfo6qz1a7j0qzcRtqZM18oIww8AG+xPnUn7XSr0ukyp1AVsQWzjE5L6XWNXMRMAxBdRBccx4WpO1lHejrvVURpfSlKJ+UM5RbdyeoyogsuY73AKA1TjG6RuL91xXb0qy9Ilc+4bwHRrfFg9Qs2C5yiDKYY/aD0s+U2KqXGB63oBrCMCpNDons5IrpjlStsFjhFGUwx+kVnqBI3q0sDKp76gHsY/ESZ41D18iqiC85jvZDIgl2iTCusRr3f/xNTDSiT6E4tzTf/8P6FT9kscAadYVpeaZhipBn1fvI3u/tEgRX4xsNvfhUW3ZXNSDc42PzD0cMX2SxwBgtTd9ottTJZ2i99AbAqvIp4STWDTyhzHDrTXR4amq7MNv/wnlc+ZLPAGcpgipEFVs95dVSgHmTubfCBHUcuhUQ3OLoZ6VZ2N/9w5OXzbBY4g6wGLS/LHsRWhVe9vJhogA8oc9yaXl6aV6S7s/mHw/tPs1ngDNZNMSxHbUo1W7WUVFUz7UTgOgpiW0RXmeWhPcFY8w/vfP49NgucQIU3lleephj9YtlY5OSfucfBbe5+cSWUXq7sHhratzja/MNts2+zWeAE1k0x1D/swj5aPRenohlcR5njUKS7c+jVV18dav7hT37xBpsFTmDZ9EGrSFOMXlAa12qvs9LM3OvgKnc8c7JVdJVZ3hLd9eb/wWaBC2CKkR7yQra65CXN/Q4uosxxa6QbjNRFVybMTf9DJs1sGFhG1a2WlyVTjG6jXatFaXpdtBGBiyhz3KytNb2t/We6erH5fzz2znU2DEyDKUb6/O6a3f105XwcoMHPfvuvsBvV+i3RZaYuOIYGolteVk0x2mG9GpyiKnCJuLF+t0SXoQfgGJhiZIMKl/giAzA4j5xYiww7aIp0W4ce4L8M1pFPr+Xl6hmk5QyCa+fkUG40mz7su9x0ptvqv4wVJFjGehpUI/Rc3VvrZ+WqsuYzAC4QZwHZLLpYQYIzWG5v0XK56Mf6qET6dsEV4iwgb4kurlTgEJhiZIvVYfeN5VL/M5SXODeqm6IbdqXCIAMsY7nYR2vuj27vryJ1y4uCKnCBiDHGZnDbKroYZIADYIqRPdbbsVzsgYbyEQ5kb2ptU6RLry6Y56WPbQuCD2eOC5/yxQZgEJJ6dMORbkuv7gOvfc7mAVFYCVOf1r/YaHGuC5ZR0BrXoxuKdFt7de+b/4jNA3NYP288fMn9PdaZtPXlerEa+I0MpuJ6dFtFN9Srq+G7bB5YA1OM7HnqA/uiixczWCapRzcsui29unc+/x6bB4hBD8tlU4xm9MXB+tJYRz4TYBUFraGRfjMxohuMMMweLGO9wMeX6EtFSi4siqnAKpHh9dOL4xHRjRtmz4g/sITl0XNaPp0zurCYsQsW0Ui/8BzdoWePb0sS3ZXmPyjDZjYRrIApBqLbvBj1BxZ5dPnbcOXy1RadDYnuEhXMYBEXUp4+pTtdWD59yQF/iEwXmq6eSRbdUAXz9gPn2EQwgfU2Ft+M+F1YPrRngX8oWG1tFwqOthHdxfHmP3zbkyfYRDDBW1dsC4BPfsCuFFKpsI7PBljjrhfOhkS3sjtZdJ89vi3sF/nE+z+ykVA41k0xfBIAF1qGtOROxmcDrKFgtUVH9wRjiaK7da57FQ9msAamGIguogvWUZAacqK6EdHYyA/2Bqea/9L9m1/h2UxABJKXvhCw34guwCMn1sKie7mz6E4GB5v/0sjL59lMKBQVzFhevlkSapgAogvQOwpSW0R3M4jtQnQru5v/kpw12EwoEhUpWV4q8uJLTv6LQiqwxj2vfBhqF6rMdRbdGDtIOWywoVAUmGLki/VKcUQXrBK1fwx2dRTdrdm6axRTgQXUvqKh5ZaXbx7A1u02ff2yA24TKaKqie7CcHeiO1090/wXdxy5xKZCIWCKkT+f/A3RBeiVyOD6mCKqNqJbmcOZCiygIQKWl0+mGA2+/t4N0dWoRz4jYIXIDN2mwfVdiG6rM9VPf3mMTYVCwBQjf6yn8xuLKUNgieH9p8NFVLNdi+7Wue6N5l8wcfI7NhZyR8PKibbyQ+/HlfXz3/P5ADsoOG3nRNVZdKeqq82/YKxyhY2FXMEUI39caRfSlzE+I2CFmHF+64namiy6S/PNv0T9R2wu5MmhT2w/+H0zxRDWe6J93ntwl4gpRmicX3eiO13ZiUkGIADJy0dHpCvX3RBd3wxJwG1UbBwa53ewd9Fl4hAUzOW/237w+9iy4koR1Usf8/kAO2ybfTtcRLWzZ9HdKqa6jEkGFIELphi+FfL8atUNwfVx78FdVGQcniykoLU/0Z2qLjX/MvUhscmAAPhpilH5zA3B/cePfD7ADioy7sYUo8tIl+EHUAzWTTFklejbnrviREURFVhCk/hCR7FL/Yvu9MJwuF/38VM/sNGQOX/4i+0Hv2+mGC6k8xuLkX5giUh/bpvz3I6iS78uFAWmGPniSn+ulub98hkBC8QMrW97ntul6Lb269794gqbDZmiIhnLy0dTjJWv3RBcTDHAEhG/5Tb9ud2LLj7MkDOYYuSLUsv6IuHCOvlnPh9gh279lnsSXebrQt7owcqDPz/U80pqGaA3Yufn7lscTUt0l2kdgrywboqh80+f9tv6JCdSy2CRh17/sqdWod5EdzNkpnUI8sJ6Fa16iH3Z670r7lQtk1oGS0RahSaDoymK7sJwOIxm1B9kgQuuSDoD9WW/rafySS2DVXqxfuxZdOvCW71I6xBkjXVXpK+/92ev9eVB7k4uLB8dwMBdehnl17/ohlqH7nrhLJsPqWO9dUXnzb7stQw+XFmqaOfzAVbYceRSq+juDU6lL7qhUX8/+cUbTB2C1FEkiejmg6JHolyA3rnz+fd6bhXqWXS3qpivkWKGrLBuiqHlS4+u9V5oolywymPvXI+6UE0vDGckusFRUsyQFS70iyr97fo+6yzXekaBKBesEnGhmqqu9KSjPf3hPcEEKWbIChnZI7rZY32CE1EuWOb2p9/tO7Xcs+huDUC4SooZssCF0XKui65S+FQsA/RHpGq5x9Ryn6JLFTNkgwv+v/pi4PIe//uXRLkA/XLf/EcDpZb7E909wRgpZkgbF0wxXI++ZC7hivuU5inzuQBrRA0xgpnMRZcUM2SBKz2jSs26uL9KK1ufUdxYep16vXwuwBL9zM5NT3Qng4OkmCFNfnfNnbTn3B/d219Xhhq4ur/gP/ceutC3IcbgortvcZQUM6SJK0YNWq4VU7lUrcxQA7DKbU+eGDi13LfoxnkxP/Da51wY6Dv16dLSuagrQw/U++zKOe6V634NkwB/0Az5NFLLA4puZY5xf5AGSie6ttRTjOCm+0XmqQ/4LIBN7n5xJZXU8oCiG4zU1L7phaiHiQsEveKCKUacSFieq+uS4GqpkI7PAlhER6c6Qg2llnflLrpbKeYzzS/knlc+5CJBz7hU5BNOhyK45cgaQHm5f/MbYSi1fG0g3RxMdINd4YKqn/32X1wo6AkXTDGSloqqLJ1DylACwQVIDx2dthpiLM0XJrpbk4fW6NmFfpk5767gNpZcqooWXv37LrlNIbjgAjHD6pVaHilYdFsnD2nOIBcLusWlQertllqe9AWiiD1UAZJLLVda+oLA/Q/WifTmTlfPDKyZA/+CUM8uBVXQC65FZ+2W0rpvXck3ulUPrmvpeR8mNYH/6Kj0p788FjrPrewuXHS3bCFXm1+Yvh1w0aAbXIvQulmaVatipiz3rfKZO9OCmpecx7jvwQUerH4RLqBa67c3N33Rna7MNr84OXdQUAXdRGouFf30uuQhrMh370o6+6Xfo3S8Kx7K4SwAbUHgErI3bhXd4GgqepnKL9lU/80Xtd78AvUtgQsH7XDRFKPfdfnvdYtDVRf3cvaryUD6ey5nBBT5W+5pBggzcfK7aAHVvsVRM6JbTzEHx3Cogl5wyRM4KzGSGIfxKeWuHmwmBoFrRAqopqqrqWllar9oenGcgiroBVdNMVidl9LJ+lLFfQ6uoaPRiANVCgVUqYtu3BCE7QfOcREhERcLgVidl86clRbnHgcXiXGgSqWAKhvR3fw2EI52lRvnQkIYH0wxWK1LrUsqHGNSELgc5UZH+FXmUtXJNH/ZlkPVZdqHoBMqKGL5s9RvzdktuI4cFdMa4Zef6IZG/ik3/vipH7ig0IJPphhlXrLAZCQf+ELUZ7m6lLpGpv4L1T4U8mNWjpwLCs1oQg/L3aUKa7V8cS+DLzz0+pep+yznIrpx0S5mGdCM76YYPq8//CV7ty2AIhjefzp1n+UcRTc64J7pQ9BAla2Wl1qZ5A/MF4P6UpW5DDrSctYCsEb8NKHFcWdEd8uPeQmzDIjDuilGo79UIqPxc2VtbdJ57eFL3K/gP2pvDRVQXc5MGzP7xYp2Q98clDPnAoNSlJZXnGWhUqp63b5Hvzqr1ReNosYUApiIclM0w8hNdLfMMs4Q7UIYy4b9EtV2r13n0Wp30rQcFwcPhJfeg1Lpimhp+QGi3FqUey1TXcxWdKPWkES75UYpW8tL3se9vB9FhBIsibALnsn6UqEza40GpNUHiHLjznLTNcPIVXSJdiGMdVMM9Q8P+h7VSqP3qTStUtIS8ryXzqH17+r9yCVKr4mUMUDnKDdtM4wCRJdoF25h3RRDYplllC/xU6GWBFkotRueMhRXuKU0cPjPKWJt/B6h147nMcAAUW6GZ7m5ie6WNeQy0S6IIqK+XhZtMQCljXIv56KHufwjMX27D7z2ORe+hFiu/lU0yTUCIMp1XnTj+nZxqSofasWxvJSu5ToBEOX6Ibox0S6ezOXCFVMMACDKdV50iXZBRUOWF0VIAES5foku0W6p+fp7u4Krs2aGrwP4zfjxb+L6cnd6K7px0e5Pf3mMebslQG5HlpeMLbhOAH4TmZeb0SQhW6Jbj3Zb5u3ee+gCN4TnlMEUAwDsoqxqXpOETIlu3LxdocNtbgx/kXmD5bX5eeQ6AXjKE+//WKshCp3lLheif4X8o88e36bD6+YNuOuFs9wcHmPdFAOLRAB/UTY1JLg3lHUtjejWXaoqu7GHLA/f/9Ou4Oq1cY0A/ERZ1J/84o1chxqYFN24YQjbZt+mhchDMMUAgKIoYqiBYdFdHKeFyH90Xmp56byZ6wTgH8qeFmmEYU5041qIlAaghcgvrJtiaPIP1wnAL5Q1vf3pd8Oiu1K45hX+AtRCNFVdb96Ye175kJvGI6wPd1cPMdcJwC8iLUK14qn8W4TMiS4tRH6DKQYA5I2ypTJeCunKkgm9M/Ei1EI0Vb0anrlLUZX7vPSxbdFV6pvrBOAXd7+4Eo5y14pqETIpultp5l3haHfHkUvcQI6DKQYA5El88VTwnBmts/JCai9mb3AqXFQ1cfI7biSHUTuO5aV2Jq4TgB/EOk9NVy+a0jlTLyamqGp4/2luJofBFAMA8kJFuJHiqT3BGKLbvqhqNpwaGKtc4YZykKc+sB3lypqS6wTgB7Fj+6aW5s1pnLUXtNW7uxoedk/vrntgigEAeZDQk3u1SOcpt0R33+Jo2Klq5OXz3FyOoXF5lpfGDXKdANznvvmPolHunmDCpL5ZfFH1gQjBwfAmPvzmV9xgDoEpBgBkTexAg6ngmFltM/vCYsb/MRDBHf7tP2wL7toPXCMAH7jz+fdienIXhhHdfgcihKJd0sxuID9jywtTDAD3GT18MZpWng5mTOua5Re3lWY+ytxd93jrim3RfeO/uEYALvPIibUYwa2eMa9p5l9gjEWkPDUxzbANphgAkBUywdBxo1WrR6dF92aaOVTNjGmGbf7xo13B/d//q585c50A3ETHjNbm5HolulumGZFJRMrncwPaY+a87Sj3ynWuEYCryCwpaoJhY4KQV6K7ZZqxEt5s5fW5EW1x+JJt0VX/MNcJwD10rBgzss+kCYYfoitvZuXtQ21Eyu9zQ9oBUwwAyIKY9iBz3speie6W8O6ijcg21k0xlP7mOgG4RXx7UGXOOQ1z7QVvpZmXGIpgExUoqVDJ6lKBF9cJwC1i24OmqitO6peTLzrGrUo2YI+9c50btGB+fcF2lKtWJq4TgDu43B7kjejWXvieYCzcRsT5bvHIdMLywhQDwC3UHhqTVt7prHa5+sK32ogis3e3HzjHjVog1k0xZE/JdQJwg9hzXIfag7wT3bpNZHWZ/l07aJCA5YUpBoAbyO43RnBXndcs59+AznenqxcZA1g81k0xVFXNdQKwT2w/rsPnuF6Jbu1NaOj9VHUdf+ZiUf+r5YUpBoB9NL719qffjevHNTmUvpSiu3W+uzMc7d7xzEnm7+aIdVOMhU+5RgDWifVVdrAf13vRrZ/vBgcxziiOy3+3LbpPfcA1ArDM/ZvfjCOCuzc45ZVO+fRm6hFv9Uz4oulCckNni3VTjO//yTUCsIwMMOS34LKvcklFd2E4PH+Xwqrs0XxaywtTDAC7qP7mtidPhAV33TVf5VKKbpJxhr5BPbr8LTd4Rlg3xfjNn7hGABaRoVGkcMqh+biI7s2IN5gJX0Q5VlHRnA0rX9sW3Zc+5hoBWEOFrrGOU5PBUW+1ydc3llRYpYpmrCLTx7opxs9/zzUCsMbdL654XzhVKtGtvcGp4Fj4ot71wllaiVJEgmZ5YYoBYI/75j+KdZzyrXCqfKIrx6qp6gqtRNlh3RRDqW+uE4AdHnjt8zjBvapCWO81yfc3eLOiOTQKUOw4cokPQAqc/LNt0a18xjUCsII6SaJnuNU1OQuWQo/K8CZrb1RWkbqwoYv9YPULPggDYt0UQ+1MXCeA4lEHSaQX1yOLR0Q3EvEujse1EtHDOxgynrC6ZNjBNQIonoReXG9bgxDdW61Eu8IXXcIrNxQ+GL1j3RRDUTjXCaB4wVXLps+eyohuW+GtzIUvvqYSYZ7ROzovtbx03sx1AiiOx0/9EC+4jg+jR3R7biVamkd4B8e6KYYqq7lOAMUgTwR5I8QUTi2XVnvK+sbrwltdCt8MOnPAtap7vv7etujuXeEaAZgS3KnqSql1p8xvvrYBm9+4sIvsD+umGHLJ4joB5I/Mh2RCFCe4vptfILoIb2bIz9jy+sNfuEYAZgR3unqx7IKL6Lammlfwae6NX1+oT++xytwfuUYAeRPrpyxzohK4TSG6vWxEgl0kwgsA0B2y10VwEV2EFwAg45RyQoR7rSz2johuvxuS4NPMGS8AQLzgxp7hIriILsILAJAeygAiuIhuesKrajuEFwAgVnATjC8QXEQ33TNenKsAAME9GV80heAiuggvAEA6JA4voEoZ0U1VeGMMNBBeAEBwt4wvEFxEN/XNShBe5vECgO8owIidh4u1I6Kbt/CKB177nA8mAHiJAgvNHUdwEd1iNi1mLKC4b/4jPqAA4BUKKOKed2Uez4foFhLxBgfjbkS5sqhZnA8rALjOvYcuxAtuSQfQI7pFb950MLP5be9G+Ia88/n3sI0EAGdR4LD9wLl4wZ2uzPH8R3SL28A9wcTmjbiOiQYA+IACBgUOMenkG0OTld089xHd4jdx3+Lo5k15Na6y+ZETa3yQAcAJHnvnenxLkAKL6cVxnveIrqFU88Lw5o25Gr5ZVfH3YPULPtAAYJrx49/UAoUYwb2KyxSia3MzZaKxNzgVdw6iggQ+2ABgkfsXPk0qmFrF9ALRdaGy+WjcDaxzksdP/cCHHABMkDgHVyiAoAcX0XUn3VyZjatslqML57wAUDQ6v40dWlArmgqO8hxHdN2sbJ6srsWd8yqdwwcfAIrgode/TDq/XadCGdH1ssAKIw0AKILRwxeTzm+vbgYKYzy3EV0/NnqquhR3oyu9ozQPDwMAyBL13yYbXlTPUDCF6HoY9QYzcUYaSvMo3cODAQCyQHUkCf23OEwhut6f847FGWmIkZfPk24GgFTZceRS0oSg9U3B3clzGdEtxzmv0jkxwnv70+9S3QwAA6P2xOH9p5PSyRcxvEB0y7f5CZOK9K1U3055cABAP7SpTt4kOEb/LaJb5nTzRFK6+a4XzmKmAQBdo+MpHVMlVCfTDoTows1082R1Oe6Dom+rD7/5FQ8UAGiLjqV0PJVs5xiM8LxFdKEl3VzZHVfdLO555UOKrAAglsRiqdo4vuAgz1dEFxKj3mAkyUyDIisAaEY9/rGzb2+ZXUzwXEV0odsiqxjv5kbUq0Z3HjoA5URZrzatQBRLIbrQX9S7OJ5UZKXBCZz1ApSPDme360PTwS6en4gu9HuBNKM3YVRgw7+ZCmcA/1F2S1mupGfBJisUSyG6kNaFqk8supxU4TxWucKDCcBTlNVSdit+DF91jVYgRBcKOOtVX+/Eye94SAF4grJY+lwnRrdqNWRQAaILmUe9Y0kVziqs0Ogu2osA3EaFUsmuUtWr+CYjupD3xZuuzCb19SoV9WD1Cx5eAA6mktsUSm3UajyoTEZ0oSjhDUaShicI9fDR2wtgH/Xctk0la0jB9OI4zz1EF2yI765aQQVVzgBOoark++Y/aleVvI6rFKILFi+m2oumluaTCq047wWwxQOvfZ5cldwwuaANCNEFB1LOe4NTSR9kznsBimX8+Dcbdzxzsl10u0oqGdEF1y6uent1DpTwwdaHXnM3eQgC5MOjy99ubD9wrl0L0DV6bhFdcD/ynWl33ov4AhQstlvntlQlI7pQkvPehvgq7cVDEiAdZFbTZqh8HR0FcW6L6ILH571ysWnzEBjefxrxBchabHVuy+g9RBdKc9471q6/F/EF6B215d176EKbkXuNIincpBBdKGnkuzjejfgyRhCgc2TbVmw1sIQiKZ65bALUxbeyM8nPufnMl2lGALdQJqhDgVTdJxmxBUQXEsW3TZuR2Db79sb9C59isgGlRV8+O/TZ1tt/piuzPFcA0YXON8bmN/Ok+b3Nc3zlcIW9JJQB2TXqy2Z7BynEFhBdGDzybXvmq3Ose175sGbYzsMZfDyvVXFUmzF7t85sp4MZnhuA6MLgN8q+xdFaq1GbPt/GVCOl3kg9g+vIKrXt1J9b03/OUI0MiC5kFPkGI1smG2udUs+q5mSsILiEsjWKartIId+ofQndE4zxXABEF7K/ceRwNV2ZrZ1fdYgENJBbZ2Gc/YJFlJVRdkZZmo5Rbd2u8SgOUoDoQnE3kYqupqorXTywanN96fkFK1GtahE6ntXebPsJnsMbGRBdsHMz1c59g4PdRL9K3+mBh+MV5C20qrhX9qWrqFbzbLFqBEQXzN9Y08GudjN9w32/OkfTJBaEAbKoPu5BaBs2jbNEtYDogoviO9Jt9NsQYD0gaT+CQYVWdQQdDSxuFUat1c5q9y2O8rkFRBf8uNn2BBPdtB01F2DtOHKJCBi6Th33KLQ3tsbq7eLzCYgu+HvT1Sqfg5naA69LAdYZsFqQ1DspZyBEBlR1/NDrX9ZqA5Qh6TJ13OirJX0MiC4gwN0+ONXecd/8R/QBlzRt3JVpRdw57fTCMJ87QHQBBhBgtXyoFUm9lnooI05+RbNqMVOhXQ+FUI2I9mKtzYeeWkB0AXoQ4FrrRvcPW6WiNW5NERGRsHuRrI4QJLJdn822srIZ0c5REAWILsAgN2qtCCs42mnyUdJAhuH9p2tV0Yqa8IW2g/q0VSynL0kdrReTJvqol1YGLZzRAqILkMFNqzYknc/1EQU3UBSlaErRsB78CHE+AvvAa5/X9r1Ly8X4imMVQiltjO8xILoABUbBOsPr50He1COsAh1FxKqKpVe4/9Yd7Z/2URFsz2excWezU9UlWnsA0QUwGQlXdtYMOepzgNcHeuBvVUqrXakhxorYyt62pMyA9qEhrmrbUQp/0L3eKqBbrU2y0nUkZQyILoBzkfBYLR1dO/vr/Uy4U5paYqP2pcaZsS/par0Pofel96f32XdauJ0TVL1vdg6PY0B0AbyMhBeGa1GUoql6e1KqQhwXKUuwRCNiFiogaghbg6yqrTVWsfFvNKLTBo3XJlR0ltle1K1At6LYYIYKY0B0AUotxovjNTGQKEgcuvSLhrjpPBLX6lK9T5Y0MQCiC9DNB6TWL7wpGkp/1iK02jnxahpnxR6wejNyrZ2ha58wogBAdAEyjY69FeVbotoobNqE6w6A6ALY/ZDtWxxtCFbNxKEhYo00djMDtj0ln6M2Exy7+e830r81Fse5XgDZ8v852iVz2qoKWQAAAABJRU5ErkJggg==", - fileName="modelica://SorpLib/Resources/Images/beta.png")}), - Documentation(info="<html> -<p> - This partial model is the basis for the mass transfer correlation models based on the loading difference <i><code>Δ</code>p</i>. <br> -</p> - -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); - -end PartialMassTransfer_dp; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/PartialMassTransfer_dx.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/PartialMassTransfer_dx.mo deleted file mode 100644 index 9e256cad4839e8f4f2b65269cddccee9de9ea949..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/PartialMassTransfer_dx.mo +++ /dev/null @@ -1,33 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial; -partial model PartialMassTransfer_dx - - Real beta(final unit="kg/s") - "Mass transfer coefficient (dx)"; - - constant Boolean computeTransportProperties = false; - - - - annotation (Icon(graphics={Bitmap( - extent={{-111,-100},{111,100}}, - imageSource= - "iVBORw0KGgoAAAANSUhEUgAAAd0AAAHdCAYAAABYPaNuAAAAAXNSR0ICQMB9xQAAAAlwSFlzAAAXEgAAFxIBZ5/SUgAAABl0RVh0U29mdHdhcmUATWljcm9zb2Z0IE9mZmljZX/tNXEAADn7SURBVHja7Z1taF1ltsfDMEgRkSBFgoiEIhJEJIhIEBn66dIP86FtEiYdUAKOolOQFESL9EMshQYJJ2ejWGrBjEIpeju0c8sQKI6h3NEiBSteSse5QhWHCeMwzRWReoe55OZ/Tk57zn45r/tlPc/+PfDzQ2zTc569z/6ftZ61/mvo1VdfHQKA/BiaruxsYnZoamk+wt7g1NBUdXVwgmOR3z0d7Lr57z97fBvXBCDHzz+bAJDCB2lPMFETscngYF3cqitN4nd1kw3zTFcv3nzNk8HRLYGeqQt0MMJ1BkB0AXKKThfHt6LDuboYVc/Uxal6wwlBTY+rLRE0ogyA6AL0L64Lwzcj1snq8lb0VyZR7Z/6F5C6IOvLCelrAEQX4ObNX08Jz9ZTqbW06nrWwnTbkyc2hvefvsno4YsRxo9/kxoPvPZ55Pff9cLZm//+T395LA8xXqvvryLjzf3e3HfuP0B0AXyPYCcru2sCm0H0esczJ2sidu+hCzVhe/jNr24K389++6+NnWc3zDNx8rubr/nB6he193HPKx/W3te22bezOkNeqqWo9y2Ocp8CogvgbhQ7Vo9iq8tpFDI1IlSJkMRIoiRxeuL9H50Q1LSFuRFB3/3iSnoRsyJiVW0rNU00DIgugOVItlboNFcrcKqnM/t++N/5/HsbIy+f39hx5FIphbVftE/aL+2b9k9inEJEXK+kng52cZ8DogtQmMiq4CmYqUWyfYqsojMJw33zH9Ui10eXv0U8M+Cxd65vPPT6lzfPk29/+t3+C7VqX6qC50hHA6ILkPXNqsKnervOxX7PXZUelsAqTYogFhsV69xbX3gGiIivbp0JEwUDogsweDQbjNTOZevuTOu9RrGKqhrVwK4UM5WZRmp6+4FzvZ8RN0fB9AwDogvQS9pY1oi1Fp6eRFZFPWOVK7V0JiLmR1pa11Pnwypk6+MsGAEGRBcgchM+e3xbTWjrLk89pYuVnnzkxBoiVQJ05q5IWIVuCDAgugA9C20wU0sdd2ml2BzNPn7qB4So5GfCKs7SGX2PPcQIMCC6UKb0cbBrq3e2qzNaVboSzUI3qej7Fz7ttShrtZ5hWRjmswmILvhzk+1bHK31WnbZ2iOhVQEUZ7PQD8qCyLyjawFWpkVfBDHkAEQX3E4fd18QpRShIlqEFtJErWGKgHX+33UbUi39TPQLiC64cEPVemk19q1z+lhCK69iTCkgLwFWBqUrc45G9EsPMCC6YO4mUj+tooMuPI5VDKXiF4QWij4DVmalq1akyeq12qhHiq8A0YVCbx6d1Sqq7aL6WG0eqjrGpAKsIYcyVcX3cPY7xucfEF3IMbJdHN9yieo4mUfRBJaL4EoBlvqAu/SGXiH1DIguZHuzaB5tF4VRsl9U9MCDHFxFLWpywvrJL97oXHilgsFnj2/jGQGILqQU2daqkK8S1ULZkAmHjkU6Vj/X2uE0jINzX0B0oZ8bo97yM9ept1YVyOqJ5KwWfEdTkTr2/jbOfRk9CIgupCm2evjIho+HMZQNVd4r9dz53Dc4RuQLiC4k3wxq++kgtqryxJIRoN73qz7ztue+9cr+JcQXEF24dRPozFa9iAkPDj1U9HDhvBYg/txXphtte35r4qszX5yuEF02ocSRba0a+Wo7Iws9TPRQ4eEK0B7VNchysoPhxjrii+hCGcV2snq5XWSrSmTEFiAj8dUxjmonaDVCdMHnNPLieLs+20YamVm1AHmKbzDD8wnRBa/ENhjZGkKA2AIUdOar45r2s30Xx3leIbrg8sVV+4+M2ttM/FHrA2ILYEV8aTNCdMHlc9tr7Vp/qEYGKEZ8VTPRptVoXV+WeY4huuDBua2m/dBnC1A8+tK7/cC5Dr7ODFVAdMHJc1sVczCEAMAespfsMNlohXGCiC6YEtzaQIL1du0/eCMD2EaVzonnvTVP5+AgLUaILhR58Ta//da+BSd8Q1bqinNbALfOe9VJ0DblvCeY4PmH6ELeF07feuu+rpEPpsaQjR//hocYgKM89s712lzqNv29y7haIbqQT3Q7keQmpdTUjiOXeGgBeIImeSWaa2CsgehChheq3nN7NOmbr74V028L4GfK+Z5XPmxfaMX8XkQXUrxI08GupJF7im7HKld4OAF4jlr9EquctwqteF4iujBodNumDUhuUgwlACgP6kLQEVKiscZ09SJRL6ILfUW3NZOLq0k9t+rt4yEEUE5UaCWjm0RHK856EV3o4aK0qUxWOwHRLQAIHS216e2lwhnRhQ5ntyNJfbeKbrFvBIAwKqBs015EXy+iC4nFUgmuUpzdAkAn2p71UmSF6ELnYikqkwGgFx5d/radj/MqYwMRXYqlEoqlVCSBhSMA9IoqnNv09a5r7CfPX0S3jOnkmaRiKVylAGBQ1OGQWGQ1tTTPcxjRLX06WWkhiqUAIC06FFmtUt2M6Poe3Y7UmtcplgKAHEksspqsXtMxF89nRNdDwa3sjKtO1gfhgdc+58EAAJmiLFrs8IS6heRzPKcRXX82WWYXMdHtttm3a9WGPBAAIK908/D+0wnp5uCYjr94ZiO6Dke3C8ND09UzcTe4bnzSyQBQBHK2S/Rupq0I0XVTcJPbgUYPX+SDDwCF8mD1iyQzjXUdh/EcR3SdP79V+b6GUvOBBwAL6HhLx1yx57wMTUB0HRHc2bj+2zueOYnZBQCYQ8dc2w+cwz4S0XVwM6eW5uNu3LtfXKm5xPABBwCr6NgraVoRz3dE19YmyvBCY7Q4vwUAh2lzzruCkQaia6dCWc4uMf23DCsAANcYP/5NvH3kZPXy0L7FUZ77iG5xm7d5A9ZuxJiCKfme8gEGABd57J3rSQVWOFghukVFuIvjmzfgGoYXAOAjMtJQAWh8S1GwCx1AdHMU3GAXFcoA4DsqAE0cmDBdmUUPEN3CBFc3Jg5TAOAjifN5EV5EtwjB1YQgWoIAwGc0qYheXkQ3R8GNN72gJQgAyoI6MuKHJSzNoxOIbrqCSw8uAEC7Xt4l9ALRRXABAFJGLZGxwot7FaI7oODOxQkuQ+cBAOFNFl7m8iK6vW9Mgo8yLlMAAHXkSRDrXiXbSIQX0UVwAQAQXkTX0oZMBgfjfJSZgwsAkCy8tz15Iiq8e4NT6Aqi21PRlAQXH2UAgPbIjS/Br5niKkQXwQUAQHgRXQQXAMBhNKEo/owXAw1E99Vka0eKpgAA+iO5uArhRXARXACA/IS35F7NCC6CCwCQCYkGGiWeTlRSwa0NoEdwAQAKE95gBtEtwxvetzi6KbhreCkDAOQnvDEVzTc2I96diK7XEe7C8ObFvorgAgDkS8JYwPWhPcEYouvjG332+LaaLVnoot976AIfCACAHLh/4dO4iPeaAiJE17c3qskXoYt91wtn+SAAAOSIAp3o+W71Yll8mksiuFE/5TueObnxs9/+iw8BAEDObD9wLk54zyC6frQGzYQvrmzKHj/1Azc/AEABKOC58/n34s54lxBdpwW3sjPcGqRmbdmUceMDABTHE+//GO/TPF2ZQ3RdbQ1SZVzIT3n8+Dfc8AAABtCAhHjXqspuRNe9SuWrmF8AANjmkRNrUfMMZSg9bSXyNK1cPUMvLgCAGzz0+pdx57tXfaxo9vEcdy588e5+cYUbGwDAMLE9vB5WNPtXOBW6aLc//S6tQQAADqAAyffCKr8Kp0Keyjqg10E9NzMAgH0UIClQ8tmj2Z/CKTmahL4h6ZyAGxkAwB3U0hmpaFZANR2MILpW3sRUcIzCKQAAP4gtrPLEKtKHc9xZPJUBAPzivvmPvHSscvvF7wkmwo5TcjiR0wk3LQCA2wzvPx0T8QYziG5R57gaCRVynFKjNTcrAID7yCM/YhWpQGvf4iiim/cLjxnVh+MUAIBfxDpWOXy+6+g5bnRy0MjL57lBAQA8JNY4Y2ppHtHNR3BHwoMMMMAAAPCb+Bm87vXvOtgeVF3lHBcAoFzofPe2J0+Ez3evDU0vDCO62bUHRXyVdxy5xA0JAFACHn7zq2i0uzc4hehmIriL4+H2IJWTcyMCAJSHew9diEszzyK6abcHhebjyiZM6QZuQgCA8pDoz+xIG5Er57hL+CoDAIB4dPlbZ9uIXKhW3kV7EAAANONqG5FzrlO0BwEAgIjYRCrNvCcYQ3T7dp0KjtIeBAAAcaiuJzIGcKq6iuj2W60cSh1o6gQ3GgAANJD9byTNPBk8h+j27q18mbQyAAB0QuNcQ8K7bnXovdW08sHwN5fx499wcwEAQISJk99Fq5mNmmbYe0H7FkfDJhj3vPIhNxYAACQSW808WdmN6PborSyvTYbSAwBAJ+58/r1wNfOatd5da97Ks5hgAABAP8SaZkwFxxDdeBOMkdq3kqbNuvvFFW4kAADomtHDF6Np5j3BBKIbrVZexlsZAAAGIcGb+TKi26EnV71X3EAAANArMlGy2rtrRHSrF5s3545nTnLjAABA36jrxWJRlYWz3JnwNxIdhnPTAABAvyRYRC6VWnS3BhpQPAUAAKkT6d01MHe34J7cpfnwQAOKpwAAIA1ii6qmq2dKKbpbLUItzlMq9eZGAQCAtJDXQ6Soarqys3yiuzc4FXaeYqABAACkTWQgQoEtRMX8o3uCifA3jwerX3BzAABA6qg410oLkYmxfbQIAQBAltx76IKJFqICBLeymxYhAADIEystREW0CF2mRQgAAPImtoUo52H3eU8RmqNFCAAAikDFuiraLTLaLdQIQzl2bgQAAChLtEuUCwAApYp2I4YZOUa7RLkAAFAqIoYZOUa7RLkAAFA61KraGu0Gx7wQXaJcAAAwH+3W7CEXx90XXYYaAACAC9FuDsMQch9qQJQLAABljXYzjnKrS0S5AABAtJux6HKWCwAATka7e4Ix90SXimUAAHAx2s2wbzfLSULXiHIBAMC5aDfDvt1cJgkR5QIAgFViPZkng6MOiS6ThAAAwB1iPJkzmbebwVnu4jjzcgHc5lerGxtzf2zljf/a2PjNn9rT/OfZR3At2lVWtrWSuTLngOhWzzS/6O0HznFBAQwhQdz8Ur9x8s8bG5f/vrHxjx83Ml/6dz75W12YJd56DU99wLUAW6j2KBztmhbdoX2Lo+Eo9+E3v+JiAhQUrR6+VBc6Cd7X32+YW//7f3VB/vcv618Efn2B6wbFodqjSLQ7WdltV3RDZhgqw+ZCAuTDzPmNjcpndRFzeX3/z42NP/ylLsJ7V7iukC+qQQpFu5dNim6c5aPKsLmIANmhFK0i2f/+H7eFtt3Se1NKGgGGPFANUtQaMthlUHRbzTC2zb7NBQTIAJ2HKh279oO/Qpu0lCZXBPxv/8F9ANlx1wtnW0V3b3DKnuiG2oRUfs3FA0gHRXkS2jyKnlxY2oe3rmxs/Pz33BuQPlmaZaQjuHuCibAZxhPv/8jFA0hJbFVwxIo//1V6HfGFtImYZaTUPpRWlLuMGQZAeqgo6nfXENtexFdpZ+4dSIvRwxczKahKa5rQDdqEANIR25WvEdF+15Xr9VYp7iUYFLUPZTFrN4UoN3iOAioAxNbSUrUz9xUMSqSgaio4ZkB0WwuoFJJzsQC6RwVBpJHTX//5V856YTBiZu2uD+rHnLrP8sTJ77hYAF2gIim1wLCyW3LhIt0M/RI7fWg6mClOdEMOVArFuVAAnVHRj4p/WNkv7TPCC/1y3/xH4Wh3tRDRrRVQKdRuejEPVr/gIgG0QelOpT1ZCC+4gbK3kYKqfYuj+YvudGW2+UUoBFcozkUCiOelj+2bWzQGEGgCkYYlhMf7iUOf1HtjXfN4lvAy2Qj6YXj/6ZDwLs3nL7pT1ZXmF6GRSFwcgHjUc2tZjPT6+pmBq8hdqXJXLCl1xouFJPSKsrihnt1ruYru0PTCcLg395ETa1wcgBB6wFstlpJQpmUoofep6NeFKmxNMOLehF5QFvenvzzWKrx7gokcRbc1tUxvLkB8FCizBmtLKW71sWYR8anf2IWoVyMQuUehF0ZePh+KdoOj+YluKLVMby5AVHwsjtvLo3fVBeHVFw9GBUIvyGkxlGJey0V041LLj71znYsCsIWKdayJTt7exBJe6y1RGiTB/QrdEptinq7szF50Q7aPtz/9LhcEYAu1pVgTG30BkAjmvRcSeeuLNiLohUiKuQ9byH5Sy6vN/+iOI5e4GABn6y1B1gqJlOIuMo1q3XGLoirohTRSzD2mloMRbB8BoqjdxtqS4BbtPawI2/LSlyTOdqFb4lPMwa7sRDeUWr7z+fe4EFB6LJ5fWhDcBtZNNNTqxH0M3RKtYq4uZye6pJYBWpCwyXDB0tIZrqXozfrZriqZuZehWyIp5h4nDw2UWtaQXy4ClBlrZ5YSkCKKptqhfmDrphkUVEG3DJpi7tsQQ16UXAAoM2o5sbb6sXLMA+tDHhh6D70wSIq5B9Gtnmn+R+5f+JTNh9IiRyNry/LZpF6b5aVzZ+5r6JaYKuZrqYpu3Bi/R5e/ZfOhlCiatJYutS4amkxkeel6cm9DtyjF/JNfvBH2Yh5LT3SnKzvxWgawWansgqWhXp/1xdg/6IW7XjgbdqeaS090J4Ojzb9c+Ww2HcqIxQEGedo7DoL1WcKKxrnHoVt0xBoqLl5NUXSrl5t/uWYLsulQNt66Yk8oXDqLtD4EQdeX+xy6RcZQoXPdG920DnUW3H2Lo+FWoSfe/5FNh1KhtLK1c1y9HpdSotb6mcNr5Wvuc+gNHbW2Cm9l9+CiS6sQgElXJdciM+vOVPgwQ6/ce+hCOMW8lILotrYKMTsXyoZFRyWdj2YxhL7MokvbEPRKP61DPbcKPXJijc2G0qCqW4tzYV0pnkJ0wWdiW4f2LY72L7qhViFZX7HRUCaUcrS2NMzAxb1EdMFHth8411PrUE+tQne/uMImQ2mwauigub2ILqILNnjgtc9Dols907/ohqYKjVWusMlQCjQ9yGJfqatRrrDY44zowqA89s71yNShASLd6g2sH6GMWBxmoOWygYP1Pl1EF/olMnWozblum/PcxXHOc6GMqHjK4ig6l6NcF0SXPl3ol5hz3dk+RLcy1/xL9EvZXCDKJcrtF+sL0YV+2XHkUtej/pJFd29wqvmX6JeyuUCUW8xysS+3GTl6WV8n/8z9D/0xfvyb8Lnu1d5Fd7J6rfmX6JeyuUCUW8xyfcj6ry/YF10Xe5/BBurXDdslD00vDHctumG/ZTX/6peyuUCUm//Sa7I+uq8Thy/ZF119MeBzAP1yxzMnu/JhTohyK7vxWwaiXBvLB09gRerWl+tfbKBYuvVhTurPXWr+y/plbCoQ5Raz5v7o/v5adPZqXrL65HMAg6CRtyGTjIs9RLqt83Mfev1LNhWIcgtYGofnw/5aH+v3yd/4DMBgdDtfN37IQcgUg/m5QJRbzHK9gErI3cv6+s2f+BzA4Nz25Ilwv+7OzqIbMsW4/el32UzwGqvnjT4UUAmlx60vH1L4UDzdDD+IG3LwHKYYUCaspj59SXm+dcW+6LrcAw120Lz51mKq4Fhn0Q0VUWGKAT5jOQpTm40Pe8x0ISgLqn/qVEwVJ7orFFFBWbBaVatqWh+iLxfOcyuf8TmAdOhm4lBc5fJa81/SL2EzwUcsF1D54gMslyfri/5cSBOZSbWbOBQqogpGmCwEZcGyYYMvhT3W+3NJLUPa3Pn8e22dqcKiu6v5D+svs4ngK1YLqHwxalBq2WomgdQyZMU9r3wYEt3gYBvRbR3np7/MJoKPWC6g8iW1LEGzvHw5Nwdb3L/waavo7g1OJYvuVHCs+Q/rL7OJ4COW056+VC3/9//YFl25kPFZgLSJjPmbrF5OFt2Q/eMjJ9bYRPAOywVUel1Ky7q+x79atS24vhiPgD3k4Bi2g2wnutg/gvdYLqDypbDnP/9qW3R9mNwEdonaQS6OR0R3aE8w1vyHts2+zeaBl1y5blcMfCjscSHKfeoDPgeQHXe9cDYkusFMVHRDlcv6S2we+MbMeduCoNdHlJvt4iwXsiYyW7epgjnRc5nKZfARy6nltR+IcrNe//iRs1zInkgFc5MHc7PoHsVzGXzHsg+wDxGY9SjXh1GJYJ+IB/NUdSUqunuDU81/6MHqF2weeIV1H+BDn7i9v3r9lpfO8unLhTx4dPnbsOhejTnTrV6kXQh8xrIPsIp7XBYEfaFR6tby/vpwXg5u0K5tKHHQweOnfmDzwCs0n9bqcr1V6HfXbEe5+sLFZwDyJNo2FIzcFN2hZ49va/6fmpLApoFPKIq07AOsQe+u7q31tDI9uVAEkcEHe4KJW6Ib6tG9/el32TTwClkrWl6q+nVxX5WylYex1aWhFj44fIF73P3iSmyvLj26UAo0RMDqcnWqkLIHlo1GtK+c40JR3Df/UWyvLj264D0SB8vRmKvnuWpxsrp0lODLTGJwkwde+zy2V5ceXfCelz62nVr+zZ/c21O9ZsuLwikomoff/Cq2V7dRubzc/D/V2MumgS9Yjsi0XIvIEFyAzjz2zvXYXt2tObrV1eb/qXmAbBr4guW5rq7151o+G0dwwRIxvbprzZFuyxxdKTSbBj5g3YXKpfNcBBegN0KR7kaz6F7DGAN8xHoPqSvnuQguQO9oRG5r29DCcCO93PI/2CzwBevnuS74LVtvt1KhHPc6WESeFy36um9xdKimvE0/lHUVmwW+YPk8V8uycYNG4Fm2ztQoRFdNRaAcDO8/HYp0KzuHasrb9EOFw2wW+ID181y5JVndO43As9zbLFMO5uKCdWJcqXbJAnKi+YdSZjYLfMD6ea7Sttb27KkPbLtMaZ38MyP6wA1kNBWKdGcjFpDbD5xjs8ALrJ/nVj6ztV8aumB5KIRGB3J+Cy4xevhixApyqKa8TT8cefk8mwVeYP0818p5pAvRrc6WGVwArnH/wqehtqGl+aGa8jb9UMrMZoHrWD/PVURZ9B5J9JXith7d0g4ErjJWuRI2yFjGdxm8xPp5blGmGDoLlYhZj2y1fneN6BbcRu6OrWe61TMR32UpM5sFrmP9PFfFQHnuh0bcScQsVyQ3lo4Ffn2Bexjc55ETa2FXqlVEF7zE+nluHqYYihIPX7Lda0sqGXxm4uR3iC74j/XzXK0s0qY6o1VFtM5p1QPsypLYqi+YNiDwXnSnqxeZMATeoVF5lpeclAZ9jxIovU95NyuStVwMlbSU6tbrR2yhNKKrOQeILviG9XmvaZhiWD+z7iaypUgKEF1EFzzgP/9qW3QkOIO+Rxeqj+MifM5sAdFFdMEzrFfoDmqKoXSsS+lkpb9dmKYEkDYakxsVXR3sNv1QJc5sFriKWmMsrzRMMdRO40IKWW1Ruh7cl1BmQqK7Fhlgr3CYjQJXUfrS8krDFEPpaavrD38hqgVIFF2B6IJPlMEUw9qZtV6PvuxQGAWA6ELJKIMphgqSEFoARBegUFRgZH0NOnjdwpm17CS53wBSEl1VW7FR4CJlMMWwMMghjZYnAESXSBccx3KBkZaKjAZ9jxbOrFWBLYMPhhIAILpQYjDFyH/J41nva9C0OQCiC+AY6g21vHw3xVAk/9LH3IcA7UV3qnoV0QXXccEUY1BjfxdMMRrRL726AMmi22ID+ejyt2wUOIfmxlpevptiJL3nQaN7AJd54v0fw6K7jvcyeIF1Uwy9vkHfo6qz1a7j0qzcRtqZM18oIww8AG+xPnUn7XSr0ukyp1AVsQWzjE5L6XWNXMRMAxBdRBccx4WpO1lHejrvVURpfSlKJ+UM5RbdyeoyogsuY73AKA1TjG6RuL91xXb0qy9Ilc+4bwHRrfFg9Qs2C5yiDKYY/aD0s+U2KqXGB63oBrCMCpNDons5IrpjlStsFjhFGUwx+kVnqBI3q0sDKp76gHsY/ESZ41D18iqiC85jvZDIgl2iTCusRr3f/xNTDSiT6E4tzTf/8P6FT9kscAadYVpeaZhipBn1fvI3u/tEgRX4xsNvfhUW3ZXNSDc42PzD0cMX2SxwBgtTd9ottTJZ2i99AbAqvIp4STWDTyhzHDrTXR4amq7MNv/wnlc+ZLPAGcpgipEFVs95dVSgHmTubfCBHUcuhUQ3OLoZ6VZ2N/9w5OXzbBY4g6wGLS/LHsRWhVe9vJhogA8oc9yaXl6aV6S7s/mHw/tPs1ngDNZNMSxHbUo1W7WUVFUz7UTgOgpiW0RXmeWhPcFY8w/vfP49NgucQIU3lleephj9YtlY5OSfucfBbe5+cSWUXq7sHhratzja/MNts2+zWeAE1k0x1D/swj5aPRenohlcR5njUKS7c+jVV18dav7hT37xBpsFTmDZ9EGrSFOMXlAa12qvs9LM3OvgKnc8c7JVdJVZ3hLd9eb/wWaBC2CKkR7yQra65CXN/Q4uosxxa6QbjNRFVybMTf9DJs1sGFhG1a2WlyVTjG6jXatFaXpdtBGBiyhz3KytNb2t/We6erH5fzz2znU2DEyDKUb6/O6a3f105XwcoMHPfvuvsBvV+i3RZaYuOIYGolteVk0x2mG9GpyiKnCJuLF+t0SXoQfgGJhiZIMKl/giAzA4j5xYiww7aIp0W4ce4L8M1pFPr+Xl6hmk5QyCa+fkUG40mz7su9x0ptvqv4wVJFjGehpUI/Rc3VvrZ+WqsuYzAC4QZwHZLLpYQYIzWG5v0XK56Mf6qET6dsEV4iwgb4kurlTgEJhiZIvVYfeN5VL/M5SXODeqm6IbdqXCIAMsY7nYR2vuj27vryJ1y4uCKnCBiDHGZnDbKroYZIADYIqRPdbbsVzsgYbyEQ5kb2ptU6RLry6Y56WPbQuCD2eOC5/yxQZgEJJ6dMORbkuv7gOvfc7mAVFYCVOf1r/YaHGuC5ZR0BrXoxuKdFt7de+b/4jNA3NYP288fMn9PdaZtPXlerEa+I0MpuJ6dFtFN9Srq+G7bB5YA1OM7HnqA/uiixczWCapRzcsui29unc+/x6bB4hBD8tlU4xm9MXB+tJYRz4TYBUFraGRfjMxohuMMMweLGO9wMeX6EtFSi4siqnAKpHh9dOL4xHRjRtmz4g/sITl0XNaPp0zurCYsQsW0Ui/8BzdoWePb0sS3ZXmPyjDZjYRrIApBqLbvBj1BxZ5dPnbcOXy1RadDYnuEhXMYBEXUp4+pTtdWD59yQF/iEwXmq6eSRbdUAXz9gPn2EQwgfU2Ft+M+F1YPrRngX8oWG1tFwqOthHdxfHmP3zbkyfYRDDBW1dsC4BPfsCuFFKpsI7PBljjrhfOhkS3sjtZdJ89vi3sF/nE+z+ykVA41k0xfBIAF1qGtOROxmcDrKFgtUVH9wRjiaK7da57FQ9msAamGIguogvWUZAacqK6EdHYyA/2Bqea/9L9m1/h2UxABJKXvhCw34guwCMn1sKie7mz6E4GB5v/0sjL59lMKBQVzFhevlkSapgAogvQOwpSW0R3M4jtQnQru5v/kpw12EwoEhUpWV4q8uJLTv6LQiqwxj2vfBhqF6rMdRbdGDtIOWywoVAUmGLki/VKcUQXrBK1fwx2dRTdrdm6axRTgQXUvqKh5ZaXbx7A1u02ff2yA24TKaKqie7CcHeiO1090/wXdxy5xKZCIWCKkT+f/A3RBeiVyOD6mCKqNqJbmcOZCiygIQKWl0+mGA2+/t4N0dWoRz4jYIXIDN2mwfVdiG6rM9VPf3mMTYVCwBQjf6yn8xuLKUNgieH9p8NFVLNdi+7Wue6N5l8wcfI7NhZyR8PKibbyQ+/HlfXz3/P5ADsoOG3nRNVZdKeqq82/YKxyhY2FXMEUI39caRfSlzE+I2CFmHF+64namiy6S/PNv0T9R2wu5MmhT2w/+H0zxRDWe6J93ntwl4gpRmicX3eiO13ZiUkGIADJy0dHpCvX3RBd3wxJwG1UbBwa53ewd9Fl4hAUzOW/237w+9iy4koR1Usf8/kAO2ybfTtcRLWzZ9HdKqa6jEkGFIELphi+FfL8atUNwfVx78FdVGQcniykoLU/0Z2qLjX/MvUhscmAAPhpilH5zA3B/cePfD7ADioy7sYUo8tIl+EHUAzWTTFklejbnrviREURFVhCk/hCR7FL/Yvu9MJwuF/38VM/sNGQOX/4i+0Hv2+mGC6k8xuLkX5giUh/bpvz3I6iS78uFAWmGPniSn+ulub98hkBC8QMrW97ntul6Lb269794gqbDZmiIhnLy0dTjJWv3RBcTDHAEhG/5Tb9ud2LLj7MkDOYYuSLUsv6IuHCOvlnPh9gh279lnsSXebrQt7owcqDPz/U80pqGaA3Yufn7lscTUt0l2kdgrywboqh80+f9tv6JCdSy2CRh17/sqdWod5EdzNkpnUI8sJ6Fa16iH3Z670r7lQtk1oGS0RahSaDoymK7sJwOIxm1B9kgQuuSDoD9WW/rafySS2DVXqxfuxZdOvCW71I6xBkjXVXpK+/92ev9eVB7k4uLB8dwMBdehnl17/ohlqH7nrhLJsPqWO9dUXnzb7stQw+XFmqaOfzAVbYceRSq+juDU6lL7qhUX8/+cUbTB2C1FEkiejmg6JHolyA3rnz+fd6bhXqWXS3qpivkWKGrLBuiqHlS4+u9V5oolywymPvXI+6UE0vDGckusFRUsyQFS70iyr97fo+6yzXekaBKBesEnGhmqqu9KSjPf3hPcEEKWbIChnZI7rZY32CE1EuWOb2p9/tO7Xcs+huDUC4SooZssCF0XKui65S+FQsA/RHpGq5x9Ryn6JLFTNkgwv+v/pi4PIe//uXRLkA/XLf/EcDpZb7E909wRgpZkgbF0wxXI++ZC7hivuU5inzuQBrRA0xgpnMRZcUM2SBKz2jSs26uL9KK1ufUdxYep16vXwuwBL9zM5NT3Qng4OkmCFNfnfNnbTn3B/d219Xhhq4ur/gP/ceutC3IcbgortvcZQUM6SJK0YNWq4VU7lUrcxQA7DKbU+eGDi13LfoxnkxP/Da51wY6Dv16dLSuagrQw/U++zKOe6V634NkwB/0Az5NFLLA4puZY5xf5AGSie6ttRTjOCm+0XmqQ/4LIBN7n5xJZXU8oCiG4zU1L7phaiHiQsEveKCKUacSFieq+uS4GqpkI7PAlhER6c6Qg2llnflLrpbKeYzzS/knlc+5CJBz7hU5BNOhyK45cgaQHm5f/MbYSi1fG0g3RxMdINd4YKqn/32X1wo6AkXTDGSloqqLJ1DylACwQVIDx2dthpiLM0XJrpbk4fW6NmFfpk5767gNpZcqooWXv37LrlNIbjgAjHD6pVaHilYdFsnD2nOIBcLusWlQertllqe9AWiiD1UAZJLLVda+oLA/Q/WifTmTlfPDKyZA/+CUM8uBVXQC65FZ+2W0rpvXck3ulUPrmvpeR8mNYH/6Kj0p788FjrPrewuXHS3bCFXm1+Yvh1w0aAbXIvQulmaVatipiz3rfKZO9OCmpecx7jvwQUerH4RLqBa67c3N33Rna7MNr84OXdQUAXdRGouFf30uuQhrMh370o6+6Xfo3S8Kx7K4SwAbUHgErI3bhXd4GgqepnKL9lU/80Xtd78AvUtgQsH7XDRFKPfdfnvdYtDVRf3cvaryUD6ey5nBBT5W+5pBggzcfK7aAHVvsVRM6JbTzEHx3Cogl5wyRM4KzGSGIfxKeWuHmwmBoFrRAqopqqrqWllar9oenGcgiroBVdNMVidl9LJ+lLFfQ6uoaPRiANVCgVUqYtu3BCE7QfOcREhERcLgVidl86clRbnHgcXiXGgSqWAKhvR3fw2EI52lRvnQkIYH0wxWK1LrUsqHGNSELgc5UZH+FXmUtXJNH/ZlkPVZdqHoBMqKGL5s9RvzdktuI4cFdMa4Zef6IZG/ik3/vipH7ig0IJPphhlXrLAZCQf+ELUZ7m6lLpGpv4L1T4U8mNWjpwLCs1oQg/L3aUKa7V8cS+DLzz0+pep+yznIrpx0S5mGdCM76YYPq8//CV7ty2AIhjefzp1n+UcRTc64J7pQ9BAla2Wl1qZ5A/MF4P6UpW5DDrSctYCsEb8NKHFcWdEd8uPeQmzDIjDuilGo79UIqPxc2VtbdJ57eFL3K/gP2pvDRVQXc5MGzP7xYp2Q98clDPnAoNSlJZXnGWhUqp63b5Hvzqr1ReNosYUApiIclM0w8hNdLfMMs4Q7UIYy4b9EtV2r13n0Wp30rQcFwcPhJfeg1Lpimhp+QGi3FqUey1TXcxWdKPWkES75UYpW8tL3se9vB9FhBIsibALnsn6UqEza40GpNUHiHLjznLTNcPIVXSJdiGMdVMM9Q8P+h7VSqP3qTStUtIS8ryXzqH17+r9yCVKr4mUMUDnKDdtM4wCRJdoF25h3RRDYplllC/xU6GWBFkotRueMhRXuKU0cPjPKWJt/B6h147nMcAAUW6GZ7m5ie6WNeQy0S6IIqK+XhZtMQCljXIv56KHufwjMX27D7z2ORe+hFiu/lU0yTUCIMp1XnTj+nZxqSofasWxvJSu5ToBEOX6Ibox0S6ezOXCFVMMACDKdV50iXZBRUOWF0VIAES5foku0W6p+fp7u4Krs2aGrwP4zfjxb+L6cnd6K7px0e5Pf3mMebslQG5HlpeMLbhOAH4TmZeb0SQhW6Jbj3Zb5u3ee+gCN4TnlMEUAwDsoqxqXpOETIlu3LxdocNtbgx/kXmD5bX5eeQ6AXjKE+//WKshCp3lLheif4X8o88e36bD6+YNuOuFs9wcHmPdFAOLRAB/UTY1JLg3lHUtjejWXaoqu7GHLA/f/9Ou4Oq1cY0A/ERZ1J/84o1chxqYFN24YQjbZt+mhchDMMUAgKIoYqiBYdFdHKeFyH90Xmp56byZ6wTgH8qeFmmEYU5041qIlAaghcgvrJtiaPIP1wnAL5Q1vf3pd8Oiu1K45hX+AtRCNFVdb96Ye175kJvGI6wPd1cPMdcJwC8iLUK14qn8W4TMiS4tRH6DKQYA5I2ypTJeCunKkgm9M/Ei1EI0Vb0anrlLUZX7vPSxbdFV6pvrBOAXd7+4Eo5y14pqETIpultp5l3haHfHkUvcQI6DKQYA5El88VTwnBmts/JCai9mb3AqXFQ1cfI7biSHUTuO5aV2Jq4TgB/EOk9NVy+a0jlTLyamqGp4/2luJofBFAMA8kJFuJHiqT3BGKLbvqhqNpwaGKtc4YZykKc+sB3lypqS6wTgB7Fj+6aW5s1pnLUXtNW7uxoedk/vrntgigEAeZDQk3u1SOcpt0R33+Jo2Klq5OXz3FyOoXF5lpfGDXKdANznvvmPolHunmDCpL5ZfFH1gQjBwfAmPvzmV9xgDoEpBgBkTexAg6ngmFltM/vCYsb/MRDBHf7tP2wL7toPXCMAH7jz+fdienIXhhHdfgcihKJd0sxuID9jywtTDAD3GT18MZpWng5mTOua5Re3lWY+ytxd93jrim3RfeO/uEYALvPIibUYwa2eMa9p5l9gjEWkPDUxzbANphgAkBUywdBxo1WrR6dF92aaOVTNjGmGbf7xo13B/d//q585c50A3ETHjNbm5HolulumGZFJRMrncwPaY+a87Sj3ynWuEYCryCwpaoJhY4KQV6K7ZZqxEt5s5fW5EW1x+JJt0VX/MNcJwD10rBgzss+kCYYfoitvZuXtQ21Eyu9zQ9oBUwwAyIKY9iBz3speie6W8O6ijcg21k0xlP7mOgG4RXx7UGXOOQ1z7QVvpZmXGIpgExUoqVDJ6lKBF9cJwC1i24OmqitO6peTLzrGrUo2YI+9c50btGB+fcF2lKtWJq4TgDu43B7kjejWXvieYCzcRsT5bvHIdMLywhQDwC3UHhqTVt7prHa5+sK32ogis3e3HzjHjVog1k0xZE/JdQJwg9hzXIfag7wT3bpNZHWZ/l07aJCA5YUpBoAbyO43RnBXndcs59+AznenqxcZA1g81k0xVFXNdQKwT2w/rsPnuF6Jbu1NaOj9VHUdf+ZiUf+r5YUpBoB9NL719qffjevHNTmUvpSiu3W+uzMc7d7xzEnm7+aIdVOMhU+5RgDWifVVdrAf13vRrZ/vBgcxziiOy3+3LbpPfcA1ArDM/ZvfjCOCuzc45ZVO+fRm6hFv9Uz4oulCckNni3VTjO//yTUCsIwMMOS34LKvcklFd2E4PH+Xwqrs0XxaywtTDAC7qP7mtidPhAV33TVf5VKKbpJxhr5BPbr8LTd4Rlg3xfjNn7hGABaRoVGkcMqh+biI7s2IN5gJX0Q5VlHRnA0rX9sW3Zc+5hoBWEOFrrGOU5PBUW+1ydc3llRYpYpmrCLTx7opxs9/zzUCsMbdL654XzhVKtGtvcGp4Fj4ot71wllaiVJEgmZ5YYoBYI/75j+KdZzyrXCqfKIrx6qp6gqtRNlh3RRDqW+uE4AdHnjt8zjBvapCWO81yfc3eLOiOTQKUOw4cokPQAqc/LNt0a18xjUCsII6SaJnuNU1OQuWQo/K8CZrb1RWkbqwoYv9YPULPggDYt0UQ+1MXCeA4lEHSaQX1yOLR0Q3EvEujse1EtHDOxgynrC6ZNjBNQIonoReXG9bgxDdW61Eu8IXXcIrNxQ+GL1j3RRDUTjXCaB4wVXLps+eyohuW+GtzIUvvqYSYZ7ROzovtbx03sx1AiiOx0/9EC+4jg+jR3R7biVamkd4B8e6KYYqq7lOAMUgTwR5I8QUTi2XVnvK+sbrwltdCt8MOnPAtap7vv7etujuXeEaAZgS3KnqSql1p8xvvrYBm9+4sIvsD+umGHLJ4joB5I/Mh2RCFCe4vptfILoIb2bIz9jy+sNfuEYAZgR3unqx7IKL6Lammlfwae6NX1+oT++xytwfuUYAeRPrpyxzohK4TSG6vWxEgl0kwgsA0B2y10VwEV2EFwAg45RyQoR7rSz2johuvxuS4NPMGS8AQLzgxp7hIriILsILAJAeygAiuIhuesKrajuEFwAgVnATjC8QXEQ33TNenKsAAME9GV80heAiuggvAEA6JA4voEoZ0U1VeGMMNBBeAEBwt4wvEFxEN/XNShBe5vECgO8owIidh4u1I6Kbt/CKB177nA8mAHiJAgvNHUdwEd1iNi1mLKC4b/4jPqAA4BUKKOKed2Uez4foFhLxBgfjbkS5sqhZnA8rALjOvYcuxAtuSQfQI7pFb950MLP5be9G+Ia88/n3sI0EAGdR4LD9wLl4wZ2uzPH8R3SL28A9wcTmjbiOiQYA+IACBgUOMenkG0OTld089xHd4jdx3+Lo5k15Na6y+ZETa3yQAcAJHnvnenxLkAKL6cVxnveIrqFU88Lw5o25Gr5ZVfH3YPULPtAAYJrx49/UAoUYwb2KyxSia3MzZaKxNzgVdw6iggQ+2ABgkfsXPk0qmFrF9ALRdaGy+WjcDaxzksdP/cCHHABMkDgHVyiAoAcX0XUn3VyZjatslqML57wAUDQ6v40dWlArmgqO8hxHdN2sbJ6srsWd8yqdwwcfAIrgode/TDq/XadCGdH1ssAKIw0AKILRwxeTzm+vbgYKYzy3EV0/NnqquhR3oyu9ozQPDwMAyBL13yYbXlTPUDCF6HoY9QYzcUYaSvMo3cODAQCyQHUkCf23OEwhut6f847FGWmIkZfPk24GgFTZceRS0oSg9U3B3clzGdEtxzmv0jkxwnv70+9S3QwAA6P2xOH9p5PSyRcxvEB0y7f5CZOK9K1U3055cABAP7SpTt4kOEb/LaJb5nTzRFK6+a4XzmKmAQBdo+MpHVMlVCfTDoTows1082R1Oe6Dom+rD7/5FQ8UAGiLjqV0PJVs5xiM8LxFdKEl3VzZHVfdLO555UOKrAAglsRiqdo4vuAgz1dEFxKj3mAkyUyDIisAaEY9/rGzb2+ZXUzwXEV0odsiqxjv5kbUq0Z3HjoA5URZrzatQBRLIbrQX9S7OJ5UZKXBCZz1ApSPDme360PTwS6en4gu9HuBNKM3YVRgw7+ZCmcA/1F2S1mupGfBJisUSyG6kNaFqk8supxU4TxWucKDCcBTlNVSdit+DF91jVYgRBcKOOtVX+/Eye94SAF4grJY+lwnRrdqNWRQAaILmUe9Y0kVziqs0Ogu2osA3EaFUsmuUtWr+CYjupD3xZuuzCb19SoV9WD1Cx5eAA6mktsUSm3UajyoTEZ0oSjhDUaShicI9fDR2wtgH/Xctk0la0jB9OI4zz1EF2yI765aQQVVzgBOoark++Y/aleVvI6rFKILFi+m2oumluaTCq047wWwxQOvfZ5cldwwuaANCNEFB1LOe4NTSR9kznsBimX8+Dcbdzxzsl10u0oqGdEF1y6uent1DpTwwdaHXnM3eQgC5MOjy99ubD9wrl0L0DV6bhFdcD/ynWl33ov4AhQstlvntlQlI7pQkvPehvgq7cVDEiAdZFbTZqh8HR0FcW6L6ILH571ysWnzEBjefxrxBchabHVuy+g9RBdKc9471q6/F/EF6B215d176EKbkXuNIincpBBdKGnkuzjejfgyRhCgc2TbVmw1sIQiKZ65bALUxbeyM8nPufnMl2lGALdQJqhDgVTdJxmxBUQXEsW3TZuR2Db79sb9C59isgGlRV8+O/TZ1tt/piuzPFcA0YXON8bmN/Ok+b3Nc3zlcIW9JJQB2TXqy2Z7BynEFhBdGDzybXvmq3Ose175sGbYzsMZfDyvVXFUmzF7t85sp4MZnhuA6MLgN8q+xdFaq1GbPt/GVCOl3kg9g+vIKrXt1J9b03/OUI0MiC5kFPkGI1smG2udUs+q5mSsILiEsjWKartIId+ofQndE4zxXABEF7K/ceRwNV2ZrZ1fdYgENJBbZ2Gc/YJFlJVRdkZZmo5Rbd2u8SgOUoDoQnE3kYqupqorXTywanN96fkFK1GtahE6ntXebPsJnsMbGRBdsHMz1c59g4PdRL9K3+mBh+MV5C20qrhX9qWrqFbzbLFqBEQXzN9Y08GudjN9w32/OkfTJBaEAbKoPu5BaBs2jbNEtYDogoviO9Jt9NsQYD0gaT+CQYVWdQQdDSxuFUat1c5q9y2O8rkFRBf8uNn2BBPdtB01F2DtOHKJCBi6Th33KLQ3tsbq7eLzCYgu+HvT1Sqfg5naA69LAdYZsFqQ1DspZyBEBlR1/NDrX9ZqA5Qh6TJ13OirJX0MiC4gwN0+ONXecd/8R/QBlzRt3JVpRdw57fTCMJ87QHQBBhBgtXyoFUm9lnooI05+RbNqMVOhXQ+FUI2I9mKtzYeeWkB0AXoQ4FrrRvcPW6WiNW5NERGRsHuRrI4QJLJdn822srIZ0c5REAWILsAgN2qtCCs42mnyUdJAhuH9p2tV0Yqa8IW2g/q0VSynL0kdrReTJvqol1YGLZzRAqILkMFNqzYknc/1EQU3UBSlaErRsB78CHE+AvvAa5/X9r1Ly8X4imMVQiltjO8xILoABUbBOsPr50He1COsAh1FxKqKpVe4/9Yd7Z/2URFsz2excWezU9UlWnsA0QUwGQlXdtYMOepzgNcHeuBvVUqrXakhxorYyt62pMyA9qEhrmrbUQp/0L3eKqBbrU2y0nUkZQyILoBzkfBYLR1dO/vr/Uy4U5paYqP2pcaZsS/par0Pofel96f32XdauJ0TVL1vdg6PY0B0AbyMhBeGa1GUoql6e1KqQhwXKUuwRCNiFiogaghbg6yqrTVWsfFvNKLTBo3XJlR0ltle1K1At6LYYIYKY0B0AUotxovjNTGQKEgcuvSLhrjpPBLX6lK9T5Y0MQCiC9DNB6TWL7wpGkp/1iK02jnxahpnxR6wejNyrZ2ha58wogBAdAEyjY69FeVbotoobNqE6w6A6ALY/ZDtWxxtCFbNxKEhYo00djMDtj0ln6M2Exy7+e830r81Fse5XgDZ8v852iVz2qoKWQAAAABJRU5ErkJggg==", - fileName= - "modelica://SorpLib/Resources/Images/beta.png")}), - Documentation(info="<html> -<p> - This partial model is the basis for the mass transfer correlation models based on the loading difference <i><code>Δ</code>x</i>. <br> -</p> - -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); - -end PartialMassTransfer_dx; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/package.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/package.mo deleted file mode 100644 index 467644e486084fcc8c331a3367f10671ceffe46a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena; -package Partial -extends SorpLib.Internals.ClassTypes.PartialPackage; - - -end Partial; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/package.order b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/package.order deleted file mode 100644 index 3b73eff722fdad7cf76a00d0b184935b66916c56..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Partial/package.order +++ /dev/null @@ -1,2 +0,0 @@ -PartialMassTransfer_dp -PartialMassTransfer_dx diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/Lanzerath2015_SilicaGel.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/Lanzerath2015_SilicaGel.mo deleted file mode 100644 index 29261b74490c1c9f470eb6b465ba0445cb6ea018..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/Lanzerath2015_SilicaGel.mo +++ /dev/null @@ -1,26 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena.Records.DiffusionCoefficients; -model Lanzerath2015_SilicaGel - "Diffusion coefficient and particle diameter for Silica Gel 123 (Lanzerath 2015)" - extends Glueckauf_dx( - final D=1.8e-10, - final r=0.00045, - m_ads=2.236); - annotation (Documentation(info="<html> -<p> - The diffusion coefficients in this record were determined by Lanzerath et. al. (2015) for silica-gel 123 particles. -</p> -<h4>References</h4> -<ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end Lanzerath2015_SilicaGel; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/Lanzerath2015_Zeolite13X_ads.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/Lanzerath2015_Zeolite13X_ads.mo deleted file mode 100644 index 40a4337a98ea48dc6eda7f712a6d57f11cdabe2b..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/Lanzerath2015_Zeolite13X_ads.mo +++ /dev/null @@ -1,26 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena.Records.DiffusionCoefficients; -model Lanzerath2015_Zeolite13X_ads - "Diffusion coefficient and particle diameter for Zeolith 13X adsorption (Lanzerath 2015)" - extends Glueckauf_dx( - final D=3.416e-10, - final r=0.0007, - m_ads=1.833); - annotation (Documentation(info="<html> -<p> - The diffusion coefficients in this record were determined by Lanzerath et. al. (2015) for Zeolite 13X particles during adsorption. -</p> -<h4>References</h4> -<ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end Lanzerath2015_Zeolite13X_ads; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/Lanzerath2015_Zeolite13X_des.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/Lanzerath2015_Zeolite13X_des.mo deleted file mode 100644 index 0d241a66ebefb4b9db9fed2744d32765bb00dcd8..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/Lanzerath2015_Zeolite13X_des.mo +++ /dev/null @@ -1,26 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena.Records.DiffusionCoefficients; -model Lanzerath2015_Zeolite13X_des - "Diffusion coefficient and particle diameter for Zeolith 13X desorption (Lanzerath 2015)" - extends Glueckauf_dx( - final D=3.055e-9, - final r=0.0007, - m_ads=1.833); - annotation (Documentation(info="<html> -<p> - The diffusion coefficients in this record were determined by Lanzerath et. al. (2015) for Zeolite 13X particles during desorption. -</p> -<h4>References</h4> -<ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end Lanzerath2015_Zeolite13X_des; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/SakodaSuzuki1984_SilicaGel.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/SakodaSuzuki1984_SilicaGel.mo deleted file mode 100644 index ce17c47fbc376c85557dc744fde86fe4807c156c..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/SakodaSuzuki1984_SilicaGel.mo +++ /dev/null @@ -1,26 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena.Records.DiffusionCoefficients; -model SakodaSuzuki1984_SilicaGel - "Diffusion coefficient and particle diameter for Silica-gel Fuji-A-type (Sakoda Suzuki 1984)" - extends GlueckaufArrhenius_dx( - final Dso=3.055e-9, - final r=0.0007, - m_ads=1.833); - annotation (Documentation(info="<html> -<p> - The diffusion coefficients in this record were determined by Sakoda and Suzuki (1984) for silica-gel fuji A. -</p> -<h4>References</h4> -<ul> - <li>Sakoda, A.; Suzuki, M. Fundamental study on a solar powered adsorption cooling system. Journal of Chemical Engineering of Japan, 1984, 17(1), 52-57.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end SakodaSuzuki1984_SilicaGel; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/package.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/package.mo deleted file mode 100644 index 80fcd4ce92797f2490337dff1c2975fd7df50170..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/package.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena.Records; -package DiffusionCoefficients -extends SorpLib.Internals.ClassTypes.RecordPackage; - - - - -end DiffusionCoefficients; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/package.order b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/package.order deleted file mode 100644 index 65473a9e965187c1f143d25eb48d47cffbb207c4..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/DiffusionCoefficients/package.order +++ /dev/null @@ -1,4 +0,0 @@ -Lanzerath2015_Zeolite13X_des -Lanzerath2015_Zeolite13X_ads -Lanzerath2015_SilicaGel -SakodaSuzuki1984_SilicaGel diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/FlowRes_Lanzerath_ads.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/FlowRes_Lanzerath_ads.mo deleted file mode 100644 index 433ede49b778d808419dd61264bd04f9a23d25b9..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/FlowRes_Lanzerath_ads.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena.Records.FlowCoefficients; -model FlowRes_Lanzerath_ads - "Coefficients flow resistance evaporator -> adsorber (Lanzerath 2013)" - extends Laminar_dp( - final zeta_lam=14.8, - final L=0.455, - final d=0.0382); -end FlowRes_Lanzerath_ads; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/FlowRes_Lanzerath_des.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/FlowRes_Lanzerath_des.mo deleted file mode 100644 index 9d05faa2b333e9521c757e390ce9e4fc3a783abc..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/FlowRes_Lanzerath_des.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena.Records.FlowCoefficients; -model FlowRes_Lanzerath_des - "Coefficients Flow Resistance adsorber -> condenser (Lanzerath 2013)" - extends Laminar_dp( - final zeta_lam=30.1, - final L=0.38, - final d=0.0345); -end FlowRes_Lanzerath_des; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/package.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/package.mo deleted file mode 100644 index 8631734070cf62d61f8f261bfd2f8ea31f75892d..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.MassTransfer.MassTransferPhenomena.Records; -package FlowCoefficients -extends SorpLib.Internals.ClassTypes.RecordPackage; - - -end FlowCoefficients; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/package.order b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/package.order deleted file mode 100644 index d6a83bacaf1ebedc8bcf09ba14fb085e4b95b7d2..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/FlowCoefficients/package.order +++ /dev/null @@ -1,2 +0,0 @@ -FlowRes_Lanzerath_des -FlowRes_Lanzerath_ads diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/package.order b/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/package.order deleted file mode 100644 index 44b738a1192fdc036d1e5540673641cf4913a924..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/Records/package.order +++ /dev/null @@ -1,2 +0,0 @@ -DiffusionCoefficients -FlowCoefficients diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/package.mo b/SorpLib/Components/MassTransfer/MassTransferPhenomena/package.mo deleted file mode 100644 index 50b60c8c036bc15d94ce909a9c169fbaea3995d9..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/package.mo +++ /dev/null @@ -1,14 +0,0 @@ -within SorpLib.Components.MassTransfer; -package MassTransferPhenomena -extends SorpLib.Internals.ClassTypes.ModelPackage; - - - - - - - - - - -end MassTransferPhenomena; diff --git a/SorpLib/Components/MassTransfer/MassTransferPhenomena/package.order b/SorpLib/Components/MassTransfer/MassTransferPhenomena/package.order deleted file mode 100644 index 0ae71e8da83a78d2f70a9df7547f292fee1dc24d..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/MassTransferPhenomena/package.order +++ /dev/null @@ -1,10 +0,0 @@ -ConstantCoefficient_dp -ConstantSpecificCoefficient_dp -Laminar_dp -DarcyPorousMedia_dp -DarcyPackedBed_Spheres_dp -ConstantCoefficient_dx -ConstantSpecificCoefficient_dx -Glueckauf_dx -GlueckaufArrhenius_dx -Partial diff --git a/SorpLib/Components/MassTransfer/Partial/PartialMassTransfer.mo b/SorpLib/Components/MassTransfer/Partial/PartialMassTransfer.mo deleted file mode 100644 index 7a07c0afbd91d8ff7add793855440243cd7961c2..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Partial/PartialMassTransfer.mo +++ /dev/null @@ -1,185 +0,0 @@ -within SorpLib.Components.MassTransfer.Partial; -partial model PartialMassTransfer - - /*********************** SIM ***********************************/ - - parameter TILMedia.VLEFluidTypes.BaseVLEFluid vleFluidType=sim.vleFluidType1 - "VLE fluid type" annotation (Dialog(tab="SIM", group="SIM"), choices( - choice=sim.vleFluidType1 "VLE fluid 1 as defined in SIM", - choice=sim.vleFluidType2 "VLE fluid 2 as defined in SIM", - choice=sim.vleFluidType3 "VLE fluid 3 as defined in SIM")); -protected - outer TIL.SystemInformationManager sim "System information manager"; - - /******************** Connectors *****************************/ - -public - TIL.Connectors.VLEFluidPort vlePortA( - p(final start=pStart), - m_flow(final start=m_flowStart), - final vleFluidType=vleFluidType) annotation (Placement(transformation( - extent={{-102,-10},{-82,10}}, rotation=0), iconTransformation(extent={ - {-101,-10},{-81,10}}))); - TIL.Connectors.VLEFluidPort vlePortB( - p(final start=pStart), - m_flow(final start=-m_flowStart), - final vleFluidType=vleFluidType) annotation (Placement(transformation( - extent={{82,-10},{102,10}}, rotation=0), iconTransformation(extent={{82, - -10},{102,10}}))); - - /*********************** VLEFluid ***************************/ - - TILMedia.VLEFluid_ph vleFluidA( - p=vlePortA.p, - h=noEvent(actualStream(vlePortA.h_outflow)), - xi=noEvent(actualStream(vlePortA.xi_outflow)), - final vleFluidType=vleFluidType, - computeTransportProperties=true) annotation (Placement(transformation( - extent={{-100,20},{-80,40}}, rotation=0))); - - TILMedia.VLEFluid_ph vleFluidB( - p=vlePortB.p, - h=noEvent(actualStream(vlePortB.h_outflow)), - xi=noEvent(actualStream(vlePortB.xi_outflow)), - final vleFluidType=vleFluidType, - computeTransportProperties=true) annotation (Placement(transformation( - extent={{80,20},{100,40}}, rotation=0))); - - - /****************** Additional inner and outer objects *******************/ - - Modelica.SIunits.Pressure dp "Total pressure drop"; - - inner Modelica.SIunits.MassFlowRate mdotHydraulic=vlePortA.m_flow - "Hydraulic mass flow rate"; - - inner TILMedia.Internals.PropertyRecord properties= - TILMedia.Internals.PropertyRecord( - d=(vleFluidA.d + vleFluidB.d)/2, - h=(vleFluidA.h + vleFluidB.h)/2, - p=(vleFluidA.p + vleFluidA.p)/2, - s=(vleFluidA.s + vleFluidB.s)/2, - T=(vleFluidA.T + vleFluidB.T)/2, - cp=(vleFluidA.cp + vleFluidB.cp)/2, - q=(vleFluidA.q + vleFluidB.q)/2, - transp=TILMedia.Internals.TransportPropertyRecord( - Pr=(vleFluidA.transp.Pr + vleFluidB.transp.Pr)/2, - lambda=(vleFluidA.transp.lambda + vleFluidA.transp.lambda)/2, - eta=(vleFluidA.transp.eta + vleFluidB.transp.eta)/2, - sigma=(vleFluidA.transp.sigma + vleFluidB.transp.sigma)/2), - VLE=vleFluidA.VLE, - VLETransp=vleFluidA.VLETransp, - crit=vleFluidA.crit); - - parameter Boolean computeTransportProperties=false "If true, tranport propertie are calculated in the vle object"; - - /****************** Start values *******************/ - - parameter Modelica.SIunits.Pressure pStart=1.013e5 - annotation (Dialog(group="Start Values", tab="Start and Initialization")); - - parameter Modelica.SIunits.MassFlowRate m_flowStart=0.01 - annotation (Dialog(group="Start Values", tab="Start and Initialization")); - - /******* Parameters and connectors for active closing and flap valve*********/ - - parameter Boolean isClosable=false - "true = activly closable, false = not activly closable" annotation (Dialog( - group="Valve type"), choices(choice=true "activly closable", choice=false - "not activly closable")); - parameter Boolean isFlap=false "true = flap valve, false = no flap valve" - annotation (Dialog(group="Valve type"), choices(choice=true - "flap valve (opens only one in one direction)", choice=false - "opens in both directions")); - parameter Boolean openingDirection=true "true = A --> B, false = B --> A" - annotation (Dialog(enable=isFlap, group="Valve type"), choices(choice=true - "A --> B", choice=false "B --> A")); - - Boolean valveOpen; - -public - Modelica.Blocks.Interfaces.BooleanInput open if isClosable annotation ( - Placement(transformation( - extent={{-17,-17},{17,17}}, - rotation=90, - origin={0,-61}))); - -protected - Modelica.Blocks.Interfaces.BooleanOutput getOpen annotation (Placement( - transformation( - extent={{-10,-10},{10,10}}, - rotation=90, - origin={16,-22}))); - Modelica.Blocks.Interfaces.BooleanInput open_=true if not isClosable - annotation (Placement(transformation( - extent={{-16,-16},{16,16}}, - rotation=90, - origin={32,-60}))); - -equation - if not getOpen or (isFlap and openingDirection and vlePortA.p <= vlePortB.p) - or (isFlap and not openingDirection and vlePortB.p <= vlePortA.p) then - valveOpen = false; - else - valveOpen = true; - end if; - - vlePortA.m_flow + vlePortB.m_flow = 0; - vlePortA.xi_outflow = inStream(vlePortB.xi_outflow); - vlePortB.xi_outflow = inStream(vlePortA.xi_outflow); - - vlePortA.h_outflow = inStream(vlePortB.h_outflow); - vlePortB.h_outflow = inStream(vlePortA.h_outflow); - - dp = vlePortA.p - vlePortB.p; - - // no limiter used - vlePortA.h_limit = -1e6; - vlePortB.h_limit = -1e6; - - connect(open, getOpen) annotation (Line(points={{0,-61},{0,-61},{0,-36},{16, - -36},{16,-22}}, color={255,0,255})); - connect(open_, getOpen) annotation (Line(points={{32,-60},{32,-60},{32,-36},{16, - -36},{16,-22}}, color={255,0,255})); - annotation ( - Icon(coordinateSystem(extent={{-100,-60},{100,60}})), - Diagram(coordinateSystem(extent={{-100,-60},{100,60}})), - Documentation(info="<html> - <p> - The mass transfer models are used to connect the adsorbent cell to an evaporator, a condenser, or a moist air cell (or any other adsorbate source or sink). - The mass transfer models are modeled as an isenthalpic valve with no volume. - Depending on the chosen Transport Phenomena, the Mass Transfer model represents diffusion in the particle and also pressure drop due to friction in pipes, connceting the adsorbent to other models. - The partial model includes the main equations, used for all Mass Transfer models including: - <ul> - <li>2 vle ports</li> - <li>Parameters and connectors to model an activly closable and a flap valve (opens only in one direction)</li> - <li>Mass balance</li> - <li>Energy balance</li> - </ul> - </p> - <h4>Main equations</h4> - <p> - The mass transfer model is modelled as an isenthalpic valve with no storage volume. - Thus, the mass balance reads: - <p align=\"center\"><i><code>ṁ</code></i><sub>in</sub> = <i><code>ṁ</code></i><sub>out</sub> </p> - The energy balance boils down to equal specific enthalpies: - <p align=\"center\"><i>h</i><sub>in</sub> = <i>h</i><sub>out</sub> </p> - </p> - <h4>References</h4> - <p> - For more information see: - <ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257. </li> - </ul> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html> -")); -end PartialMassTransfer; diff --git a/SorpLib/Components/MassTransfer/Partial/package.mo b/SorpLib/Components/MassTransfer/Partial/package.mo deleted file mode 100644 index 87a4ed8f6cf97ac2fd1010e015e0610ca27a3e26..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Partial/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.MassTransfer; -package Partial -extends SorpLib.Internals.ClassTypes.PartialPackage; - -end Partial; diff --git a/SorpLib/Components/MassTransfer/Partial/package.order b/SorpLib/Components/MassTransfer/Partial/package.order deleted file mode 100644 index b90627136ce3b452acff172b04499c2e9f3eeb64..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Partial/package.order +++ /dev/null @@ -1 +0,0 @@ -PartialMassTransfer diff --git a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/Lanzerath2015_SilicaGel.mo b/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/Lanzerath2015_SilicaGel.mo deleted file mode 100644 index 1e2239a14221d2d2db332f9fc6277e9993be6691..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/Lanzerath2015_SilicaGel.mo +++ /dev/null @@ -1,26 +0,0 @@ -within SorpLib.Components.MassTransfer.Record.DiffusionCoefficients; -model Lanzerath2015_SilicaGel - "Diffusion coefficient and particle diameter for Silica Gel 123 (Lanzerath 2015)" - extends MassTransfer.MassTransferPhenomena.Glueckauf_dx( - final D=1.8e-10, - final r=0.00045); - annotation (Documentation(info="<html> -<p> - The diffusion coefficients in this record were determined by Lanzerath et. al. (2015) for silica-gel 123 particles. -</p> -<h4>References</h4> -<ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); - -end Lanzerath2015_SilicaGel; diff --git a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/Lanzerath2015_Zeolite13X_ads.mo b/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/Lanzerath2015_Zeolite13X_ads.mo deleted file mode 100644 index 22aa5bd32352596ef02e0f1fff1c7e0fe0e5499a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/Lanzerath2015_Zeolite13X_ads.mo +++ /dev/null @@ -1,27 +0,0 @@ -within SorpLib.Components.MassTransfer.Record.DiffusionCoefficients; -model Lanzerath2015_Zeolite13X_ads - "Diffusion coefficient and particle diameter for Zeolith 13X adsorption (Lanzerath 2015)" - extends MassTransfer.MassTransferPhenomena.Glueckauf_dx( - final D=3.416e-10, - final r=0.0007); - - annotation (Documentation(info="<html> -<p> - The diffusion coefficients in this record were determined by Lanzerath et. al. (2015) for Zeolite 13X particles during adsorption. -</p> -<h4>References</h4> -<ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); - -end Lanzerath2015_Zeolite13X_ads; diff --git a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/Lanzerath2015_Zeolite13X_des.mo b/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/Lanzerath2015_Zeolite13X_des.mo deleted file mode 100644 index 378a0aef7081cd8c7c6ae61bbadae0857dddb802..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/Lanzerath2015_Zeolite13X_des.mo +++ /dev/null @@ -1,25 +0,0 @@ -within SorpLib.Components.MassTransfer.Record.DiffusionCoefficients; -model Lanzerath2015_Zeolite13X_des - "Diffusion coefficient and particle diameter for Zeolith 13X desorption (Lanzerath 2015)" - extends MassTransfer.MassTransferPhenomena.Glueckauf_dx( - final D=3.055e-9, - final r=0.0007); - annotation (Documentation(info="<html> -<p> - The diffusion coefficients in this record were determined by Lanzerath et. al. (2015) for Zeolite 13X particles during desorption. -</p> -<h4>References</h4> -<ul> - <li>Lanzerath, F.; Bau, U.; Seiler, J.; Bardow, A. Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 2015, 21(3), 248-257.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end Lanzerath2015_Zeolite13X_des; diff --git a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/SakodaSuzuki1984_SilicaGel.mo b/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/SakodaSuzuki1984_SilicaGel.mo deleted file mode 100644 index bc4b40f81232dfab250efa764f5aa3accd41fc7a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/SakodaSuzuki1984_SilicaGel.mo +++ /dev/null @@ -1,26 +0,0 @@ -within SorpLib.Components.MassTransfer.Record.DiffusionCoefficients; -model SakodaSuzuki1984_SilicaGel - "Diffusion coefficient and particle diameter for Silica-gel Fuji-A-type (Sakoda Suzuki 1984)" - extends MassTransfer.MassTransferPhenomena.GlueckaufArrhenius_dx( - final Dso=3.055e-9, - final r=0.0007); - annotation (Documentation(info="<html> -<p> - The diffusion coefficients in this record were determined by Sakoda and Suzuki (1984) for silica-gel fuji A. -</p> -<h4>References</h4> -<ul> - <li>Sakoda, A.; Suzuki, M. Fundamental study on a solar powered adsorption cooling system. Journal of Chemical Engineering of Japan, 1984, 17(1), 52-57.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); - -end SakodaSuzuki1984_SilicaGel; diff --git a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/package.mo b/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/package.mo deleted file mode 100644 index b2a502ce16dabf22d57379cdbc27419b1b6920b5..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/package.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.MassTransfer.Record; -package DiffusionCoefficients -extends SorpLib.Internals.ClassTypes.RecordPackage; - - - - -end DiffusionCoefficients; diff --git a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/package.order b/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/package.order deleted file mode 100644 index 65473a9e965187c1f143d25eb48d47cffbb207c4..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/DiffusionCoefficients/package.order +++ /dev/null @@ -1,4 +0,0 @@ -Lanzerath2015_Zeolite13X_des -Lanzerath2015_Zeolite13X_ads -Lanzerath2015_SilicaGel -SakodaSuzuki1984_SilicaGel diff --git a/SorpLib/Components/MassTransfer/Record/FlowCoefficients/FlowRes_Lanzerath_ads.mo b/SorpLib/Components/MassTransfer/Record/FlowCoefficients/FlowRes_Lanzerath_ads.mo deleted file mode 100644 index 6e15d4820653396cb2991a9afbf32aa94f762b78..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/FlowCoefficients/FlowRes_Lanzerath_ads.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.MassTransfer.Record.FlowCoefficients; -model FlowRes_Lanzerath_ads - "Coefficients flow resistance evaporator -> adsorber (Lanzerath 2015)" - extends MassTransfer.MassTransferPhenomena.Laminar_dp( - final zeta_lam=14.8, - final L=0.455, - final d=0.0382); -end FlowRes_Lanzerath_ads; diff --git a/SorpLib/Components/MassTransfer/Record/FlowCoefficients/FlowRes_Lanzerath_des.mo b/SorpLib/Components/MassTransfer/Record/FlowCoefficients/FlowRes_Lanzerath_des.mo deleted file mode 100644 index 71fa65f81800f87cd771786d6411f4ebd57840ca..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/FlowCoefficients/FlowRes_Lanzerath_des.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.MassTransfer.Record.FlowCoefficients; -model FlowRes_Lanzerath_des - "Coefficients Flow Resistance adsorber -> condenser (Lanzerath 2015)" - extends MassTransfer.MassTransferPhenomena.Laminar_dp( - final zeta_lam=30.1, - final L=0.38, - final d=0.0345); -end FlowRes_Lanzerath_des; diff --git a/SorpLib/Components/MassTransfer/Record/FlowCoefficients/package.mo b/SorpLib/Components/MassTransfer/Record/FlowCoefficients/package.mo deleted file mode 100644 index a22d3448fea7cb48e55779de7ff859c9156dcaad..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/FlowCoefficients/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.MassTransfer.Record; -package FlowCoefficients -extends SorpLib.Internals.ClassTypes.RecordPackage; - - -end FlowCoefficients; diff --git a/SorpLib/Components/MassTransfer/Record/FlowCoefficients/package.order b/SorpLib/Components/MassTransfer/Record/FlowCoefficients/package.order deleted file mode 100644 index d6a83bacaf1ebedc8bcf09ba14fb085e4b95b7d2..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/FlowCoefficients/package.order +++ /dev/null @@ -1,2 +0,0 @@ -FlowRes_Lanzerath_des -FlowRes_Lanzerath_ads diff --git a/SorpLib/Components/MassTransfer/Record/package.mo b/SorpLib/Components/MassTransfer/Record/package.mo deleted file mode 100644 index 3a80320d666ea6a4afefba88ddb925b1c6a007da..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.MassTransfer; -package Record -extends SorpLib.Internals.ClassTypes.RecordPackage; - - -end Record; diff --git a/SorpLib/Components/MassTransfer/Record/package.order b/SorpLib/Components/MassTransfer/Record/package.order deleted file mode 100644 index 44b738a1192fdc036d1e5540673641cf4913a924..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Record/package.order +++ /dev/null @@ -1,2 +0,0 @@ -DiffusionCoefficients -FlowCoefficients diff --git a/SorpLib/Components/MassTransfer/Records/FluidProperties.mo b/SorpLib/Components/MassTransfer/Records/FluidProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..b0c5863580c1a463e04816f513a1ed4523e8222d --- /dev/null +++ b/SorpLib/Components/MassTransfer/Records/FluidProperties.mo @@ -0,0 +1,36 @@ +within SorpLib.Components.MassTransfer.Records; +record FluidProperties + "This record contains fluid properties required for heat transfer coefficients" + extends Modelica.Icons.Record; + + // + // Definition of variables describing fluid properties + // + Modelica.Units.SI.Temperature T_adsorbate + "Temperature at the adsorbate state"; + + Modelica.Units.SI.Pressure p_adsorptive + "Pressure at the adsorptive state"; + Modelica.Units.SI.Temperature T_adsorptive + "Temperature at the adsorptive state"; + Modelica.Units.SI.Density d_adsorptive + "Density at the adsorptive state"; + Modelica.Units.SI.DynamicViscosity eta_adsorptive + "Dynamic viscosity at the adsorptive state"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains fluid properties required for mass transfer coefficients. +</p> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end FluidProperties; diff --git a/SorpLib/Components/MassTransfer/Records/GeometryClosedAdsorber.mo b/SorpLib/Components/MassTransfer/Records/GeometryClosedAdsorber.mo new file mode 100644 index 0000000000000000000000000000000000000000..f0055d7b9b0806e8c93007808ad04f749ea4c099 --- /dev/null +++ b/SorpLib/Components/MassTransfer/Records/GeometryClosedAdsorber.mo @@ -0,0 +1,22 @@ +within SorpLib.Components.MassTransfer.Records; +record GeometryClosedAdsorber + "This record contains the geometry required for mass transfer coefficients of closed adsorbers" + extends SorpLib.Components.HeatExchanger.Records.GeometryClosedAdsorber; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters required by models calculating the mass +transfer coefficients in closed adsorbers. +</p> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryClosedAdsorber; diff --git a/SorpLib/Components/MassTransfer/Records/GeometryOpenAdsorber.mo b/SorpLib/Components/MassTransfer/Records/GeometryOpenAdsorber.mo new file mode 100644 index 0000000000000000000000000000000000000000..ab7a1f526c641a58cc231aa685a651297d9203a6 --- /dev/null +++ b/SorpLib/Components/MassTransfer/Records/GeometryOpenAdsorber.mo @@ -0,0 +1,222 @@ +within SorpLib.Components.MassTransfer.Records; +record GeometryOpenAdsorber + "This record contains the geometry required for mass transfer coefficients of open adsorbers" + extends Modelica.Icons.Record; + + // + // Definition of parameters regarding the disretization + // + parameter Integer no_volumes(min=1) = 1 + "Number of discretization volumes in flow direction" + annotation (Dialog(tab="General", group="Discretization", enable=false)); + + // + // Definition of parameters regarding the geometry of the casing + // + parameter Modelica.Units.SI.Length l_cas = 1 + "Length of the casing" + annotation (Dialog(tab="Casing", group="General")); + + parameter Modelica.Units.SI.Diameter d_inner_cas = 0.15 + "Inner diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_outer_cas = 0.16 + "Outer diameter of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + parameter Modelica.Units.SI.Thickness t_wall_cas= + (d_outer_cas - d_inner_cas) / 2 + "Wall thickness of the casing" + annotation (Dialog(tab="Casing", group="Diameters")); + + parameter Modelica.Units.SI.Area A_crossInner_cas= + Modelica.Constants.pi/4 * d_inner_cas^2 + "Inner cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_crossOuter_cas= + Modelica.Constants.pi/4 * d_outer_cas^2 + "Outer cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_crossWall_cas= + A_crossOuter_cas - A_crossInner_cas + "Wall cross-sectional area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferInner_cas= + Modelica.Constants.pi * d_inner_cas * l_cas + "Inner heat transfer area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferOuter_cas= + Modelica.Constants.pi * d_outer_cas * l_cas + "Outer heat transfer area of the casing" + annotation (Dialog(tab="Casing", group="Areas")); + + parameter Modelica.Units.SI.Volume V_inner_cas= + Modelica.Constants.pi/4 * d_inner_cas * l_cas + "Inner volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_outer_cas= + Modelica.Constants.pi/4 * d_outer_cas * l_cas + "Outer volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_wall_cas= + V_outer_cas - V_inner_cas + "Wall volume of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + parameter Modelica.Units.SI.Volume V_free_cas= + V_inner_cas - V_inner_hx - V_outer_hx - V_sorbent_hx + "Free volume (i.e., gas/vapor volume) of the casing" + annotation (Dialog(tab="Casing", group="Volumes")); + + // + // Definition of parameters regarding the general geometry of the heat exchanger + // + parameter Integer no_hydraulicParallelTubes(min=1) = 1 + "Number of hydraulically parallel tubes" + annotation (Dialog(tab="Heat Exchanger", group="General")); + + parameter Modelica.Units.SI.Length l_hx = 0 + "Length of the tube" + annotation (Dialog(tab="Heat Exchanger", group="General")); + + parameter Modelica.Units.SI.Length roughness_hx = 0 + "Absolute roughness of the tube" + annotation (Dialog(tab="Heat Exchanger", group="General")); + + // + // Definition of parameters regarding diameters of the heat exchanger + // + parameter Modelica.Units.SI.Diameter d_inner_hx = 0 + "Inner diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_outer_hx = 0 + "Outer diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + + parameter Modelica.Units.SI.Diameter d_hydInner_hx = d_inner_hx + "Hydraulic inner diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + parameter Modelica.Units.SI.Diameter d_hydOuter_hx = d_outer_hx + "Hydraulic outer diameter of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + + parameter Modelica.Units.SI.Thickness t_wall_hx= + (d_outer_hx - d_inner_hx) / 2 + "Wall thickness of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Diameters")); + + // + // Definition of parameters regarding areas of the heat exchanger + // + parameter Modelica.Units.SI.Area A_crossInner_hx= + Modelica.Constants.pi/4 * d_inner_hx^2 + "Inner cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_crossOuter_hx= + Modelica.Constants.pi/4 * d_outer_hx^2 + "Outer cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_crossWall_hx= + A_crossOuter_hx - A_crossInner_hx + "Wall cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + + parameter Modelica.Units.SI.Area A_hydCrossInner_hx = A_crossInner_hx + "Hydraulic inner cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossOuter_hx = A_crossOuter_hx + "Hydraulic outer cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_hydCrossWall_hx= + A_hydCrossOuter_hx - A_hydCrossInner_hx + "Hydraulic wall cross-sectional area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + + parameter Modelica.Units.SI.Area A_heatTransferInner_hx= + Modelica.Constants.pi * d_inner_hx * l_hx + "Total inner heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Modelica.Units.SI.Area A_heatTransferOuter_hx= + Modelica.Constants.pi * d_outer_hx * l_hx + "Total outer heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + + parameter Real f_finAreaRatioInner_hx(min=0, max=1) = 0 + "Ratio of total inner fin area to total inner heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + parameter Real f_finAreaRatioOuter_hx(min=0, max=1) = 0 + "Ratio of total outer fin area to total outer heat transfer area of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Areas")); + + // + // Definition of parameters regarding volumes of the heat exchanger + // + parameter Modelica.Units.SI.Volume V_inner_hx = A_crossInner_hx * l_hx + "Total inner volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_outer_hx = A_crossOuter_hx * l_hx + "Total outer volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_wall_hx = V_outer_hx - V_inner_hx + "Total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Modelica.Units.SI.Volume V_sorbent_hx= + 2.5 * V_wall_hx + "Available volume for sorbent particles of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + + parameter Real f_finVolumeRatioInner_hx(min=0, max=1) = 0 + "Ratio of total inner fin volume to total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + parameter Real f_finVolumeRatioOuter_hx(min=0, max=1) = 0 + "Ratio of total outer fin volume to total wall volume of the tube" + annotation (Dialog(tab="Heat Exchanger", group="Volumes")); + + // + // Definition of parameters regarding the sorbent gemeotry + // + parameter Real no_particles = (1-psi_particles) * V_inner_cas / V_particle + "Number of particles" + annotation (Dialog(tab="Sorbent", group="General")); + parameter Real psi_particles(unit="1") = 1 - 0.74 + "Void fraction of the adsorber (i.e., ratio of the free fluid volume to + the total inner volume)" + annotation (Dialog(tab="Sorbent", group="General")); + + parameter Modelica.Units.SI.Diameter d_particle = 0.7 / 1000 + "Average diameter of the adsorbent particles" + annotation (Dialog(tab="Sorbent", group="Diameters")); + + parameter Modelica.Units.SI.Area A_cross_particle= + Modelica.Constants.pi/4 * d_particle^2 + "Average cross-sectional area of the particle" + annotation (Dialog(tab="Sorbent", group="Areas")); + parameter Modelica.Units.SI.Area A_surface_particle= + Modelica.Constants.pi * d_particle^2 + "Average suraface area of the particle" + annotation (Dialog(tab="Sorbent", group="Areas")); + + parameter Modelica.Units.SI.Volume V_particle= + Modelica.Constants.pi/6 * d_particle^3 + "Average volume of the particle" + annotation (Dialog(tab="Sorbent", group="Volumes")); + parameter Modelica.Units.SI.Volume V_particles= + no_particles * V_particle + "Average volume of all particles" + annotation (Dialog(tab="Sorbent", group="Volumes")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters required by models calculating the mass +transfer coefficients in open adsorbers. +</p> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryOpenAdsorber; diff --git a/SorpLib/Components/MassTransfer/Records/package.mo b/SorpLib/Components/MassTransfer/Records/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..1558ae87d98358414661e359d2d86218dc68c893 --- /dev/null +++ b/SorpLib/Components/MassTransfer/Records/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.MassTransfer; +package Records "Package containing records" + extends Modelica.Icons.RecordsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains definitions of records. These records are used to cluster +variables and tidy up the model output. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Records; diff --git a/SorpLib/Components/MassTransfer/Records/package.order b/SorpLib/Components/MassTransfer/Records/package.order new file mode 100644 index 0000000000000000000000000000000000000000..72a79bf0e06a49430795ba34d9f7ab5d55b70b0f --- /dev/null +++ b/SorpLib/Components/MassTransfer/Records/package.order @@ -0,0 +1,3 @@ +FluidProperties +GeometryClosedAdsorber +GeometryOpenAdsorber diff --git a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusion1.mo b/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusion1.mo deleted file mode 100644 index 93fed9b9c25977f985875587e56489df5df0eb25..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusion1.mo +++ /dev/null @@ -1,54 +0,0 @@ -within SorpLib.Components.MassTransfer.Testers; -model TesterMassTransferDiffusion1 - - MassTransferDiffusion massTransfer( - pStart(displayUnit="kPa") = 1200, - inputChoice="dx", - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - vleFluidType=sim.vleFluidType1, - isClosable=false, - isFlap=true, - openingDirection=false, - redeclare model MassTransfer_diffusion_dx = - MassTransferPhenomena.Glueckauf_dx ( - m_ads=2, - D=1.8e-8, - r(displayUnit="mm") = 0.0007)) - annotation (Placement(transformation(extent={{-12,13},{12,27}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="p", - pFixed(displayUnit="kPa") = 1750.51, - hFixed=2.8e6, - use_pressureInput=true) - annotation (Placement(transformation(extent={{-36,10},{-28,30}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - boundaryType="p", - hFixed=2.8e6, - pFixed(displayUnit="kPa") = 1900) - annotation (Placement(transformation(extent={{22,10},{30,30}}))); - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - Modelica.Blocks.Sources.Step step( - startTime=250, - height=300, - offset=1800) - annotation (Placement(transformation(extent={{-52,14},{-40,26}}))); -equation - - connect(vleBoundary1.port, massTransfer.vlePortA) annotation (Line( - points={{-32,20},{-10.92,20}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(massTransfer.vlePortB, vleBoundary2.port) annotation (Line( - points={{11.04,20},{26,20}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(step.y, vleBoundary1.p_in) annotation (Line(points={{-39.4,20},{-38, - 20},{-38,26},{-36,26}}, color={0,0,127})); - annotation (experiment(StopTime=500, Interval=1)); -end TesterMassTransferDiffusion1; diff --git a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusionFlow1.mo b/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusionFlow1.mo deleted file mode 100644 index 9bff252eeb48c53130eb9c650891ccbb0e83b8e7..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusionFlow1.mo +++ /dev/null @@ -1,60 +0,0 @@ -within SorpLib.Components.MassTransfer.Testers; -model TesterMassTransferDiffusionFlow1 - - MassTransferDiffusionFlow - massTransfer( - pStart(displayUnit="kPa") = 1200, - vleFluidType=sim.vleFluidType1, - openingDirection=false, - isFlap=false, - inputChoice="dx", - isClosable=false, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model MassTransfer_flow = - MassTransferPhenomena.DarcyPorousMedia_dp ( - area=1, - dx=0.05, - k=2e-9), - redeclare model MassTransfer_diffusion_dx = - MassTransferPhenomena.Glueckauf_dx ( - m_ads=2, - D=1.8e-8, - r(displayUnit="mm") = 0.0007)) - annotation (Placement(transformation(extent={{-12,13},{12,27}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="p", - pFixed(displayUnit="kPa") = 1750.51, - hFixed=2.8e6, - use_pressureInput=true) - annotation (Placement(transformation(extent={{-36,10},{-28,30}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - boundaryType="p", - hFixed=2.8e6, - pFixed(displayUnit="kPa") = 1900) - annotation (Placement(transformation(extent={{22,10},{30,30}}))); - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - Modelica.Blocks.Sources.Step step( - startTime=250, - height=300, - offset=1800) - annotation (Placement(transformation(extent={{-52,14},{-40,26}}))); -equation - - connect(vleBoundary1.port, massTransfer.vlePortA) annotation (Line( - points={{-32,20},{-10.92,20}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(massTransfer.vlePortB, vleBoundary2.port) annotation (Line( - points={{11.04,20},{26,20}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(step.y, vleBoundary1.p_in) annotation (Line(points={{-39.4,20},{-38, - 20},{-38,26},{-36,26}}, color={0,0,127})); - annotation (experiment(StopTime=500, Interval=1)); -end TesterMassTransferDiffusionFlow1; diff --git a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusionFlow2.mo b/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusionFlow2.mo deleted file mode 100644 index b0cc39814f13362568b7729517deafaa0cbeb92f..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusionFlow2.mo +++ /dev/null @@ -1,66 +0,0 @@ -within SorpLib.Components.MassTransfer.Testers; -model TesterMassTransferDiffusionFlow2 - - MassTransferDiffusionFlow - massTransfer( - pStart(displayUnit="kPa") = 1200, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model MassTransfer_diffusion_dp = - MassTransferPhenomena.ConstantCoefficient_dp, - vleFluidType=sim.vleFluidType1, - openingDirection=false, - isFlap=false, - redeclare model MassTransfer_flow = - Record.FlowCoefficients.FlowRes_Lanzerath_des, - inputChoice="dx", - isClosable=true, - redeclare model MassTransfer_diffusion_dx = - MassTransferPhenomena.Glueckauf_dx ( - m_ads=2, - D=1.8e-8, - r(displayUnit="mm") = 0.0007)) - annotation (Placement(transformation(extent={{-12,13},{12,27}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="p", - pFixed(displayUnit="kPa") = 1750.51, - hFixed=2.8e6, - use_pressureInput=true) - annotation (Placement(transformation(extent={{-36,10},{-28,30}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - boundaryType="p", - hFixed=2.8e6, - pFixed(displayUnit="kPa") = 1900) - annotation (Placement(transformation(extent={{22,10},{30,30}}))); - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - Modelica.Blocks.Sources.BooleanStep booleanStep(startTime=150) annotation ( - Placement(transformation( - extent={{-5,-5},{5,5}}, - rotation=90, - origin={-6,-3}))); - Modelica.Blocks.Sources.Step step( - startTime=250, - height=300, - offset=1800) - annotation (Placement(transformation(extent={{-52,14},{-40,26}}))); -equation - - connect(vleBoundary1.port, massTransfer.vlePortA) annotation (Line( - points={{-32,20},{-10.92,20}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(massTransfer.vlePortB, vleBoundary2.port) annotation (Line( - points={{11.04,20},{26,20}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(booleanStep.y, massTransfer.open) annotation (Line(points={{-6,2.5},{ - -6,12.8833},{0,12.8833}}, - color={255,0,255})); - connect(step.y, vleBoundary1.p_in) annotation (Line(points={{-39.4,20},{-38, - 20},{-38,26},{-36,26}}, color={0,0,127})); -end TesterMassTransferDiffusionFlow2; diff --git a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusionFlow3.mo b/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusionFlow3.mo deleted file mode 100644 index 8f1dd9c6080f741fb8432137dc06d0afbae1a5d2..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferDiffusionFlow3.mo +++ /dev/null @@ -1,58 +0,0 @@ -within SorpLib.Components.MassTransfer.Testers; -model TesterMassTransferDiffusionFlow3 - - MassTransferDiffusionFlow - massTransfer( - pStart(displayUnit="kPa") = 1200, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model MassTransfer_diffusion_dp = - MassTransferPhenomena.ConstantCoefficient_dp, - vleFluidType=sim.vleFluidType1, - openingDirection=false, - redeclare model MassTransfer_flow = - Record.FlowCoefficients.FlowRes_Lanzerath_des, - inputChoice="dx", - isClosable=false, - isFlap=true, - redeclare model MassTransfer_diffusion_dx = - MassTransferPhenomena.Glueckauf_dx ( - m_ads=2, - D=1.8e-8, - r=0.0007)) - annotation (Placement(transformation(extent={{-12,13},{12,27}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="p", - pFixed(displayUnit="kPa") = 1750.51, - hFixed=2.8e6, - use_pressureInput=true) - annotation (Placement(transformation(extent={{-36,10},{-28,30}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - boundaryType="p", - hFixed=2.8e6, - pFixed(displayUnit="kPa") = 1900) - annotation (Placement(transformation(extent={{22,10},{30,30}}))); - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - Modelica.Blocks.Sources.Step step( - startTime=250, - height=300, - offset=1800) - annotation (Placement(transformation(extent={{-52,14},{-40,26}}))); -equation - - connect(vleBoundary1.port, massTransfer.vlePortA) annotation (Line( - points={{-32,20},{-10.92,20}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(massTransfer.vlePortB, vleBoundary2.port) annotation (Line( - points={{11.04,20},{26,20}}, - color={153,204,0}, - thickness=0.5, - smooth=Smooth.None)); - connect(step.y, vleBoundary1.p_in) annotation (Line(points={{-39.4,20},{-38, - 20},{-38,26},{-36,26}}, color={0,0,127})); -end TesterMassTransferDiffusionFlow3; diff --git a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow1.mo b/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow1.mo deleted file mode 100644 index 05cd0f50c5b0e937ab5811033eac8ed732ea74b1..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow1.mo +++ /dev/null @@ -1,54 +0,0 @@ -within SorpLib.Components.MassTransfer.Testers; -model TesterMassTransferFlow1 - - MassTransferFlow massTransfer( - pStart(displayUnit="kPa") = 1200, - openingDirection=true, - vleFluidType=sim.vleFluidType1, - isFlap=false, - redeclare model MassTransfer_flow = - MassTransferPhenomena.Laminar_dp ( - L=0.4, - zeta_lam=20, - d=0.03), - isClosable=false) - annotation (Placement(transformation(extent={{-10,-7},{10,7}}, - rotation=0, - origin={0,20}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="p", - pFixed(displayUnit="kPa") = 1750.51, - use_pressureInput=true, - vleFluidType=sim.vleFluidType1, - hFixed=2800000) - annotation (Placement(transformation(extent={{-36,10},{-28,30}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - m_flowFixed=-0.2, - boundaryType="p", - pFixed(displayUnit="kPa") = 1927.6, - vleFluidType=sim.vleFluidType1, - hFixed=2800000) - annotation (Placement(transformation(extent={{22,10},{30,30}}))); - Modelica.Blocks.Sources.Step step( - startTime=250, - height=300, - offset=1800) - annotation (Placement(transformation(extent={{-58,14},{-46,26}}))); - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); -equation - - connect(step.y, vleBoundary1.p_in) annotation (Line(points={{-45.4,20},{-42, - 20},{-42,26},{-36,26}}, color={0,0,127})); - connect(vleBoundary1.port, massTransfer.vlePortA) annotation (Line( - points={{-32,20},{-16,20},{-9.1,20}}, - color={153,204,0}, - thickness=0.5)); - connect(massTransfer.vlePortB, vleBoundary2.port) annotation (Line( - points={{9.2,20},{9.2,20},{26,20}}, - color={153,204,0}, - thickness=0.5)); - annotation (experiment(StopTime=500, Interval=1)); -end TesterMassTransferFlow1; diff --git a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow2.mo b/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow2.mo deleted file mode 100644 index 8dcbfb3bf15239efeb36bdd52af4afdc3fedd2c2..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow2.mo +++ /dev/null @@ -1,46 +0,0 @@ -within SorpLib.Components.MassTransfer.Testers; -model TesterMassTransferFlow2 - - MassTransferFlow massTransfer( - pStart(displayUnit="kPa") = 1200, - openingDirection=true, - isClosable=false, - vleFluidType=sim.vleFluidType1, - isFlap=false, - redeclare model MassTransfer_flow = - Record.FlowCoefficients.FlowRes_Lanzerath_des) - annotation (Placement(transformation(extent={{-10,13},{10,27}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="p", - pFixed(displayUnit="kPa") = 1750.51, - use_pressureInput=true, - hFixed=2.8e6) - annotation (Placement(transformation(extent={{-36,10},{-28,30}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - pFixed(displayUnit="kPa") = 2227.6, - boundaryType="m_flow", - hFixed=2.8e6, - m_flowFixed=-0.001) - annotation (Placement(transformation(extent={{22,10},{30,30}}))); - Modelica.Blocks.Sources.Step step( - height=1000, - offset=1700, - startTime=250) - annotation (Placement(transformation(extent={{-58,14},{-46,26}}))); - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); -equation - - connect(step.y, vleBoundary1.p_in) annotation (Line(points={{-45.4,20},{-42, - 20},{-42,26},{-36,26}}, color={0,0,127})); - connect(vleBoundary1.port, massTransfer.vlePortA) annotation (Line( - points={{-32,20},{-9.1,20}}, - color={153,204,0}, - thickness=0.5)); - connect(massTransfer.vlePortB, vleBoundary2.port) annotation (Line( - points={{9.2,20},{9.2,20},{26,20}}, - color={153,204,0}, - thickness=0.5)); -end TesterMassTransferFlow2; diff --git a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow3.mo b/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow3.mo deleted file mode 100644 index 74fa6586bf6acbb0630957d7bdf3b00e4a299c3a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow3.mo +++ /dev/null @@ -1,50 +0,0 @@ -within SorpLib.Components.MassTransfer.Testers; -model TesterMassTransferFlow3 - - MassTransferFlow massTransfer( - pStart(displayUnit="kPa") = 1200, - openingDirection=true, - vleFluidType=sim.vleFluidType1, - redeclare model MassTransfer_flow = - MassTransferPhenomena.Laminar_dp ( - L=0.4, - zeta_lam=20, - d=0.03), - isFlap=false, - isClosable=false) - annotation (Placement(transformation(extent={{-10,13},{10,27}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - pFixed(displayUnit="kPa") = 1750.51, - boundaryType="m_flow", - use_pressureInput=false, - use_massFlowRateInput=true, - hFixed=2.8e6) - annotation (Placement(transformation(extent={{-36,10},{-28,30}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - pFixed(displayUnit="kPa") = 2227.6, - m_flowFixed=-0.2, - boundaryType="p", - hFixed=2.8e6) - annotation (Placement(transformation(extent={{22,10},{30,30}}))); - Modelica.Blocks.Sources.Step step( - startTime=250, - offset=-0.0005, - height=0.001) - annotation (Placement(transformation(extent={{-58,14},{-46,26}}))); - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); -equation - - connect(massTransfer.vlePortB, vleBoundary2.port) annotation (Line( - points={{9.2,20},{9.2,20},{26,20}}, - color={153,204,0}, - thickness=0.5)); - connect(step.y, vleBoundary1.m_flow_in) annotation (Line(points={{-45.4,20},{ - -42,20},{-42,22},{-36,22}}, color={0,0,127})); - connect(vleBoundary1.port, massTransfer.vlePortA) annotation (Line( - points={{-32,20},{-9.1,20}}, - color={153,204,0}, - thickness=0.5)); -end TesterMassTransferFlow3; diff --git a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow4.mo b/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow4.mo deleted file mode 100644 index 2b191c04066a251e06a724965edf3f370a5d5d90..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Testers/TesterMassTransferFlow4.mo +++ /dev/null @@ -1,56 +0,0 @@ -within SorpLib.Components.MassTransfer.Testers; -model TesterMassTransferFlow4 - - MassTransferFlow massTransfer( - pStart(displayUnit="kPa") = 1200, - openingDirection=true, - vleFluidType=sim.vleFluidType1, - redeclare model MassTransfer_flow = - MassTransferPhenomena.Laminar_dp ( - L=0.4, - zeta_lam=20, - d=0.03), - isClosable=true, - isFlap=true) - annotation (Placement(transformation(extent={{-10,13},{10,27}}))); - - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary1( - boundaryType="p", - pFixed(displayUnit="kPa") = 1750.51, - use_pressureInput=true, - hFixed=2.8e6) - annotation (Placement(transformation(extent={{-36,10},{-28,30}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundary2( - m_flowFixed=-0.2, - boundaryType="p", - pFixed(displayUnit="kPa") = 1927.6, - hFixed=2.8e6) - annotation (Placement(transformation(extent={{22,10},{30,30}}))); - Modelica.Blocks.Sources.Step step( - startTime=250, - height=300, - offset=1800) - annotation (Placement(transformation(extent={{-58,14},{-46,26}}))); - Modelica.Blocks.Sources.BooleanStep booleanStep(startTime=150) annotation ( - Placement(transformation( - extent={{-5,-5},{5,5}}, - rotation=90, - origin={0,-5}))); - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); -equation - - connect(step.y, vleBoundary1.p_in) annotation (Line(points={{-45.4,20},{-42, - 20},{-42,26},{-36,26}}, color={0,0,127})); - connect(vleBoundary1.port, massTransfer.vlePortA) annotation (Line( - points={{-32,20},{-9.1,20}}, - color={153,204,0}, - thickness=0.5)); - connect(massTransfer.vlePortB, vleBoundary2.port) annotation (Line( - points={{9.2,20},{9.2,20},{26,20}}, - color={153,204,0}, - thickness=0.5)); - connect(booleanStep.y, massTransfer.open) annotation (Line(points={{ - 4.44089e-016,0.5},{0,0.5},{0,12.8833}}, color={255,0,255})); -end TesterMassTransferFlow4; diff --git a/SorpLib/Components/MassTransfer/Testers/package.mo b/SorpLib/Components/MassTransfer/Testers/package.mo deleted file mode 100644 index 13ff9fba3d8a2d0860fdf4b866cb6a3b52b40d9e..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Testers/package.mo +++ /dev/null @@ -1,11 +0,0 @@ -within SorpLib.Components.MassTransfer; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - - - - - - -end Testers; diff --git a/SorpLib/Components/MassTransfer/Testers/package.order b/SorpLib/Components/MassTransfer/Testers/package.order deleted file mode 100644 index 4aac1e2a7474d1e355d1db32665b62e3fce0a473..0000000000000000000000000000000000000000 --- a/SorpLib/Components/MassTransfer/Testers/package.order +++ /dev/null @@ -1,8 +0,0 @@ -TesterMassTransferFlow1 -TesterMassTransferFlow2 -TesterMassTransferFlow3 -TesterMassTransferFlow4 -TesterMassTransferDiffusion1 -TesterMassTransferDiffusionFlow1 -TesterMassTransferDiffusionFlow2 -TesterMassTransferDiffusionFlow3 diff --git a/SorpLib/Components/MassTransfer/VLEMassTransfers/ClosedAdsorberMassTransferDP.mo b/SorpLib/Components/MassTransfer/VLEMassTransfers/ClosedAdsorberMassTransferDP.mo new file mode 100644 index 0000000000000000000000000000000000000000..c5e2623bd81f113a9901d67c0f591ee5b1e5ca57 --- /dev/null +++ b/SorpLib/Components/MassTransfer/VLEMassTransfers/ClosedAdsorberMassTransferDP.mo @@ -0,0 +1,226 @@ +within SorpLib.Components.MassTransfer.VLEMassTransfers; +model ClosedAdsorberMassTransferDP + "Pressure-driven mass transfer models describing pure component adsorption in closed adsorbern" + extends SorpLib.Components.MassTransfer.BaseClasses.PartialPureMassTransferDP( + redeclare final SorpLib.Basics.Interfaces.FluidPorts.VLEPort_in port_a, + redeclare final SorpLib.Basics.Interfaces.FluidPorts.VLEPort_out port_b, + final no_components=Medium.nX, + redeclare replaceable model MassTransferCoefficient = + SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.ConstantCoefficient + constrainedby + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDP( + fluidProperties=fluidProperties)); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="Medium", group="Fluid"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of state records + // + Medium.ThermodynamicState stateAIn = if calculateFluidProperties and not + fluidPropertyPosition == SorpLib.Choices.MassTransferFluidProperties.PortBInlet + then Medium.setState_phX( + p = if limitPressureForCalculations then max(port_a.p, p_min) else port_a.p, + h = inStream(port_a.h_outflow), + X = inStream(port_a.Xi_outflow)) + else Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Instreaming state properties at port a"; + + Medium.ThermodynamicState stateBIn = if calculateFluidProperties and not + fluidPropertyPosition == SorpLib.Choices.MassTransferFluidProperties.PortAInlet + then Medium.setState_phX( + p = if limitPressureForCalculations then max(port_b.p, p_min) else port_b.p, + h = inStream(port_b.h_outflow), + X = inStream(port_b.Xi_outflow)) + else Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Instreaming state properties at port b"; + + // + // Definition of connectors for conditional removed models / variables + // +protected + Modelica.Blocks.Interfaces.RealInput T_adsorptiveA_calc(final unit="K")= + Medium.temperature(state=stateAIn) if + calculateFluidProperties + "Temperature of adsorptive at port a"; + Modelica.Blocks.Interfaces.RealInput T_adsorptiveB_calc(final unit="K")= + Medium.temperature(state=stateBIn) if + calculateFluidProperties + "Temperature of adsorptive at port b"; + + Modelica.Blocks.Interfaces.RealInput d_adsorptiveA_calc(final unit="kg/m3")= + Medium.density(state=stateAIn) if + calculateFluidProperties + "Density of adsorptive at port a"; + Modelica.Blocks.Interfaces.RealInput d_adsorptiveB_calc(final unit="kg/m3")= + Medium.density(state=stateBIn) if + calculateFluidProperties + "Density of adsorptive at port b"; + + Modelica.Blocks.Interfaces.RealInput eta_adsorptiveA_calc(final unit="Pa.s")= + Medium.dynamicViscosity(state=stateAIn) if + calculateFluidProperties + "Dynamic viscosity of adsorptive at port a"; + Modelica.Blocks.Interfaces.RealInput eta_adsorptiveB_calc(final unit="Pa.s")= + Medium.dynamicViscosity(state=stateBIn) if + calculateFluidProperties + "Dynamic viscosity of adsorptive at port b"; + +equation + // + // Connections + // + connect(T_adsorptiveA_internal, T_adsorptiveA_calc); + connect(T_adsorptiveB_internal, T_adsorptiveB_calc); + + connect(d_adsorptiveA_internal, d_adsorptiveA_calc); + connect(d_adsorptiveB_internal, d_adsorptiveB_calc); + + connect(eta_adsorptiveA_internal, eta_adsorptiveA_calc); + connect(eta_adsorptiveB_internal, eta_adsorptiveB_calc); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model is used to connect adsorbate volumes with a VLE volume, +evaporator, condenser, or other adsorbate volumes. Thus, the mass heat transfer +model represents a hydraulic resistance between two models. Depending on the +driving potential (i.e., pressure difference) and the chosen transport phenomena, +this model determines the mass flow rate between the connected models. Note that +port b is located at the adsorbate volume by design. +</p> + +<h4>Main equations</h4> +<p> +The model has a steady-state energy balance +</p> +<pre> + 0 = port_a.m_flow + port_b.m_flow; +</pre> +<p> +and a steady-state energy balance +</p> +<pre> + port_a.h_outflow = port_b.h_outflow; +</pre> +<p> +The mass flow rate <i>port_a.m_flow</i> is calculated linearly dependent on the +pressure difference <i>Δp = port_a.p - port_b.p</i>: +</p> +<pre> + port_a.m_flow = β * Δp = β * (port_a.p - port_b.p); +</pre> +<p> +The mass transport coefficient is calculated according to the selected corrlation. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> + <li> + Isenthalpic process + </li> + <li> + Linear driving force approach + </li> +</ul> + +<h4>Typical use</h4> +<p> +This mass transfer model is used to describe the mass transfer between an +adsorbate volume and VLE volume or evaporator/condenser within closed adosrbers. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>canBeActivated</i>: + Defines if the mass transfer can activaly be activated or deactivated via an + input signal. + </li> + <li> + <i>isFlapValve</i>: + Defines if the mass transfer model behaves like a flap valve. + </li> + <li> + <i>isFlowAB</i>: + Defines the flow direction if the mass transfer models behaves like a flap + valve. + </li> + <li> + <i>offset_dp</i>: + Defines an optional offset for pressure difference if the mass transfer behaves + likes a flap valve. + </li> + <br> + <li> + <i>useBetaInput</i>: + Defines if mass transfer coefficient is given via an input. + </li> + <li> + <i>calculateFluidProperties</i>: + Defines if fluid properties are required to calculate the mass transfer coefficient. + </li> + <li> + <i>fluidPropertyPosition</i>: + Defines the position of the fluid properties used for calculations. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> + <li> + <i>avoid_events_activating</i>: + Defines if events shall be avoided via the noEvent()-operator when activating/ + deactivating the mass transfer. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Lanzerath, F. and Bau, U. and Seiler, J. and Bardow, A. (2015). Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 21(3), 248-257. DOI: https://doi.org/10.1080/10789669.2014.990337. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ClosedAdsorberMassTransferDP; diff --git a/SorpLib/Components/MassTransfer/VLEMassTransfers/ClosedAdsorberMassTransferDX.mo b/SorpLib/Components/MassTransfer/VLEMassTransfers/ClosedAdsorberMassTransferDX.mo new file mode 100644 index 0000000000000000000000000000000000000000..3357788b15dff3157293db30cf08bb611d322317 --- /dev/null +++ b/SorpLib/Components/MassTransfer/VLEMassTransfers/ClosedAdsorberMassTransferDX.mo @@ -0,0 +1,240 @@ +within SorpLib.Components.MassTransfer.VLEMassTransfers; +model ClosedAdsorberMassTransferDX + "Loading-driven mass transfer models describing pure component adsorption in closed adsorbern" + extends SorpLib.Components.MassTransfer.BaseClasses.PartialPureMassTransferDX( + redeclare final SorpLib.Basics.Interfaces.FluidPorts.VLEPort_in port_a, + redeclare final SorpLib.Basics.Interfaces.FluidPorts.VLEPort_out port_b, + final no_components=Medium.nX, + redeclare replaceable model MassTransferCoefficient = + SorpLib.Components.MassTransfer.MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven.ConstantCoefficient + constrainedby + SorpLib.Components.MassTransfer.BaseClasses.PartialMassTransferCoefficientClosedAdsorberDX( + fluidProperties=fluidProperties), + redeclare replaceable model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = Medium, + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + calcCaloricProperties=false, + calcEntropicProperties=false, + calcDerivativesIsotherm=false, + calcDerivativesMassEnergyBalance=false, + calcDerivativesEntropyBalance=false)); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="Medium", group="Fluid"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of state records + // + Medium.ThermodynamicState stateAIn = if calculateFluidProperties and not + fluidPropertyPosition == SorpLib.Choices.MassTransferFluidProperties.PortBInlet + then Medium.setState_phX( + p = if limitPressureForCalculations then max(port_a.p, p_min) else port_a.p, + h = inStream(port_a.h_outflow), + X = inStream(port_a.Xi_outflow)) + else Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Instreaming state properties at port a"; + + Medium.ThermodynamicState stateBIn = if calculateFluidProperties and not + fluidPropertyPosition == SorpLib.Choices.MassTransferFluidProperties.PortAInlet + then Medium.setState_phX( + p = if limitPressureForCalculations then max(port_b.p, p_min) else port_b.p, + h = inStream(port_b.h_outflow), + X = inStream(port_b.Xi_outflow)) + else Medium.setState_phX( + p=Medium.p_default, + h=Medium.specificEnthalpy_pTX( + p=Medium.p_default, + T=Medium.T_default, + X=Medium.X_default), + X=Medium.X_default) + "Instreaming state properties at port b"; + + // + // Definition of connectors for conditional removed models / variables + // +protected + Modelica.Blocks.Interfaces.RealInput T_adsorptiveA_calc(final unit="K")= + Medium.temperature(state=stateAIn) if + calculateFluidProperties + "Temperature of adsorptive at port a"; + Modelica.Blocks.Interfaces.RealInput T_adsorptiveB_calc(final unit="K")= + Medium.temperature(state=stateBIn) if + calculateFluidProperties + "Temperature of adsorptive at port b"; + + Modelica.Blocks.Interfaces.RealInput d_adsorptiveA_calc(final unit="kg/m3")= + Medium.density(state=stateAIn) if + calculateFluidProperties + "Density of adsorptive at port a"; + Modelica.Blocks.Interfaces.RealInput d_adsorptiveB_calc(final unit="kg/m3")= + Medium.density(state=stateBIn) if + calculateFluidProperties + "Density of adsorptive at port b"; + + Modelica.Blocks.Interfaces.RealInput eta_adsorptiveA_calc(final unit="Pa.s")= + Medium.dynamicViscosity(state=stateAIn) if + calculateFluidProperties + "Dynamic viscosity of adsorptive at port a"; + Modelica.Blocks.Interfaces.RealInput eta_adsorptiveB_calc(final unit="Pa.s")= + Medium.dynamicViscosity(state=stateBIn) if + calculateFluidProperties + "Dynamic viscosity of adsorptive at port b"; + +equation + // + // Connections + // + connect(T_adsorptiveA_internal, T_adsorptiveA_calc); + connect(T_adsorptiveB_internal, T_adsorptiveB_calc); + + connect(d_adsorptiveA_internal, d_adsorptiveA_calc); + connect(d_adsorptiveB_internal, d_adsorptiveB_calc); + + connect(eta_adsorptiveA_internal, eta_adsorptiveA_calc); + connect(eta_adsorptiveB_internal, eta_adsorptiveB_calc); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass transfer model is used to connect adsorbate volumes with a VLE volume, +evaporator, condenser, or other adsorbate volumes. Thus, the mass heat transfer +model represents a hydraulic resistance between two models. Depending on the +driving potential (i.e., loading difference) and the chosen transport phenomena, +this model determines the mass flow rate between the connected models. Note that +port b is located at the adsorbate volume by design. +</p> + +<h4>Main equations</h4> +<p> +The model has a steady-state energy balance +</p> +<pre> + 0 = port_a.m_flow + port_b.m_flow; +</pre> +<p> +and a steady-state energy balance +</p> +<pre> + port_a.h_outflow = port_b.h_outflow; +</pre> +<p> +The mass flow rate <i>port_a.m_flow</i> is calculated linearly dependent on the +loading difference <i>Δx = port_a.x - port_b.x</i>: +</p> +<pre> + port_a.m_flow = β * Δx = β * (port_a.x - port_b.x); +</pre> +<p> +Note that the loading at port p corresponds to the loading of the connect adsorbate +volume and is given via an input. The loading at port a is calculated loading using +the pressure at port a and the actual adorpt temperature (i.e., temperature at port +b given via an input). The mass transport coefficient is calculated according to the +selected corrlation. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No storage of mass or energy + </li> + <li> + Isenthalpic process + </li> + <li> + Linear driving force approach + </li> +</ul> + +<h4>Typical use</h4> +<p> +This mass transfer model is used to describe the mass transfer between an +adsorbate volume and VLE volume or evaporator/condenser within closed adosrbers. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>canBeActivated</i>: + Defines if the mass transfer can activaly be activated or deactivated via an + input signal. + </li> + <li> + <i>isFlapValve</i>: + Defines if the mass transfer model behaves like a flap valve. + </li> + <li> + <i>isFlowAB</i>: + Defines the flow direction if the mass transfer models behaves like a flap + valve. + </li> + <li> + <i>offset_dp</i>: + Defines an optional offset for pressure difference if the mass transfer behaves + likes a flap valve. + </li> + <br> + <li> + <i>useBetaInput</i>: + Defines if mass transfer coefficient is given via an input. + </li> + <li> + <i>calculateFluidProperties</i>: + Defines if fluid properties are required to calculate the mass transfer coefficient. + </li> + <li> + <i>fluidPropertyPosition</i>: + Defines the position of the fluid properties used for calculations. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> + <li> + <i>avoid_events_activating</i>: + Defines if events shall be avoided via the noEvent()-operator when activating/ + deactivating the mass transfer. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Lanzerath, F. and Bau, U. and Seiler, J. and Bardow, A. (2015). Optimal design of adsorption chillers based on a validated dynamic object-oriented model. Science and Technology for the Built Environment, 21(3), 248-257. DOI: https://doi.org/10.1080/10789669.2014.990337. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 25, 2024, by Mirko Engelpracht:<br/> + Minor revisions and documentation. + </li> + <li> + January 18, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ClosedAdsorberMassTransferDX; diff --git a/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/Test_ClosedAdsorberMassTransferDP.mo b/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/Test_ClosedAdsorberMassTransferDP.mo new file mode 100644 index 0000000000000000000000000000000000000000..b47bd3689eae84571488538cc8339b5d31c04886 --- /dev/null +++ b/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/Test_ClosedAdsorberMassTransferDP.mo @@ -0,0 +1,169 @@ +within SorpLib.Components.MassTransfer.VLEMassTransfers.Tester; +model Test_ClosedAdsorberMassTransferDP + "Tester for the pressure-driven mass transfer model used within closed adsorbers describing pure component adsorption" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource fluidSource( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare package Medium = Medium) + "Fluid source" annotation (Placement( + transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={-40,60}))); + + SorpLib.Basics.Sources.Thermal.HeatSource heatSource( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=true) + "Heat source for fluid volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={40,60}))); + + // + // Definition of heat and mass transfer models + // + SorpLib.Components.MassTransfer.VLEMassTransfers.ClosedAdsorberMassTransferDP + massTransfer( + calculateFluidProperties=true, + fluidPropertyPosition=SorpLib.Choices.MassTransferFluidProperties.AverageInstreaming, + p_min(displayUnit="Pa") = 1000, + redeclare model MassTransferCoefficient = + MassTransferCoefficientCorrelations.ClosedAdsorber.PressureDriven.DarcyPackedBedSpheresKnudsenDiffusionPoiseuilleFlow, + redeclare package Medium = Medium) "Mass transfer model" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={-40,38}))); + + SorpLib.Components.HeatTransfer.ClosedAdsorberHeatTransfer heatTransfer( + redeclare model HeatTransferCoefficient = + HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.LinearAlphaA + ( + constantAlphaA=500, b=2), + fluidProperties= SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=adsorbateVolume.adsorbateProperties.p, + T=adsorbateVolume.adsorbateProperties.T, + rho=1/adsorbateVolume.workingPair.medium_sorbent.state_variables.v, + cp=adsorbateVolume.workingPair.medium_sorbent.additional_variables.c, + eta=0, + lambda=adsorbateVolume.workingPair.medium_sorbent.additional_variables.lambda)) + "Heat transfer model" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={40,40}))); + + // + // Definition of liquid volume models + // + Basics.Volumes.AdsorbateVolumes.AdsorbatePureVLEVolume adsorbateVolume( + T_initial=373.15, + useHeatPorts=false, + useHeatPortsX=false, + geometry(V=Modelica.Constants.pi/4*0.1^2*1), + redeclare model PureWorkingPairModel = + Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl, + limitLowerPressure=true, + limitLowerPressureAdsorptive=true), + x_initial=0.1, + redeclare final package Medium = Medium, + nSorptionPorts=1) + "Model of an adsorbate volume" + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={0,0}))); + + // + // Definition of thermal boundaries + // + +protected + Modelica.Blocks.Sources.Sine input_T( + amplitude=50, + f=1/250, + offset=273.15 + 75) "Input for temperature" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={40,80}))); + + Modelica.Blocks.Sources.Sine input_p( + amplitude=2.5e3, + f=1/250, + offset=5e3) + "Input for pressure" + annotation (Placement(transformation( + extent={{10,10},{-10,-10}}, + rotation=90, + origin={-40,80}))); + +equation + // + // Connections + // + connect(massTransfer.port_b, adsorbateVolume.fp_sorption[1]) annotation (Line( + points={{-40,30},{-40,20},{-3.2,20},{-3.2,8.8}}, + color={0,140,72}, + thickness=1)); + connect(fluidSource.port, massTransfer.port_a) annotation (Line( + points={{-40,60},{-40,45.8}}, + color={0,140,72}, + thickness=1)); + + connect(heatSource.port, heatTransfer.hp_b[1]) annotation (Line( + points={{40,60},{40,48}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer.hp_a[1], adsorbateVolume.hp_sorption) annotation (Line( + points={{40,32},{40,28},{3.2,28},{3.2,15.2}}, + color={238,46,47}, + thickness=1)); + + connect(input_p.y, fluidSource.p_input) annotation (Line(points={{-40,69},{-40, + 64},{-45,64},{-45,61.2}}, color={0,0,127})); + connect(input_T.y, heatSource.T_input) annotation (Line(points={{40,69},{40,64}, + {45.2,64},{45.2,61}}, + color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the pressure-driven mass transfer model used within closed +adsorbers describing pure component adsorption. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 24, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_ClosedAdsorberMassTransferDP; diff --git a/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/Test_ClosedAdsorberMassTransferDX.mo b/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/Test_ClosedAdsorberMassTransferDX.mo new file mode 100644 index 0000000000000000000000000000000000000000..b871a1169b4ffa48c3d04dd498366d4857a9720d --- /dev/null +++ b/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/Test_ClosedAdsorberMassTransferDX.mo @@ -0,0 +1,179 @@ +within SorpLib.Components.MassTransfer.VLEMassTransfers.Tester; +model Test_ClosedAdsorberMassTransferDX + "Tester for the loading-driven mass transfer model used within closed adsorbers describing pure component adsorption" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE + "Working pair model" + annotation (Dialog(tab="General", group="Media"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource fluidSource( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=323.15, + redeclare package Medium = Medium) + "Fluid source" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={-40,60}))); + + SorpLib.Basics.Sources.Thermal.HeatSource heatSource( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=true) + "Heat source for fluid volume" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={40,60}))); + + // + // Definition of heat and mass transfer models + // + SorpLib.Components.MassTransfer.VLEMassTransfers.ClosedAdsorberMassTransferDX + massTransfer( + calculateFluidProperties=true, + fluidPropertyPosition=SorpLib.Choices.MassTransferFluidProperties.AverageInstreaming, + p_min(displayUnit="Pa") = 1000, + redeclare model MassTransferCoefficient = + MassTransferCoefficientCorrelations.ClosedAdsorber.LoadingDriven.GlueckaufArrhenius + (m_sorbent=adsorbateVolume.m_sor_initial), + x_adsorpt_input=adsorbateVolume.x, + T_adsorpt_input=adsorbateVolume.T, + redeclare model WorkingPair = WorkingPair, + redeclare package Medium = Medium) "Mass transfer model" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={-40,40}))); + + SorpLib.Components.HeatTransfer.ClosedAdsorberHeatTransfer heatTransfer( + redeclare model HeatTransferCoefficient = + HeatTransfer.HeatTransferCoefficientCorrelations.ClosedAdsorber.LinearAlphaA + ( + constantAlphaA=500, b=2), + fluidProperties=SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=adsorbateVolume.adsorbateProperties.p, + T=adsorbateVolume.adsorbateProperties.T, + rho=1/adsorbateVolume.workingPair.medium_sorbent.state_variables.v, + cp=adsorbateVolume.workingPair.medium_sorbent.additional_variables.c, + eta=0, + lambda=adsorbateVolume.workingPair.medium_sorbent.additional_variables.lambda)) + "Heat transfer model" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={40,40}))); + + // + // Definition of liquid volume models + // + Basics.Volumes.AdsorbateVolumes.AdsorbatePureVLEVolume adsorbateVolume( + T_initial=373.15, + useHeatPorts=false, + useHeatPortsX=false, + geometry(V=Modelica.Constants.pi/4*0.1^2*1), + redeclare model PureWorkingPairModel = WorkingPair ( + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl, + limitLowerPressure=true, + limitLowerPressureAdsorptive=true), + x_initial=0.1, + redeclare final package Medium = Medium, + nSorptionPorts=1) + "Model of an adsorbate volume" + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={0,0}))); + + // + // Definition of thermal boundaries + // +protected + Modelica.Blocks.Sources.Sine input_T( + amplitude=50, + f=1/250, + offset=273.15 + 75) "Input for temperature" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={40,80}))); + + Modelica.Blocks.Sources.Sine input_p( + amplitude=2.5e3, + f=1/250, + offset=5e3) + "Input for pressure" + annotation (Placement(transformation( + extent={{10,10},{-10,-10}}, + rotation=90, + origin={-40,80}))); + +equation + // + // Connections + // + connect(fluidSource.port, massTransfer.port_a) annotation (Line( + points={{-40,60},{-40,47.8}}, + color={0,140,72}, + thickness=1)); + connect(massTransfer.port_b, adsorbateVolume.fp_sorption[1]) annotation (Line( + points={{-40,32},{-40,20},{-3.2,20},{-3.2,8.8}}, + color={0,140,72}, + thickness=1)); + + connect(heatSource.port, heatTransfer.hp_b[1]) annotation (Line( + points={{40,60},{40,48}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer.hp_a[1], adsorbateVolume.hp_sorption) annotation (Line( + points={{40,32},{40,28},{3.2,28},{3.2,15.2}}, + color={238,46,47}, + thickness=1)); + + connect(input_p.y, fluidSource.p_input) annotation (Line(points={{-40,69},{-40, + 64},{-45,64},{-45,61.2}}, color={0,0,127})); + connect(input_T.y, heatSource.T_input) annotation (Line(points={{40,69},{40,64}, + {45.2,64},{45.2,61}}, + color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the loading-driven mass transfer model used within closed +adsorbers describing pure component adsorption. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 25, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_ClosedAdsorberMassTransferDX; diff --git a/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/package.mo b/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..18f9d41c4a67a991ff8adc1d0ffad8dca4a1765a --- /dev/null +++ b/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.MassTransfer.VLEMassTransfers; +package Tester "Models to test and varify mass transfer models" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented mass transfer +models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructering the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/package.order b/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..d5178c20bf5e3a6bf48b96458509226e58376862 --- /dev/null +++ b/SorpLib/Components/MassTransfer/VLEMassTransfers/Tester/package.order @@ -0,0 +1,2 @@ +Test_ClosedAdsorberMassTransferDP +Test_ClosedAdsorberMassTransferDX diff --git a/SorpLib/Components/MassTransfer/VLEMassTransfers/package.mo b/SorpLib/Components/MassTransfer/VLEMassTransfers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..cd28e97653b43adaa501a76fdf6fdeb2ceb84aa7 --- /dev/null +++ b/SorpLib/Components/MassTransfer/VLEMassTransfers/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Components.MassTransfer; +package VLEMassTransfers "Mass transfer models for real fluids (i.e., with a two-phase regime)" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains mass transfer models using real fluids (i.e., with a two- +phase regime) that are based on the open-source Modelica Standard Library (MSL). +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end VLEMassTransfers; diff --git a/SorpLib/Components/MassTransfer/VLEMassTransfers/package.order b/SorpLib/Components/MassTransfer/VLEMassTransfers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..8e9f26f089be415c75b25a719493b98c5154ae5f --- /dev/null +++ b/SorpLib/Components/MassTransfer/VLEMassTransfers/package.order @@ -0,0 +1,3 @@ +ClosedAdsorberMassTransferDP +ClosedAdsorberMassTransferDX +Tester diff --git a/SorpLib/Components/MassTransfer/package.mo b/SorpLib/Components/MassTransfer/package.mo index dddf08f0dc7b367fbfac57b20843ca302dbd696d..62e4d499c3d64d65815829221572e63b0f5a3596 100644 --- a/SorpLib/Components/MassTransfer/package.mo +++ b/SorpLib/Components/MassTransfer/package.mo @@ -1,10 +1,21 @@ within SorpLib.Components; -package MassTransfer -extends SorpLib.Internals.ClassTypes.ComponentPackage; - - - - - +package MassTransfer "Models and correlations to calculate mass transfers" + extends SorpLib.Icons.MassTransfersPackage; + annotation (Documentation(info="<html> +<p> +This package includes various mass transfer models for deal gases and real +substances (i.e., with a two-phase region). The mass transfer models can be +used within closed or open adsorbers to describe the mass transfer between +adsorbate volumes and other volumes, such as gas, VLE, or phase saparator +volumes. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); end MassTransfer; diff --git a/SorpLib/Components/MassTransfer/package.order b/SorpLib/Components/MassTransfer/package.order index b106aa7c21de9e5bbb4172020a98897f978d44f0..746da38c54b57d6126deacf74182f0880880a49b 100644 --- a/SorpLib/Components/MassTransfer/package.order +++ b/SorpLib/Components/MassTransfer/package.order @@ -1,7 +1,4 @@ -MassTransferFlow -MassTransferDiffusion -MassTransferDiffusionFlow -Partial -MassTransferPhenomena -Testers -Record +BaseClasses +Records +MassTransferCoefficientCorrelations +VLEMassTransfers diff --git a/SorpLib/Components/OpenAdsorber/Geometry/CylindricAdsorber.mo b/SorpLib/Components/OpenAdsorber/Geometry/CylindricAdsorber.mo deleted file mode 100644 index 12e2aefd52ab64d2b9e59e00abf51e5111a95307..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/Geometry/CylindricAdsorber.mo +++ /dev/null @@ -1,29 +0,0 @@ -within SorpLib.Components.OpenAdsorber.Geometry; -record CylindricAdsorber - extends GeneralAdsorberGeometry( - final innerVolume = length*Modelica.Constants.pi*(innerDiameter/2)^2, - final outerVolume = length*Modelica.Constants.pi*(outerDiameter/2)^2, - final innerLateralArea = Modelica.Constants.pi*innerDiameter*length, - final outerLateralArea = Modelica.Constants.pi*outerDiameter*length, - final innerCrossSection = Modelica.Constants.pi*(innerDiameter/2)^2, - final hydraulicDiameter = innerDiameter); - - parameter Modelica.SIunits.Diameter innerDiameter=0.15 - "Inner diameter of adsorber" annotation (Dialog(group="Geometry")); - parameter Modelica.SIunits.Diameter outerDiameter=0.16 - "Outer diameter of adsorber" annotation (Dialog(group="Geometry")); - - annotation (Documentation(info="<html> - <p> - This record describes a cylindric open adsorber. <br> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end CylindricAdsorber; diff --git a/SorpLib/Components/OpenAdsorber/Geometry/GeneralAdsorberGeometry.mo b/SorpLib/Components/OpenAdsorber/Geometry/GeneralAdsorberGeometry.mo deleted file mode 100644 index 77edfabfd67591f3421f511fd4276240bfed7751..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/Geometry/GeneralAdsorberGeometry.mo +++ /dev/null @@ -1,61 +0,0 @@ -within SorpLib.Components.OpenAdsorber.Geometry; -record GeneralAdsorberGeometry - extends SorpLib.Internals.ClassTypes.Record; - - parameter Real psi(final unit="1")=0.34 "Void percentage of packed bed" annotation (Dialog(group="Packed bed")); - - parameter Modelica.SIunits.Density bulkDensity=750 - "Bulk density of packed bed" annotation (Dialog(group="Packed bed")); - - parameter Modelica.SIunits.Diameter particleDiameter=0.002 - "Diameter of particle" annotation (Dialog(group="Packed bed")); - - parameter Modelica.SIunits.Length length=0.088 "Length of adsorber" annotation (Dialog(group="Geometry")); - - parameter Modelica.SIunits.Volume innerVolume "Inner volume of adsorber" annotation (Dialog(group="Geometry")); - - parameter Modelica.SIunits.Volume outerVolume "Outer volume of adsorber" annotation (Dialog(group="Geometry")); - - parameter Modelica.SIunits.Area innerLateralArea - "Inner lateral area of adsorber" annotation (Dialog(group="Geometry")); - - parameter Modelica.SIunits.Area outerLateralArea - "Outer lateral area of adsorber" annotation (Dialog(group="Geometry")); - - parameter Modelica.SIunits.CrossSection innerCrossSection "Inner cross section of adsorber" annotation (Dialog(group="Geometry")); - - parameter Modelica.SIunits.Diameter hydraulicDiameter "Hydraulic diameter" annotation (Dialog(group="Geometry")); - - final parameter Modelica.SIunits.Diameter hydraulicDiameter_bed = (2/3)*psi/(1-psi)*particleDiameter "Hydraulic diameter of packed bed with spheric particles"; - - final parameter Modelica.SIunits.Mass massAdsorbent = innerVolume*bulkDensity; - - final parameter Modelica.SIunits.Volume bedVolume = innerVolume*(1-psi) - "Volume of bed"; - - final parameter Modelica.SIunits.Volume wallVolume = outerVolume-innerVolume - "Volume of wall"; - - final parameter Modelica.SIunits.Volume particleVolume = (Modelica.Constants.pi/6)*(particleDiameter)^3 - "Volume of particle"; - - final parameter Real particleNumber = bedVolume/particleVolume - "Number of particles"; - - final parameter Modelica.SIunits.Area particleSurface = particleNumber*Modelica.Constants.pi*(particleDiameter)^2 - "Total surface of particles"; - - annotation (Documentation(info="<html> - <p> - This record containes all information necessary to describe a open adsorber geometry. <br> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end GeneralAdsorberGeometry; diff --git a/SorpLib/Components/OpenAdsorber/Geometry/RectangularAdsorber.mo b/SorpLib/Components/OpenAdsorber/Geometry/RectangularAdsorber.mo deleted file mode 100644 index 5041271dc2a24be462f4329d194792cdd7e7e495..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/Geometry/RectangularAdsorber.mo +++ /dev/null @@ -1,30 +0,0 @@ -within SorpLib.Components.OpenAdsorber.Geometry; -record RectangularAdsorber - extends GeneralAdsorberGeometry( - final innerVolume = length*innerCrossSection, - final outerVolume = length*outerCrossSection, - final innerLateralArea = length*2*(innerWidth+innerHeigth), - final outerLateralArea = length*2*(innerWidth+innerHeigth+4*wallThickness), - final innerCrossSection = innerWidth*innerHeigth); - - parameter Modelica.SIunits.Diameter innerWidth=0.1 - "Inner width of adsorber" annotation (Dialog(group="Geometry")); - parameter Modelica.SIunits.Diameter innerHeigth=0.1 - "Inner height of adsorber" annotation (Dialog(group="Geometry")); - parameter Modelica.SIunits.Thickness wallThickness=0.01 - "Wall thickness of adsorber" annotation (Dialog(group="Geometry")); - - annotation (Documentation(info="<html> - <p> - This record describes a rectanular open adsorber. <br> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end RectangularAdsorber; diff --git a/SorpLib/Components/OpenAdsorber/Geometry/package.mo b/SorpLib/Components/OpenAdsorber/Geometry/package.mo deleted file mode 100644 index 8ee4c7c720277dd6c630cd26815075022c49655e..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/Geometry/package.mo +++ /dev/null @@ -1,11 +0,0 @@ -within SorpLib.Components.OpenAdsorber; -package Geometry -extends SorpLib.Internals.ClassTypes.RecordPackage; - - - - - -annotation (Documentation(info="<html> -</html>")); -end Geometry; diff --git a/SorpLib/Components/OpenAdsorber/Geometry/package.order b/SorpLib/Components/OpenAdsorber/Geometry/package.order deleted file mode 100644 index c8840b00c225e05eb2804fa224859f4488a32802..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/Geometry/package.order +++ /dev/null @@ -1,3 +0,0 @@ -GeneralAdsorberGeometry -CylindricAdsorber -RectangularAdsorber diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/HeatTransfer.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/HeatTransfer.mo deleted file mode 100644 index 91ed4a4e9518ed8abf2153c9feff69c6b60bc01a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/HeatTransfer.mo +++ /dev/null @@ -1,20 +0,0 @@ -within SorpLib.Components.OpenAdsorber.HeatAndMassTransfer; -model HeatTransfer - extends SorpLib.Components.HeatTransfer.HeatTransfer; - - inner input TILMedia.Internals.PropertyRecord properties_gas; - inner input Modelica.SIunits.MassFlowRate mdotHydraulic_gas; - - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false)), - Documentation(info="<html> - <h4>Author Information</h4> - <p> - <ul> - <li>December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end HeatTransfer; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/MassTransferDiffusion.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/MassTransferDiffusion.mo deleted file mode 100644 index 1d6bd153c15cf34a0bd6607b4df7073ba90cae0a..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/MassTransferDiffusion.mo +++ /dev/null @@ -1,20 +0,0 @@ -within SorpLib.Components.OpenAdsorber.HeatAndMassTransfer; -model MassTransferDiffusion - extends SorpLib.Components.MassTransfer.MassTransferDiffusion; - - inner input TILMedia.Internals.PropertyRecord properties_gas; - inner input Modelica.SIunits.MassFlowRate mdotHydraulic_gas; - - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false)), - Documentation(info="<html> - <h4>Author Information</h4> - <p> - <ul> - <li>December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end MassTransferDiffusion; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/PackedBedGas_HougenMarshall1947.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/PackedBedGas_HougenMarshall1947.mo deleted file mode 100644 index 988426c8ad755c4c12384c4caf580a387d19e610..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/PackedBedGas_HougenMarshall1947.mo +++ /dev/null @@ -1,45 +0,0 @@ -within SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.HeatTransfer; -model PackedBedGas_HougenMarshall1947 "Heat transfer between packed bed and gas according to Hougen and Marshall (1947)" - extends - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer(final computeTransportProperties=true); - - outer parameter Integer nCells; - outer parameter SorpLib.Components.OpenAdsorber.Geometry.GeneralAdsorberGeometry adsorberGeometry; - - outer TILMedia.Internals.PropertyRecord properties_gas; - outer Modelica.SIunits.MassFlowRate mdotHydraulic_gas; - - Modelica.SIunits.ReynoldsNumber Re_par "Reynolds-Number for one Particle"; - -equation - Re_par = noEvent(abs(mdotHydraulic_gas))*adsorberGeometry.particleDiameter/(adsorberGeometry.innerCrossSection*properties_gas.transp.eta*adsorberGeometry.psi); - - alphaA = 0.683*properties_gas.cp*mdotHydraulic_gas/(adsorberGeometry.innerCrossSection*adsorberGeometry.psi)*(Re_par+1)^(-0.51)*adsorberGeometry.particleSurface/nCells; - - annotation (Documentation(info="<html> -<p> - This model calculates heat transfer coefficient from gas to adsorbent for packed beds according to Hougen and Marshall (1947). The hydraulic mass flow rate, the fluid properties record, the adsorber geometry and discretization number are defined as outer objects and thus taken from the overlying model level. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> <i><code>α</code></i> = 0.683 <i>c</i><sub>p</sub> <i><code>ṁ</code></i><sub>hydraulic</sub> / (<i>A</i><sub>cs</sub> <i><code>ψ</code></i>) Re<sup>-0.51</sup> -<p>where <i><code>α</code></i> is the heat transfer coefficient, <i>c</i><sub>p</sub> is the specific heat capacity, <i><code>ṁ</code></i><sub>hydraulic</sub> is the hydraulic mass flow, <i>A</i><sub>cs</sub> is the cross sectional area, <i><code>ψ</code></i> is the void percentage of packed bed and Re is the Reynolds number. </p> -<p>For detailed information we refer to Hougen and Marshall (1947).</p> -</p> - -<h4>References</h4> -<ul> -<li>Adsorption from a Fluid Stream flowing through a stationary Granular Bed, Hougen O.A. and Marshall W.R., Chemical Engineering Progress, 1947. </li> -</ul> - -<h4>Author Information</h4> -<p> - <ul> - <li> - December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end PackedBedGas_HougenMarshall1947; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/PackedBedGas_Kast1988.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/PackedBedGas_Kast1988.mo deleted file mode 100644 index ba39e405c5dfda8b802ce6a782e061c066a69fb0..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/PackedBedGas_Kast1988.mo +++ /dev/null @@ -1,64 +0,0 @@ -within SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.HeatTransfer; -model PackedBedGas_Kast1988 "Heat transfer between packed bed and gas according to Kast (1988)" - extends - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer(final computeTransportProperties=true); - - outer parameter Integer nCells; - outer parameter SorpLib.Components.OpenAdsorber.Geometry.GeneralAdsorberGeometry adsorberGeometry; - - outer TILMedia.Internals.PropertyRecord properties_gas; - outer Modelica.SIunits.MassFlowRate mdotHydraulic_gas; - - final parameter Real Nu_min=2 "For spehrical particles"; - final parameter Real formFactor=1+1.5*(1-adsorberGeometry.psi) "For spherical particles"; - - Modelica.SIunits.ReynoldsNumber Re_par "Reynolds-Number for one Particle"; - Modelica.SIunits.NusseltNumber Nu_lam "Laminar Nusselt-Number"; - Modelica.SIunits.NusseltNumber Nu_turb "Turbulent Nusselt-Number"; - Modelica.SIunits.NusseltNumber Nu_Par "Nusselt-Number for one Particle"; - Modelica.SIunits.NusseltNumber Nu_Bed "Nusselt-Number for all Bed"; - -equation - Re_par = noEvent(abs(mdotHydraulic_gas))*adsorberGeometry.particleDiameter/(adsorberGeometry.innerCrossSection*properties_gas.transp.eta*adsorberGeometry.psi); - - Nu_lam = 0.664*(Re_par+1)^0.5*properties_gas.transp.Pr^0.5; - - Nu_turb = (0.037*(Re_par+1)^0.8*properties_gas.transp.Pr)/(1 + 2.443*(Re_par+1)^(-0.8)*(properties_gas.transp.Pr^(2/3) - 1)); - - Nu_Par = Nu_min + (Nu_lam^2 + Nu_turb^2)^0.5; - - Nu_Bed = formFactor*Nu_Par; - - alphaA = Nu_Bed*properties_gas.transp.lambda/adsorberGeometry.particleDiameter*adsorberGeometry.particleSurface/nCells; - - annotation (Documentation(info="<html> -<p> - This model calculates heat transfer coefficient from gas to adsorbent for packed beds according to Kast (1988). The hydraulic mass flow rate, the fluid properties record, the adsorber geometry and discretization number are defined as outer objects and thus taken from the overlying model level. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> Nu = <i>f</i><sub>a</sub> (Nu<sub>min</sub> + <code>√</code>(Nu<sub>lam</sub><sup>2</sup> + Nu<sub>turb</sub><sup>2</sup>)) </p> -<p>where Nu is the Nusselt number and <i>f</i><sub>a</sub> is the form factor. </p> -Nu<sub>lam</sub> and Nu<sub>turb</sub> are calculated by following correlations: -<p align=\"center\"> Nu<sub>lam</sub> = 0.664 <code>√</code>Re <code>√</code>Pr </p> -<p align=\"center\"> Nu<sub>turb</sub> = 0.037 Re<sup>0.8</sup> Pr / (1 + 2.443 Re<sup>-0.8</sup> (Pr<sup>2/3</sup> - 1)) </p> -<p>where Re is the Reynolds number and Pr is the Prandtl number. </p> -<p>For detailed information we refer to Kast (1988). </p> -</p> - -<h4>References</h4> -<ul> -<li>Adsorption aus der Gasphase, Werner Kast, Darmstadt, 1988. </li> -</ul> - -<h4>Author Information</h4> -<p> - <ul> - <li> - December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end PackedBedGas_Kast1988; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/PackedBedWall_Kast1988.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/PackedBedWall_Kast1988.mo deleted file mode 100644 index 4515249f5d94419f6ffb9d614c4b0ee972b846c6..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/PackedBedWall_Kast1988.mo +++ /dev/null @@ -1,58 +0,0 @@ -within SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.HeatTransfer; -model PackedBedWall_Kast1988 "Heat transfer between packed bed and wall according to Kast (1988)" - extends - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer(final computeTransportProperties=true); - - outer parameter Integer nCells; - outer parameter SorpLib.Components.OpenAdsorber.Geometry.GeneralAdsorberGeometry adsorberGeometry; - - outer TILMedia.Internals.PropertyRecord properties_gas; - outer Modelica.SIunits.MassFlowRate mdotHydraulic_gas; - - final parameter Real c=12 "Parameter for particle form consideration --> 12 for spherical"; - - Modelica.SIunits.PecletNumber Pe - "Peclet number"; - - Modelica.SIunits.NusseltNumber Nu_lengthCorrection; - - Modelica.SIunits.NusseltNumber Nu - "Nusselt number"; - - final parameter Modelica.SIunits.Length mixtureLength = 1.15*adsorberGeometry.particleDiameter "Mixture Length for spherical particles"; - -equation - Pe=noEvent(abs(mdotHydraulic_gas))/(properties_gas.d*adsorberGeometry.innerCrossSection*adsorberGeometry.psi)*mixtureLength/(properties_gas.transp.lambda/properties_gas.d/properties_gas.cp); - - Nu_lengthCorrection=-1.55e-6*Pe^2+0.04285*Pe+24.57 "Own fit for spherical particles from Kast (1988) p. 136"; - - Nu=Nu_lengthCorrection/(1+c*adsorberGeometry.length/adsorberGeometry.hydraulicDiameter/(Pe+0.1)); - - alphaA=Nu*properties_gas.transp.lambda/mixtureLength*adsorberGeometry.innerLateralArea/nCells; - - annotation (Documentation(info="<html> -<p> - This model calculates heat transfer coefficient from gas to wall for packed beds according to Kast (1988). The hydraulic mass flow rate, the fluid properties record, the adsorber geometry and discretization number are defined as outer objects and thus taken from the overlying model level. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> Nu (1 + <i>c</i> <i>L / D</i> / Pe) = <i>f</i>(Pe)</p> -<p>where Nu is the Nusselt number, <i>c</i> is a constant for the particle form, <i>L</i> is the hydraulic length, <i>D</i> is the hydraulic diameter and Pe is the Peclet number. The correlation <i>f</i>(Pe) is fitted with a second order polynom according to the diagram in Kast (1988), p. 136. </p> -</p> - -<h4>References</h4> -<ul> -<li>Adsorption aus der Gasphase, Werner Kast, Darmstadt, 1988. </li> -</ul> - -<h4>Author Information</h4> -<p> - <ul> - <li> - December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end PackedBedWall_Kast1988; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.mo deleted file mode 100644 index 11111c25549954c6e8006020a66cd31e3e48b471..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.mo +++ /dev/null @@ -1,10 +0,0 @@ -within SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena; -package HeatTransfer - extends SorpLib.Internals.ClassTypes.ModelPackage; - - - - - - -end HeatTransfer; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.order b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.order deleted file mode 100644 index 357276534e3707baea9fbbe8ae51fdd624881861..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/HeatTransfer/package.order +++ /dev/null @@ -1,3 +0,0 @@ -PackedBedWall_Kast1988 -PackedBedGas_Kast1988 -PackedBedGas_HougenMarshall1947 diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/PackedBedGas_HougenMarshall1947.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/PackedBedGas_HougenMarshall1947.mo deleted file mode 100644 index 4be518fcfb3f53de31e82b3d9d017e58a70f3f1b..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/PackedBedGas_HougenMarshall1947.mo +++ /dev/null @@ -1,48 +0,0 @@ -within SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.MassTransfer; -model PackedBedGas_HougenMarshall1947 "Mass transfer between packed bed and gas according to Hougen and Marshall (1947)" - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp( final computeTransportProperties=true); - - outer parameter Modelica.SIunits.MolarMass M_adsorbent "Molar mass of adsorbate"; - outer parameter Modelica.SIunits.MolarMass M_carrier "Molar mass of carrier"; - - outer parameter Integer nCells; - outer parameter SorpLib.Components.OpenAdsorber.Geometry.GeneralAdsorberGeometry adsorberGeometry; - - outer TILMedia.Internals.PropertyRecord properties_gas; - outer Modelica.SIunits.MassFlowRate mdotHydraulic_gas; - - Modelica.SIunits.ReynoldsNumber Re_par "Reynolds number for one particle"; - -equation - Re_par=noEvent(abs(mdotHydraulic_gas))*adsorberGeometry.particleDiameter/(adsorberGeometry.innerCrossSection*properties_gas.transp.eta*adsorberGeometry.psi); - - beta=0.704*noEvent(abs(mdotHydraulic_gas))/(adsorberGeometry.innerCrossSection*adsorberGeometry.psi)*(Re_par+1)^(-0.51)*(M_adsorbent/M_carrier)/properties_gas.p*adsorberGeometry.particleSurface/nCells; - - annotation (Documentation(info="<html> -<p> - This model calculates mass transfer coefficient from gas to adsorbent for packed beds according to Hougen and Marshall (1947). The hydraulic mass flow rate, the fluid properties record, the adsorber geometry and discretization number are defined as outer objects and thus taken from the overlying model level. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> <i><code>β</code></i> = 0.704 <i><code>ṁ</code></i><sub>hydraulic</sub> / (<i>A</i><sub>cs</sub> <i><code>ψ</code></i>) Re<sup>-0.51</sup> -<p>where <i><code>β</code></i> is the mass transfer coefficient, <i><code>ṁ</code></i><sub>hydraulic</sub> is the hydraulic mass flow, <i>A</i><sub>cs</sub> is the cross sectional area, <i><code>ψ</code></i> is the void percentage of packed bed and Re is the Reynolds number. </p> -<p>For detailed information we refer to Hougen and Marshall (1947).</p> -</p> - -<h4>References</h4> -<ul> -<li>Adsorption from a Fluid Stream flowing through a stationary Granular Bed, Hougen O.A. and Marshall W.R., Chemical Engineering Progress, 1947. </li> -</ul> - -<h4>Author Information</h4> -<p> - <ul> - <li> - December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end PackedBedGas_HougenMarshall1947; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/PackedBedGas_Kast1988.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/PackedBedGas_Kast1988.mo deleted file mode 100644 index 2022e3ac08ccf84adb1771ef4bc5af842cc8f041..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/PackedBedGas_Kast1988.mo +++ /dev/null @@ -1,72 +0,0 @@ -within SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.MassTransfer; -model PackedBedGas_Kast1988 "Mass transfer between packed bed and gas according to Kast (1988)" - extends - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp( final computeTransportProperties=true); - - outer parameter Modelica.SIunits.MolarMass M_adsorbent "Molar mass of adsorbate"; - - outer parameter Integer nCells; - outer parameter SorpLib.Components.OpenAdsorber.Geometry.GeneralAdsorberGeometry adsorberGeometry; - - outer TILMedia.Internals.PropertyRecord properties_gas; - outer Modelica.SIunits.MassFlowRate mdotHydraulic_gas; - - final parameter Real Sh_min=2 "For spehrical particles"; - final parameter Real formFactor=1+1.5*(1-adsorberGeometry.psi) "For spherical particles"; - - Modelica.SIunits.ReynoldsNumber Re_par "Reynolds number for one particle"; - Modelica.SIunits.DiffusionCoefficient diffusionCoefficient "Diffusion coefficient in binary mixture"; - Modelica.SIunits.SchmidtNumber Sc "Schmidt number"; - Real Sh_lam "Laminar Sherwood-Number"; - Real Sh_turb "Turbulent Sherwood-Number"; - Real Sh_par "Sherwood-Number for one Particle"; - Real Sh_bed "Sherwood-Number for entire Bed"; - -equation - Re_par = noEvent(abs(mdotHydraulic_gas))*adsorberGeometry.particleDiameter/(adsorberGeometry.innerCrossSection*properties_gas.transp.eta*adsorberGeometry.psi); - - diffusionCoefficient = 1.72e-7*properties_gas.T-2.438e-5; - - Sc = properties_gas.transp.eta/properties_gas.d/diffusionCoefficient; - - Sh_lam = 0.664*(Re_par+1)^0.5*Sc^0.5; - - Sh_turb = (0.037*(Re_par+1)^0.8*Sc)/(1 + 2.443*(Re_par+1)^(-0.8)*(Sc^(2/3) - 1)); - - Sh_par = Sh_min + (Sh_lam^2 + Sh_turb^2)^0.5; - - Sh_bed = formFactor*Sh_par; - - beta = Sh_bed*diffusionCoefficient/adsorberGeometry.particleDiameter*M_adsorbent/(properties_gas.T*Modelica.Constants.R)*adsorberGeometry.particleSurface/nCells; - - annotation (Documentation(info="<html> -<p> - This model calculates heat mass coefficient from gas to adsorbent for packed beds according to Kast (1988). The hydraulic mass flow rate, the fluid properties record, the adsorber geometry and discretization number are defined as outer objects and thus taken from the overlying model level. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> Sh = <i>f</i><sub>a</sub> (Sh<sub>min</sub> + <code>√</code>(Sh<sub>lam</sub><sup>2</sup> + Sh<sub>turb</sub><sup>2</sup>)) </p> -<p>where Sh is the Sherwood number and <i>f</i><sub>a</sub> is the form factor. </p> -Sh<sub>lam</sub> and Sh<sub>turb</sub> are calculated by following correlations: -<p align=\"center\"> Sh<sub>lam</sub> = 0.664 <code>√</code>Re <code>√</code>Sc </p> -<p align=\"center\"> Sh<sub>turb</sub> = 0.037 Re<sup>0.8</sup> Sc / (1 + 2.443 Re<sup>-0.8</sup> (Sc<sup>2/3</sup> - 1)) </p> -<p>where Re is the Reynolds number and Sc is the Schmidt number. </p> -<p>For detailed information we refer to Kast (1988). </p> -</p> - -<h4>References</h4> -<ul> -<li>Adsorption aus der Gasphase, Werner Kast, Darmstadt, 1988. </li> -</ul> - -<h4>Author Information</h4> -<p> - <ul> - <li> - December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end PackedBedGas_Kast1988; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/package.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/package.mo deleted file mode 100644 index e307e18fd5faf8a30a78f5c0bb77ada77eb635d9..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/package.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena; -package MassTransfer - extends SorpLib.Internals.ClassTypes.ModelPackage; - - - - -end MassTransfer; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/package.order b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/package.order deleted file mode 100644 index 526b0405601f6ea78bf6d25d88896f1782caa8f4..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/MassTransfer/package.order +++ /dev/null @@ -1,2 +0,0 @@ -PackedBedGas_Kast1988 -PackedBedGas_HougenMarshall1947 diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/package.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/package.mo deleted file mode 100644 index fab7cd978b80bd1056749849845c73c81ace74ca..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.OpenAdsorber.HeatAndMassTransfer; -package TransportPhenomena - extends SorpLib.Internals.ClassTypes.ModelPackage; - -end TransportPhenomena; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/package.order b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/package.order deleted file mode 100644 index b9c86f1c9f1a3dd35fcee9fa819cd8653b4da268..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/TransportPhenomena/package.order +++ /dev/null @@ -1,2 +0,0 @@ -HeatTransfer -MassTransfer diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/package.mo b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/package.mo deleted file mode 100644 index c8ae297b479dee1ea6778178fd53b559576c36a4..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.OpenAdsorber; -package HeatAndMassTransfer - extends SorpLib.Internals.ClassTypes.ModelPackage; - - -end HeatAndMassTransfer; diff --git a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/package.order b/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/package.order deleted file mode 100644 index 2917363d0511e7edc1b79d745ac6c343472934bc..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/HeatAndMassTransfer/package.order +++ /dev/null @@ -1,3 +0,0 @@ -MassTransferDiffusion -HeatTransfer -TransportPhenomena diff --git a/SorpLib/Components/OpenAdsorber/OpenAdsorber.mo b/SorpLib/Components/OpenAdsorber/OpenAdsorber.mo deleted file mode 100644 index 409908cf107a3565b32d25e4664d62456cc07162..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/OpenAdsorber.mo +++ /dev/null @@ -1,433 +0,0 @@ -within SorpLib.Components.OpenAdsorber; -model OpenAdsorber "Open adsorption system" - - /*********************** SIM ***********************************/ - - inner parameter TILMedia.GasTypes.BaseGas gasType=sim.gasType1 "Gas type" - annotation (Dialog(tab="SIM", group="SIM"), choices(choice=sim.gasType1 - "Gas 1 as defined in SIM", choice=sim.gasType2 - "Gas 2 as defined in SIM")); - parameter TILMedia.VLEFluidTypes.BaseVLEFluid vleFluidType=sim.vleFluidType1 - "VLE fluid type" annotation (Dialog(tab="SIM", group="SIM"), choices( - choice=sim.vleFluidType1 "VLE fluid 1 as defined in SIM", - choice=sim.vleFluidType2 "VLE fluid 2 as defined in SIM", - choice=sim.vleFluidType3 "VLE fluid 3 as defined in SIM")); - -protected - outer TIL.SystemInformationManager sim "System Information Manager"; - TIL.Internals.SimPort simPort; - - /************************** Connectors *********************************/ - -public - TIL.Connectors.GasPort gasPortA(final gasType=gasType) annotation (Placement(transformation(extent={{-128, - -10},{-108,10}}), iconTransformation(extent={{-128,-10},{-108,10}}))); - TIL.Connectors.GasPort gasPortB(final gasType=gasType) annotation (Placement(transformation(extent={{112,-10}, - {132,10}}), iconTransformation(extent={{112,-10},{132,10}}))); - - TIL.Connectors.HeatPort[nCells] heatPort annotation (Placement(transformation(extent={{-10,130}, - {10,150}}), iconTransformation(extent={{-10,130},{10,150}}))); - - /************************** Gas inlet/outlet ****************************/ - - TILMedia.Gas_ph gasA( - final gasType=gasType, - final p=gasPortA.p, - final h=noEvent(actualStream(gasPortA.h_outflow)), - each final xi=noEvent(actualStream(gasPortA.xi_outflow))) - annotation (Placement(transformation(extent={{-60,60},{-40,80}}))); - - TILMedia.Gas_ph gasB( - final gasType=gasType, - final p=gasPortB.p, - final h=noEvent(actualStream(gasPortB.h_outflow)), - each final xi=noEvent(actualStream(gasPortB.xi_outflow))) - annotation (Placement(transformation(extent={{40,60},{60,80}}))); - - /***********************Geometry characteristics******************************/ - - inner parameter Integer nCells(min=1) = 1 - "Number of cells in adsorber for discretization" annotation (Dialog(group="Discretization")); - - inner replaceable parameter Geometry.GeneralAdsorberGeometry adsorberGeometry - constrainedby Geometry.GeneralAdsorberGeometry "Adsorber geometry" - annotation (Dialog(group="Adsorber geometry"), - choicesAllMatching=true, Placement(transformation(extent={{58,-138},{78, - -118}}))); - - - /*************************** Components *********************************/ - - /************************** Gas volume **********************************/ - - Cells.Gas.Gas[nCells] gas( - each final cellGeometry( - length=adsorberGeometry.length/nCells, - hydraulicDiameter=adsorberGeometry.particleDiameter, - flowCrossSection=adsorberGeometry.innerCrossSection, - psi=adsorberGeometry.psi), - each final gasType=gasType, - each final vleFluidType=vleFluidType, - each final generateEventsAtFlowReversal=generateEventsAtFlowReversal, - each final computeTransportProperties=computeTransportProperties, - each final HydraulicMassFlowPosition=HydraulicMassFlowPosition, - each final TInitial=TInitialGas, - each final xiInitial=xiInitial, - each final pInitial=pInitial, - each final m_flowStart=m_flowStart, - redeclare each final model PressureDropModel = PressureDropModel, - final fixedInitialPressure=cat(1, {fixedInitialPressure_firstCell}, {fixedInitialPressure for i in 2:nCells})) - annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); - - replaceable model PressureDropModel = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.Partial.PartialPressureDrop - constrainedby - SorpLib.Components.Cells.Gas.PressureDropCorrelations.Partial.PartialPressureDrop - "Pressure drop model for gas cell" annotation (Dialog(group="Pressure drop model"),choices(choice(redeclare - model PressureDropModel = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.ZeroPressureDrop), - choice(redeclare model PressureDropModel = - SorpLib.Components.Cells.Gas.PressureDropCorrelations.ConstantResistanceCoefficient), - choice(redeclare model PressureDropModel = - SorpLib.Components.OpenAdsorber.PressureDropCorrelations.PackedBed_Kast1988 - "Pressure drop in packed bed according to Kast (1988)"))); - - /************************** Adsorbent volume **********************************/ - - SorpLib.Components.Cells.Adsorbent.Adsorbent[nCells] adsorbent( - each final vleFluidType=vleFluidType, - each final massAdsorbent=adsorberGeometry.massAdsorbent/nCells, - each final generateEventsAtFlowReversal=generateEventsAtFlowReversal, - each final TInitial=TInitialAdsorbent, - each final xInitial=xInitial, - each final initial_x=true, - redeclare each final model AdsorbentAdsorbateModel=AdsorbentAdsorbate) - annotation (Placement(transformation(extent={{-10,-120},{10,-100}}))); - - replaceable model AdsorbentAdsorbate = - SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater - constrainedby - SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater - "Adsorbent adsorbate model" annotation (Dialog(group="Adsorbent model"),choicesAllMatching=true); - - /************************** Wall volume **********************************/ - - Cells.Wall.Wall[nCells] wall( - each final volume=adsorberGeometry.wallVolume/nCells, - each final TInitial=TInitialWall, - redeclare each final model WallMaterial=WallMaterial) - annotation (Placement(transformation(extent={{-8,76},{8,84}}))); - - replaceable model WallMaterial = TILMedia.SolidTypes.BaseSolid constrainedby - TILMedia.SolidTypes.BaseSolid "Wall material model" - annotation (Dialog(group="Wall material"),choicesAllMatching=true); - - /*********************** Heat and mass transfer models ****************************/ - - HeatAndMassTransfer.HeatTransfer[ nCells] heatTransfer_gasWall( - each final n=1, - each final useAlphaAInput=false, - redeclare each final model HeatTransfer = HeatTransfer_gasWall, - final properties_gas=gas.properties, - final mdotHydraulic_gas=gas.mdotHydraulic) annotation ( - Placement(transformation( - extent={{-8,-4},{8,4}}, - rotation=90, - origin={0,44}))); - - replaceable model HeatTransfer_gasWall = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - constrainedby - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - "Heat Transfer Model between gas and wall" annotation(Dialog(group="Heat transfer"), choices(choice(redeclare - model HeatTransfer_gasWall = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlpha), - choice(redeclare model HeatTransfer_gasWall = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA), - choice(redeclare model HeatTransfer_gasWall = - SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.HeatTransfer.PackedBedWall_Kast1988 - "Heat transfer between packed bed and wall according to Kast (1988)"))); - - HeatAndMassTransfer.HeatTransfer[nCells] heatTransfer_gasAdsorbent( - each final n=1, - each final useAlphaAInput=false, - redeclare each final model HeatTransfer = HeatTransfer_gasAdsorbent, - final properties_gas=gas.properties, - final mdotHydraulic_gas=gas.mdotHydraulic) annotation ( - Placement(transformation( - extent={{8,-4},{-8,4}}, - rotation=90, - origin={40,-56}))); - - replaceable model HeatTransfer_gasAdsorbent = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - constrainedby - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.Partial.PartialHeatTransfer - "Heat Transfer Model between gas and adsorbent" - annotation(Dialog(group="Heat transfer"), choices(choice(redeclare model - HeatTransfer_gasAdsorbent = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlpha), - choice(redeclare model HeatTransfer_gasAdsorbent = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA), - choice(redeclare model HeatTransfer_gasAdsorbent = - SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.HeatTransfer.PackedBedGas_Kast1988 - "Heat transfer between packed bed and gas according to Kast (1988)"), - choice(redeclare model HeatTransfer_gasAdsorbent = - SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.HeatTransfer.PackedBedGas_HougenMarshall1947 - "Heat transfer between packed bed and gas according to Hougen and Marshall (1947)"))); - - HeatAndMassTransfer.MassTransferDiffusion[ nCells] massTransferDiffusion( - each final vleFluidType=vleFluidType, - each final isClosable=false, - each final isFlap=false, - each final inputChoice=inputChoice, - redeclare each final model AdsorbentAdsorbate = AdsorbentAdsorbate, - redeclare each final model MassTransfer_diffusion_dp = - MassTransfer_diffusion_dp, - redeclare each final model MassTransfer_diffusion_dx = - MassTransfer_diffusion_dx, - final properties_gas=gas.properties, - final mdotHydraulic_gas=gas.mdotHydraulic) annotation (Placement(transformation( - extent={{-10,-6},{10,6}}, - rotation=-90, - origin={-40,-56}))); - - replaceable model MassTransfer_diffusion_dp = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantCoefficient_dp - constrainedby - SorpLib.Components.MassTransfer.MassTransferPhenomena.Partial.PartialMassTransfer_dp - "Mass Transfer Model" annotation (Placement(transformation(extent={{-32,-70}, - {-12,-50}})), Dialog(enable=inputChoice == "dp", group="Diffusion"), - choices(choice(redeclare model MassTransfer_diffusion_dp = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantCoefficient_dp), - choice(redeclare model MassTransfer_diffusion_dp = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantSpecificCoefficient_dp), - choice(redeclare model MassTransfer_diffusion_dp = - SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.MassTransfer.PackedBedGas_Kast1988 - "Mass transfer between packed bed and gas according to Kast (1988)"), - choice(redeclare model MassTransfer_diffusion_dp = - SorpLib.Components.OpenAdsorber.HeatAndMassTransfer.TransportPhenomena.MassTransfer.PackedBedGas_HougenMarshall1947 - "Mass transfer between packed bed and gas according to Hougen and Marshall (1947)"))); - - final model MassTransfer_diffusion_dx = - SorpLib.Components.MassTransfer.MassTransferPhenomena.ConstantCoefficient_dx - "Mass Transfer Model" annotation (Placement(transformation(extent={{-32,-70}, - {-12,-50}})), choicesAllMatching=true, - Dialog(enable=inputChoice == "dx", group="Diffusion")); - - /********************* General Parameters ************************************/ - - final parameter Boolean computeTransportProperties=heatTransfer_gasWall[1].computeTransportProperties or heatTransfer_gasAdsorbent[1].computeTransportProperties or massTransferDiffusion[1].computeTransportProperties; - - parameter Boolean generateEventsAtFlowReversal=false "If true, events are generated at flow reversal" annotation(Evaluate=true, Dialog(tab="Advanced", group="Event-Handling")); - - parameter String HydraulicMassFlowPosition="gas port B" "Position of hydraulic mass flow of gas cell" annotation(Evaluate=true, Dialog(tab="Advanced", group="Hydraulic mass flow position"), - choices( - choice="gas port A" "hydraulic mass flow at gas port A", - choice="gas port B" "hydraulic mass flow at gas port B")); - - final parameter String inputChoice="dp" "Driving force of diffusion"; - - final inner parameter Modelica.SIunits.MolarMass M_adsorbent=TILMedia.GasFunctions.molarMass_n(gasType,0) "Molar mass of adsorbate"; - - final inner parameter Modelica.SIunits.MolarMass M_carrier=TILMedia.GasFunctions.molarMass_n(gasType,1) "Molar mass of carrier gas"; - - /******************** Initialization ********************/ - - parameter Modelica.SIunits.Temperature TInitialGas - "Initial temperature of gas" annotation (Dialog(group="Gas volume", tab="Initialization")); - parameter Modelica.SIunits.MassFraction[gasType.nc - 1] xiInitial=gasType.defaultMixingRatio[1:end - 1]/sum(gasType.defaultMixingRatio) - "Initial composition of gas" annotation (Dialog(group="Gas volume", tab="Initialization")); - parameter Modelica.SIunits.Pressure pInitial - "Initial pressure in gas cell" annotation (Dialog(group="Gas volume", tab="Initialization")); - parameter Boolean fixedInitialPressure=true - "If true, initial pressure is fixed" annotation (Dialog(group="Gas volume", tab="Initialization")); - parameter Boolean fixedInitialPressure_firstCell=true - "Use false, if two pressure boundaries are connected" annotation (Dialog(group="Gas volume", tab="Initialization")); - parameter Modelica.SIunits.MassFlowRate m_flowStart=0.2 - "Start mass flow rate for iteration" annotation (Dialog(group="Gas volume", tab="Initialization")); - parameter Modelica.SIunits.Temperature TInitialAdsorbent - "Initial temperature of adsorbent" annotation (Dialog(group="Adsorbent volume", tab="Initialization")); - parameter Real xInitial(unit="kg/kg",start=0.2) "Initial loading of adsorbent" annotation (Dialog(group="Adsorbent volume", tab="Initialization")); - - parameter Modelica.SIunits.Temperature TInitialWall "Initial Temperature of wall" annotation (Dialog(group="Wall volume", tab="Initialization")); - - /************************** Summary ************************************/ - - inner parameter Boolean includeSummaryArrays=true - "include array entries in summary" - annotation (Dialog(tab="Advanced", group="Summary")); - inner parameter Boolean includeDefaultSummary=true - "include default entries in summary" - annotation (Dialog(tab="Advanced", group="Summary")); - -protected - record Summary - extends TIL.Internals.ClassTypes.Record; - - Modelica.SIunits.MassFlowRate m_flow_A if include; - Modelica.SIunits.MassFlowRate m_flow_B if include; - - Modelica.SIunits.HeatFlowRate Q_flow_gasWall if include; - Modelica.SIunits.HeatFlowRate Q_flow_gasSorbent if include; - Modelica.SIunits.HeatFlowRate Q_flow_wallAmbient if include; - - Modelica.SIunits.Temperature T_A if include; - Modelica.SIunits.Temperature T_B if include; - Modelica.SIunits.Pressure p_A if include; - Modelica.SIunits.Pressure p_B if include; - Modelica.SIunits.Pressure delta_p if include; - Modelica.SIunits.MassFraction xi_A[gasType.nc-1] if include; - Modelica.SIunits.MassFraction xi_B[gasType.nc-1] if include; - TILMedia.Internals.Units.RelativeHumidity phi_A if include; - TILMedia.Internals.Units.RelativeHumidity phi_B if include; - Modelica.SIunits.MassFlowRate m_flow_ads if include; - Modelica.SIunits.Mass m_adsorbent if include; - Modelica.SIunits.Mass m_adsorbate if include; - Real x_avg if include; - - protected - outer parameter Boolean includeDefaultSummary; - parameter Boolean include=includeDefaultSummary; - outer parameter TILMedia.GasTypes.BaseGas gasType; - - public - replaceable Arrays arrays; - - protected - record Arrays - parameter Integer n if includeCross; - - Modelica.SIunits.Temperature[n] T_gas if includeCross; - Modelica.SIunits.Temperature[n] T_sorbent if includeCross; - Modelica.SIunits.Temperature[n] T_wall if includeCross; - Modelica.SIunits.Pressure[n] p_gas if includeCross; - Modelica.SIunits.Pressure[n] delta_p if includeCross; - Modelica.SIunits.Pressure[n] p_sorbent if includeCross; - Modelica.SIunits.MassFraction[n,gasType.nc-1] xi if includeCross; - TILMedia.Internals.Units.RelativeHumidity[n] phi if includeCross; - Modelica.SIunits.Mass[n] m_adsorbent if includeCross; - Modelica.SIunits.Mass[n] m_adsorbate if includeCross; - Real[n] x if includeCross; - - protected - outer parameter Boolean includeSummaryArrays; - parameter Boolean includeCross = includeSummaryArrays; - outer parameter TILMedia.GasTypes.BaseGas gasType; - end Arrays; - - end Summary; - - replaceable record SummaryClass = Summary; - -public - SummaryClass summary( - m_flow_A=gasPortA.m_flow, - m_flow_B=gasPortB.m_flow, - Q_flow_gasWall=-sum(gas.heatPortB.Q_flow), - Q_flow_gasSorbent=-sum(gas.heatPortA.Q_flow), - Q_flow_wallAmbient=-sum(wall.heatPortB.Q_flow), - T_A=gasA.T, - T_B=gasB.T, - p_A=gasPortA.p, - p_B=gasPortB.p, - delta_p=gasPortA.p-gasPortB.p, - xi_A=gasA.xi, - xi_B=gasB.xi, - phi_A=gasA.phi, - phi_B=gasB.phi, - m_flow_ads=-sum(gas.vlePort.m_flow), - m_adsorbent=adsorberGeometry.massAdsorbent, - m_adsorbate=sum(adsorbent.massVLEFluid), - x_avg=sum(adsorbent.x)/nCells, - arrays(n=nCells, - T_gas=gas.properties.T, - T_sorbent=adsorbent.T, - T_wall=wall.T, - p_gas=gas.properties.p, - delta_p=gas.gasPortA.p-gas.gasPortB.p, - p_sorbent=adsorbent.p, - xi=gas.gas.xi, - phi=gas.gas.phi, - m_adsorbent=adsorbent.massAdsorbent, - m_adsorbate=adsorbent.massVLEFluid, - x=adsorbent.x)); -equation - - connect(wall.heatPortB, heatPort) annotation (Line( - points={{0,83.8},{0,140}}, - color={204,0,0}, - thickness=0.5)); - connect(wall.heatPortA, heatTransfer_gasWall.heatPortB[1]) annotation (Line( - points={{0,76},{0,52}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransfer_gasWall.heatPortA, gas.heatPortB) annotation (Line( - points={{0,36},{0,10}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransfer_gasAdsorbent.heatPortA, gas.heatPortA) annotation (Line( - points={{40,-48},{40,-20},{0,-20},{0,-10}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransfer_gasAdsorbent.heatPortB[1], adsorbent.heatPortB) - annotation (Line( - points={{40,-64},{40,-90},{0,-90},{0,-104}}, - color={204,0,0}, - thickness=0.5)); - connect(gas.vlePort, massTransferDiffusion.vlePortA) annotation (Line( - points={{-6,-10},{-6,-20},{-40,-20},{-40,-46.9}}, - color={153,204,0}, - thickness=0.5)); - connect(massTransferDiffusion.vlePortB, adsorbent.vlePortA) annotation (Line( - points={{-40,-65.2},{-40,-90},{-7.2,-90},{-7.2,-110}}, - color={153,204,0}, - thickness=0.5)); - - connect(gasPortA, gas[1].gasPortA) annotation (Line( - points={{-118,0},{-10,0}}, - color={255,153,0}, - thickness=0.5)); - - for i in 1:(nCells-1) loop - connect(gas[i].gasPortB, gas[i+1].gasPortA); - end for; - - connect(gas[nCells].gasPortB, gasPortB) annotation (Line( - points={{9.8,0},{122,0}}, - color={255,153,0}, - thickness=0.5)); - annotation ( - Icon(coordinateSystem(preserveAspectRatio=false,extent={{-120,-140},{120, - 140}}), - graphics={Bitmap(extent={{-246,-140},{232,142}}, fileName= - "modelica://SorpLib/Resources/Images/OpenAdsorber.png")}), - Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-120,-140},{ - 120,140}})), - Dialog(tab="SIM", group="SIM"), - Line( - points={{-40,0},{-4,0}}, - color={255,153,0}, - pattern=LinePattern.None, - thickness=0.5, - smooth=Smooth.None), - Line( - points={{4,0},{40,0}}, - color={255,153,0}, - pattern=LinePattern.None, - thickness=0.5, - smooth=Smooth.None), - Documentation(info="<html> - <p> - This model represents an packed bed open adsorption system, which can be used for desiccant applications. The model consists of a gas cell, an adsorbent cell and a wall cell connected by heat and mass transfer resistances. Some transfer correlation are implemented from literature. The model can be descretized in flow direction to build up a finite volume model. - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end OpenAdsorber; diff --git a/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/PackedBed_Kast1988.mo b/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/PackedBed_Kast1988.mo deleted file mode 100644 index 13c4b5d27b38421264274387354bc2ede4eca96d..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/PackedBed_Kast1988.mo +++ /dev/null @@ -1,52 +0,0 @@ -within SorpLib.Components.OpenAdsorber.PressureDropCorrelations; -model PackedBed_Kast1988 - "Pressure drop correlation for packed beds according to Kast (1988)" - extends - SorpLib.Components.Cells.Gas.PressureDropCorrelations.Partial.PartialPressureDrop( - final computeTransportProperties=true); - - outer parameter Cells.Gas.Geometry.CellGeometry cellGeometry "cell geometry"; - - outer TILMedia.Internals.PropertyRecord properties; - outer Modelica.SIunits.MassFlowRate mdotHydraulic - "Hydraulic mass flow rate"; - - Real zeta(final unit="1") "Pressure drop coefficient"; - Modelica.SIunits.ReynoldsNumber Re "Reynolds number"; - -equation - Re=noEvent(abs(mdotHydraulic))*cellGeometry.hydraulicDiameter/(cellGeometry.flowCrossSection*properties.transp.eta*cellGeometry.psi); - - zeta=2.2*(64/(Re+1)+1.8/(Re+1)^0.1); - - pressureDrop=(cellGeometry.length/cellGeometry.hydraulicDiameter)/(2*properties.d*cellGeometry.flowCrossSection^2*cellGeometry.psi^2)*zeta*TIL.Utilities.Numerics.squareFunction(mdotHydraulic); - - annotation (Documentation(info="<html> -<p> - This model calculates the pressure drop for packed beds according to Kast (1988). The sign of the pressure drop is automatically determined by the sign of the hydraulic mass flow rate. The hydraulic mass flow rate, the fluid properties record, the adsorber geometry and discretization number are defined as outer objects and thus taken from the overlying model level. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> <i><code>Δ</code>p</i> = sgn(<i><code>ṁ</code></i><sub>hydraulic</sub>) <i>L</i> / <i>D</i> <i>f</i> / (2 <i><code>ρ</code></i> <i>A</i><sup>2</sup> <i><code>ψ</code></i><sup>2</sup>) <i><code>ṁ</code></i><sub>hydraulic</sub><sup>2</sup> </p> -<p>where <i><code>Δ</code>p</i> is the pressure drop, <i><code>ṁ</code></i><sub>hydraulic</sub> is the hydraulic mass flow rate, <i>L</i> is the hydraulic length, <i>D</i> is the hydraulic diameter, <i>f</i> is the resistance coefficient, <i><code>ρ</code></i> is the fluid density, <i>A</i> is the cross sectional area and <i><code>ψ</code></i> is the void percentage of packed bed. </p> -The resistance coefficient <i>f</i> is calculated by -<p align=\"center\"> <i>f</i> = 2.2 (64/Re + 1.8/Re<sup>0.1</sup>)</p> -where Re is the Reynolds number. -</p> - -<h4>References</h4> -<ul> -<li>Adsorption aus der Gasphase, Werner Kast, Darmstadt, 1988. </li> -</ul> - -<h4>Author Information</h4> -<p> - <ul> - <li> - December 11, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end PackedBed_Kast1988; diff --git a/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/Partial/PartialPressureDrop.mo b/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/Partial/PartialPressureDrop.mo deleted file mode 100644 index 0bd4baf0397ae28190a135a3565987730299fefb..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/Partial/PartialPressureDrop.mo +++ /dev/null @@ -1,29 +0,0 @@ -within SorpLib.Components.OpenAdsorber.PressureDropCorrelations.Partial; -partial model PartialPressureDrop - - Modelica.SIunits.Pressure pressureDrop; - - parameter Boolean computeTransportProperties; - - annotation (Icon(graphics={Bitmap(extent={{-100,-100},{100,100}}, - imageSource= - "iVBORw0KGgoAAAANSUhEUgAAAdwAAAHdCAYAAAC3/8hQAAAAAXNSR0ICQMB9xQAAAAlwSFlzAAAXEgAAFxIBZ5/SUgAAABl0RVh0U29mdHdhcmUATWljcm9zb2Z0IE9mZmljZX/tNXEAAD/ESURBVHja7Z1viFzl2f8XKRJEZBGRICKLiAQRWUQkiJS8KnnxvEiyWZoULAs+ilaQCPIYJC9iELLIMjsHxZAG3CqEYGuJrTwsSGsIfXxCEUyxhNQ+QiyWLrU0+YlIbGnZ335ndpIzZ86ZOTNz7jPXfd+fGz4IG3d39vz7nuu6r+t7Tb300ktTAFAPU/PJ1qn5xo5r7F0+3MNccnRqb/PM2Mw3T/f87PnGwrXfvX9phnMCUOP9z0EAGFdEF6dbAjbX2NUWtuRYl/DNNa9u/HfdNHPNtWufd09yalP4D7b+rt3Jds4zAIILMAFBbS5vCul580JarShf7Yqc5xsH2tHy0izXCQCCCzCkuC7NTs0n+zaF9cxm5BePqI7HxetinOzciIy3cU0BILhA1LoZtSYHN0R1ZUMoztUhSrc8/fb69DPvtNj6wvvrM0fOdbGtcWF99vgXlXD/q5/1/Hz9zs7vv/mJk3UJ8ZnWMe6kqDeOPdcgILgAoV7oG9HWxgP/qfaDv3mpSkH5zg+OtQTstufea4naPYsfXxO9h1a+XN/x7rp5vvvzf3WJdUegO+LsID19qbVXrLQ0e8SA4AL4HMFuRq97m6sbXKkqMpUI3f3yRy1RevDEmhdiWrUoP/D6563jcOehs1VHymeupaOJggHBBTB4ET95fEvrIX29nWbsaPWuwx+20ru+RKgW0AuIjlknMr7xsRPj7wm30v1qZUq2cq0DggswiQtXKWKlI9sR7EgP9Jsef+taGliR2yOnvkE4K+bRn37bOrbKCnT2j8dIQ59vvVSRggYEF8DhhdoqclL1cHJslD3YG77/2rWUsARA6VEEcbLRsPa69cIzYiR8ZXMPmOgXEFyA8UV2abZd2Tp8BbGiV0VU977yCWlhD3j4zcutdPQdL37QOncjR7/0BAOCCzBEqlgPziGjWD2kVcSjgh6lMREx/1PROpfaSx+6KKt97SwjvoDgAmQvwv1LM5sVxReHSRErHakIdvvJrxCpwNH+uiLg259fbRW2Ib6A4AKUThcnWzf7Ys+PEsUiQuwBqxBL7VqILyC4AD0iuzjdEtkhWneIYqFM+vm+5qetPfvS0a/Et13xjP0kILgQktDKhKLl8HS1rMgqfcheLIyCLC2HEl8V5ana+cnjW7hfAcEFX1PGB8sWP6llR5EsvbBQFWr9UuSrfV/t+ZdqNVLbGVEvILjgidDuK2tGgchCneKrrImyJ0S9gOCCvxeRWnnahhRrZQqfEFmY9J6vxLdkwRVRLyC4YCGabewoE80qnac9tdjM/sE+MtyQ2UZJt6szU3ONXdz7gOBCnUK7UKadpxPNUvwEPqD93luffbdshfNTpJsBwQU3F0prIk/jwKAiKFWGEs2Cz6gFTT2+WxbeKJFubo0TxMsZEFyoIppNtrYeKgNmysp+T/tiDAWAkJDJysBCK7W7qe2NfV5AcGGkC6Nltzi4d1YpOJyfIIaoV5mbEu1Fq6pt4BkCCC6Ui2gltAP2sfTwUcEJD2OICVXXa6BCCVONM1hIAoILfVLHzeV+Ea0eMnrY0NIDsaOtE83zHbjPO988jfACggulhVYPFT1c2J8F6EW1CwNHCO5JTmmbhmcOggtRCu3i9KBiKAmtHiY8VAEGIw/ngcKr7RqEF8EFhBahBahBeNvZpGXaiRBcCPlkt+fPFtovym0HoQWoU3g3Xn4x0EBwIaCTvDvZ3s8ZSkLLHi2Auz3evsVVLecqLCMRXPA8fZxsbRVrILQA9oWXViIEFzw8qbJhVKqqoPJY7T2yrkNoAepH/uL9hyUkx1RrwbMMwQXz+7SNXf32aWVYQR8twGTRQA/1tPdxrroi73KeaQgumEwfL822UlIFQqvZnwwUALCF3NoGTCi6ODWf7OQZh+CClfTxXHK03z6txo7xcAOwi/zINc6yb/8uaWYEFyYZ1SY7W2/ABUPfZ46cY58WwCNUxNjHp1lp5gWefQgu1Cq0i9P9BgxonBj7tAD+7u/eeejsgIlEmGYguFCD2DYWioqilJJiVB5AGDy08mWr9qJ4Bm9ykGciggtu0sdbW2+2BW+9qngkfQwQHmrhK6xmnm+eY/A9ggtVnqSNN9minlqqjwHCR1tEfauZVTiJRSSCC2NGtXqDLSiK0psvDyOAeJBbVR/TjItEuwgujBTVNnYVTfTRm+72k1/xAAKIEBVVycCmcG8XwwwEF0qekFZfbX4FstoFmOYDAEIFkn28malkRnCh78nQVJ+CvlpFtXqz5UEDAB1UKHnHix/06dvFpQrBhdKFUdqrVTM8DxcA6BftFhtmJMcoqEJw4aX+7T7qq1UvHg8UABjEgErmi4z+Q3BjF9udRYVRShPRVwsAw1LYt0tBFYIb7YHXvNqCwqj7X/2MBwcAjIwyY4XDEPYkpxiEgOBGEtUuTheN0Zt+5h08kAGgEgYUVNGzi+AGfrBVhTzXvJR3A2BiAQAu6FNQdUX9/jybEdzwDvRc8lReFbJcY2aPf8GDAQCcIaOcm584WWgLyTMawQ3jAMvIQmX5BT7IpJABoK4Uc6FDlba52NdFcL0+uPuXZjai2vNUIQOAFe595ZOiKuZLtA4huJ4WRzV25LX86EK/r/kpNz4ATAxNGMsdgtBuHVrgGY7g+rVfmxPVyvcUIwsAsIC2s4oH3LOvi+D6IbZH8y7g2557Dy9kADDHnYfOFk0eWsESEsG1WxylhvKcC3fmyDlubAAwi7a5cvd1KaZCcO3t1y5O5w2KZ78WAHxB+7oF/boXVQDKsx7BtVGJnDNSTxcu/bUA4BPq182dsTvXXKOCGcGd7MFrz6+9klcc9fCbl7mBAcA7VGuSW0ylCmacqRDcyRRHNXblOUfJzQUzCwDwGXkEqNCzoIL5KTQAwa1xz7axkHchahYlZhYAEAqFFcx7lw+jBQhuDZFtfo+tnKO4QQEgNO5Z/LjIDnIZTUBw3R2sghm2TPoBgJDRjO4CO8gVtAHBrU1stzUucEMCQPAUtg0hugiua7GlxxYAYkPWtAW9uqu4UiG4FezZNlfyxFZDnbkBAQDRRXQRXMQWAMAJ8hnINciQ6GIFieBWIbZ6q0NsAQD6ulKdR3QR3LHFltF6AACILoKL2AIATER05bCXO2mIPV0Et7gaOTmWvWhufOwEYgsA0Af5LxeILoVUCG651h8iWwAARBfBRWwBAEyhwS0Fe7qYYyC4rUEEBxBbAIBq6FNIFb3oxi62C/TZAgDUJLp7k2MILmKL2AIAVEixI1W8o/0iFdtkJ2ILADAh0Z1LDiK4UYjt0uzUXPNq9gJgEAEAgBvRzR3tN5/sQ3BD/mP3L81siO0aI/YAAOpD2cMe0VXgM9/YgeAGGdkuTrfsxjJie8/ix9wQAACO0RD7nB7dKwqEENyQ/sgnj29pNV9nTvYdL37AjQAAUBMKcHLahS7F4rsch+DmWDbe+uy73AAAADVz56GzOfu5zXMxuFGFL7ZzycHsyZX92Hd//i8ufgCACXDbc+/lie5pBNfv9p992ZOqZmzZj3HRAwBMBgU8tzz9dt6e7jKC6+MftjvZnm3/UT/Yw29e5oIHAJgwGnaQ60Y13ziA4PoV2W7Ntv9gbAEAYAtZQOYaYwTaLhRmRbI24Om1BQAwz4Mn1vJ6dNcUOCG45iuSm8tZsb3r8Idc2AAARsnt0Q2wcjmwVHLvQILpZ97hggYAMI4Co9CLqAIS216PZG3Ia2OeixkAwD4KkEL2XA5EbFu2jZeyRVLaG+AiBgDwA7Vs9lQuK5DanWxDcO3s265SJAUA4D8FRVRB2D8GILbLh/FIBgAIh3tf+SRIJyq/P/xcY1f2pMi9BNtGAAC/2frC+8ENrvfb3EKjnTJOUmqk5mIFAPAbBU7yve8R3d3JdgS3/n3bM9kTMXv8Cy5UAIBAyHWi0n6up/25vvbbHsiK7cyRc1ygAACBkWuKMddcQXDr+MC7k23Zflvt23JhAgCEiQphQ+jP9evDyid5rnmefVsAgHjQfu5Nj7+VFd0rvvkte1aVnByl3xYAID5y+3P3Ns8guG72bXdkxfb251e5EAEAIkG1Oj7Pz/XWuhGfZACA+OjxW1ZNz/zSLIJbWSq5uUILEAAAFAytv+hDq5APBhf7aAECAIAOqt3JcaE6iuCOn0pew7oRAADSqIandz/XdmrZuJtUciw7cu/hNy9zsQEARI5qeG587ER2P/e85dSyV1XJd7/8ERcaAAC0yHehsjvgwK7BhTbBUwdRJtZcYAAAkKYntayq5f1LMwjuiAYXSiU/tPIlFxcAAHTxyKlv8qqWTRpiGEwlL81mvZLvOvwhFxYAAOSSW7U831hAcAcKbvNc+qDJP5OqZAAA6EeOIcaaNa9la4VSBzC4AACAYZEhRo/X8p7kFIKb90H2L81kU8kaycSFBAAAZbhn8eO8MX47EdzeVPLp9EFSfxVeyQAAMAwyR7Jq+2jFvnFn9q1E/VVcPAAAMAzqaOlJLRuZKGRlOEHXUPnbnnuPCwcAAEbizkNnTQ6rN1coRc8tAACMgzpbemwf9zaXoxbcvOEEejPhggEAgHG495VPzA03mPBwguZytlBKriFcLAAAMC6yBM6I7mqUgpvnKKWSbi4SAACoAvk49A43aOyKUHC724BwlAIAgKpREa6VNqEJVSU3dtEGBAAArtE2pZU2ocmM3su0Ad367LtcGAAA4AQNwLHQJmTCL5k2IAAAcIWVNqFJRLe0AQEAQK30jPBT0W7NUe7ETS5oAwIAgDrIaRNaDlJwiW4BAGCSqDi3J8rdnWwLT3CJbgEAwFqUO988HZTgKk/eqgojugUAAEtRbo2WjxOxcCS6BQCA2KLceqJbLBwBACDyKHciAwqwcAQAgNiiXKJbAACIjtzBBo6jXKJbAACIkp7BBo6jXKJbAACIEtkK1xnl1tZ3S3QLAADW0PCcLsHdk5zySnDzXKVmjpzj5AIAgCly3acceSy7Sifvo+8WAAB8oC6PZUcD5rvn3eIqBQAAVlF9UU+U++TxLeYFd2q+sSO7Cf3wm5c5qQAAYJLcebnzjQMeCG7zdPpDq+yaEwoAAJa56/CH2Sh3reoot1qx3Z1sy0a3KrvmZAIAgGVUZ6R6o27RbeyyK7gZowttRHMiAQDAB7a+8H42yj1vUnDzjC5Ubs1JBAAAH8g3wkh2GhTcbqOLmx5/ixMIAABe0WOEUaHdo7NWIGwcAQDAN1waYVRVLLU9a3Tx6E+/5eQBAIB3uGoRqiq6XUl/uNufX+Wkwfq+99fXf/IHO/z4AucEAAYjK+LMXu5FE4I7Nb84nS2W0pxBThr87LN1c+tHZzkvANAftQj1FE/tTrYbEFyKpaCX7/1yff3v39oT3JN/5NwAwGB6ZuXONVcmL7iZYqm7X/6IkwXrRz6yJ7Zaa99wbgBgMLnFU2M6T1VeLMVUIBDn/2ZTcEkrA0BZeoqn5pKnJie4mWIpfJNB/OcZu2JLWhkAytJTPDWm81SlxVI4S4GwWCxFWhkAhiW3eGp+abZ+wd0IrdMfQqE3JwhULPX1P20LLmllAChLT/HUGMPpxxlUcCb9IRR6c3Jg8WP7YktaGQDKklM8tVar4LYGFWTC7O0nv+LkwPqFy34ILmllAChLjvPUjvoEN5NOvuXptzkpYL5YirQyAIzCHS9+kEkrJ8fqE9xMOpneWxDWi6VIKwPAKMg9MZtWHqUnl3QyVIIvxVKklQFgFHrTysPPySWdDJXgS7FUdv3wV5w7ABhMT1p5BKtH0slQCb4US2WXpghx/gBgED1p5b3NK8OmlUknw9j4ViyVXn/6mvMHAOUYN608Vjp5+pl3OAmw/otL/gouaWUAKMu4aeWx0sn3vvIJJyFyVCz1j3/7LbiklQGgDOOmlcdKJzMZCBq/81tsSSsDwDCMk1YeZtD8AulkyPJ//89/wSWtDABlGSetPITgNk+nf8k9ix9z8CPH52Ip0soAMAoPvP55VnAvVSq4ylG3ctWpX/LQypcc/MjxvViKtDIADMt3f/6v9Ru+/1q36O5OtlUnuPONHekfvmXhDQ585IRQLEVaGQBG4dZn380OMzhQneDOJUfTP3zrC+9z0CMnhGIp0soAMAraUs0UEZ+pUHCb59M//L7mpxz0yAmlWIq0MgAMiwyfMvu4V8u0Bw0W2/1LM9l2oEd/+i0HPWJCKpYirQwAo6Ct1W7RbewaX3BpB4IMIRVLZdePL3B+AWAwdx46m00rL1cguN3tQDNHznGwI+Y//ju8Yqn00hAGzjMADGKU9qCh24EePLHGwY6Y134frth21r73Oc8A0J/c9qD9SzOjC26mHeg7PzjGgY6cEIulSCsDwCjc9tx7Q7UHDdUOdPvzqxzkiPnR2fDFlrQyAJRFA3y6Bbd5enTBzUwH2ta4wEGOmNU/xSG4pJUBoAwPv3m5Z3rQGBFu8yp2jiBCL5YirQwAo6Ct1rL7uH32b5dm2b+FDjEUS5FWBoBhydnHXRhBcBsH0j9EP5SDGy8xFEuRVgaAYbn75Y9Kj+srFtw9yan0D9EP5eDGSSzFUqSVAWBYZo9/kd3HvTi84M41L6V/iH4oBzdOYiqWIq0MAMOgftys/fHU/OJ0acHN+ieruVc/lIMbH3tW4yqWIq0MAMNy8xMnS/kqF0S3jV34J4NwUSzlk4Dr7+c6AIB+lPVVLuq/XU5/s34YBzVONLLOhYj5ss7/jWsAAPqjkbUZA4xzQ0S43fNv73/1Mw5qhBz4n+oF7O/frq9/75d+VT0rrc71AABFlJ2Pmz+wIGN4wfzbOPn1n6sXr5991v7ZP/mDP4Lb+B3XAgD058bHTmT7cXcMFtyM4cVNj7/FwYwQV8VSnQHv+i9pZQAIhTKDDPIGFjyF4QW42GfNttmsfUNaGQDCQLPiuwunkmODBTdTMIXhRZy4KJbKpmZP/pG0MgCEgWqdBhVO5QnuKgVTceOiWErpaQ1AcP17SCsDwCQoMzkor0J5Lf1N+iEczLhwUSwlt6q836WqZdLKABACMonqNzkoUzCVbGVCUNy4KpZSNJv3+3yyjSStDAD9uOXpt/s6TmUFd2f6f9Y3cxDjQob9VS8VRxX9vv/6X9LKABAGd7z4QUZwk4N9BLd7JJ++mYMYFy4qh9VzW/T7ZILhk9UjaWUAKOKexY+7BXdPcqpYcPcmx9L/s76ZgxgPrqLNQSLlYs+YtDIA1E3PqL655vliwc1YOj54Yo2DGBG/+Uv1AvXbvw7+vUc+8kdwy/w9ABAncmXMWjz2E1wsHSPFVbGUxHTQ71a7kC9p5bz2JqgHjUpUFkZbFHo51J66KOoZ7/y7UM+3vjfGc6e/WUWLqs/QsUsfF5nRZNfX/7z+7ypq1PeIQ7/lGixDr8Xj0myP4E7tTral/6ctC29w8CLCRbGUblzt0Zb5/YocfVmLH3O91MF/nml7b+vBX+ULmQZn/OJSceW87+LaeSnRPVV1TYbuaYkw4lvMrc++mxHcZF+v4GYqlPVNHLx4cFEs1RlUUAbtjZJWBomgxLAu20+Jr+/ioZdaZZJcbAkhvsPTMxs3Valc6KFMhXI8uCqWUoRS9jMope3LIq1cLTr3SvlO0gRFAl9m+8MSEjoVHFrYjlFqepj7PWR6KpVTnsppwT2Kh3KcuHgzVuQw7OfI20+yukgrj48mRlkzPlF0XXYbZFLRrNLFii4tLr04xf4y2uOpvLe52iu4e5JT6f9JE+x5KMQRXbh4Q9a0oWE/i4t9ZFeLtPLo/Ois7T17vSyqQMua0Oqe8sEKVZ8x5jTzQytfZgX3Ys4ebvMcLUHx4WIQvAR8FIMIn2bkklYe7eXOFytPRZDaarFw3JRN8clzvLOUObOcLXBFv9agwqEFj5z6hodEBLi4kbWvNOrncTEW0NUirVweFcVZTYP2E91J7ktK8H2aGZ23Ys0E9bYGJVuvCe7Uk8e3pP9REw94SISP0j4u1jiRgYuIm4fJ5JBg+bQ3n10SvLrTy4oKVeEfyiqaFBYyPUMMdifbrwtupgf3psff4mERAS6KpRQxj/OZtL/nyyKtHM7LU7+lPd26zrO2VXzK8iC6+dz+/GpuLy49uJHiqg2n36CCsviURiOtnH9tyawipDVMT/moqCjKp0Eewy5VMMdyD9x1+MPcXlx6cIk+Kl1VpN/UmuHLUpaA6+k62k7wba+2zBq1ELDsC4pPTmvjrFG6F3zk3lc+ye3FpQc3UlwUS1U1L1ZuQz49iGOsxMxDEUzISy+CLlLIvhdGWXlxscQDr3+e24vbqVBeSf+jGnd5gISLq2KpqtKrEjCfoiTfHIqqRlkNnwujhllVVi2rXiHEbMCgFUNW6OE3L+f24m7OwW2eSf+jZvohTOHiolhqmEEFZfClX1NrnDYo35EA+dgjOuqqai9XL2kh79cOWlZ6nF2R04u7lo5wu+bgSp0RpjBxVSxVdbrNpxm5saaVlSmJTTSU/h33uGkfM/alSuzQ75lMhLueFtxLmF6wzzbOUnqsys+pm9Gnh3lsaeWYRWOcwsCQ+mvHXbJyDfke0Yjb7tagxelOSrnrHxCmMJGIuUj/6W3Vl9S3qxVTWtmnKnIXa9RKW5+2SepYoRdQyc+iS1v3L81MtVQ39UVZUiFO4aYALT2ABqEiLJ8eHqGnyGT+EEv7Sr81StEPYpu/Qu7NnX7mnUyE29gx1VLd1BcVBiNOYeLiYenyLVUPeJ9WyGllnQs5LrGGz+ggtsVrXGc6y+S4Te2UreP29BelyohTeGjfycVyXeLvk2NRqGlll2KrFzYdNxmxKKOhIQdKWVtuMxpGJFzv2aqIS/dIGt+W+u5DvG9kIJWJcBd6bB1ve+49BCpAXBVLuZ576VNxTohpZb2ouRBb/UxlBPodL7UcWe1TLXPsXLi56QVXx21Q4ZbabhRZ+1B4GKrP8syRcz32jlMt1U19cesL7yNQgeGqWEo/07XAuIrMXa2Q0so69lW7ICkdO8xLmlUnpkHbKFWKrV5OFPmPsnWjlxbrwxCq7uG3wj2LH2dag5YPT7VUN/VFqTIiFRauiqXqKnjwae8wlLSyC7FVqniUB6vExtrqF2FWJbY6/lVkkHTMrRe7hVj/sK1xIWt+sYKPcgS4utkUfdTx+X0a8xbC23rVYqtjMo5waA/ZWmq0SHCrMGzR36prvsrrSMfQcqQbot2jHBu793Cbp3t8lKXKiFRYaUEXS0Utdf0NEnafls+2dVWLrX5WFf7DyhxYF1yZv4z7YqCXY1cD73UfWd3TDXG29IMn1rJuU2cQ3MBxVSWpNF+df4dPE1V8LgKpMv1Y5eB2a8VzeS8q49ZJ1LFFY9npqmq3ukmz/eRXCG5MuCqWmkQ1rk+j33xPK1chuvr+KiMWSyYoOr/Z4zVOnYHup7r2MC0XIdb9El+74M43zzEpKGBcDQCYRATn04xcLd+noYwjuvq+ql84LJ3/7NzncSxI9UJcd2RntYDKxbxhU4KrmQUIbri4aoKfVKO6T2PgQugtHEV09f+7+CyW9vHTI/rGybwoKna1X+tLtiC96qwLQXDBiwdUFePJRsUni7xQeguHEV0Xka3FVGhHcMfJIFW5vx1KWjmbqkdwwRtcFUdMcqSW0rQ+rVCGbJcRXZdiK5R2tbT0945a8auX1klPybFahFhXq2EdaMxtr+BqIzf1RZUyI1j+PyBdpV8n+aDwbUZuSJZ1/URX0ZrraN63Pfx+YjuJNHIWq6MvXVvF1k1GcNd6hs8rDEa0/MZVsZSr/blhsNaP2W+FZlmXJ7oSkDpSoz6NarQutsJq1b8MP4IVXIHghoerYikL9muuXiZcrVDSynmiqyxKXQKirQyfl16+rIitsGiXqRWa4xSCGziuiqXqGFRQBos2f/1WiJNQdB0o01CFg1RZ1DLi87L24mW1HiLbcoXggmlcFUulWyEmjXUj9mxkw3U5Ppbn4w5akyw0rPvFfNwVWmvQQMFVZRU3uL+Rh6tiqTqjGV/TYUUr1AHbdWJ1Lu6gZTVFarU1aJJth0S4MBSuCktUhWrp71SltE8rNAcdxKHc0nQeq0VzCC6CC0bTbjKOJ8U4+lLWgetzdFzNc3a5rBVJZVEthNWF4IJ5lPJ1sayOzfKtapW08uj4NA+5s5Rtsn5cEdxJCO7e5kUE139cFUupGtXi3+vbjFzSyqNj1aShaFnoV/dZcEOai5snuF3Wjg+tfMlN7hnaJ3JVVGK5j1R7ZL4s0sqj49PQCt2Hk7ZtLPvMsLosp+KH4dGffpsV3Ct4KQeAq2Ip6wUMvqUaSSsPj28Fcj6kkoXlQrRQ/JQZXhAorgqIrNusWTO0H7RIKw+PTwVTvqSSrQtuKC+mCG6AuCqW0vIhtWN16kneIq08PK5qE6peKi601KuO4FoV3LnmCoLLAym7fLFY883yj7TycLjyBa96WXJi8z07pM8WjeDe1/yUG90TXBZLWRhUUAbfxraRVh7u+vbBN1uf0YdCKV/um1CKplSAnBHc8z2Cu61xgZvdE1xZHPo0Vs7lS4eLRVq5PC63S6pcPo6Us7w3HorgKlucqVI+g+B6jCwXicLaE3l8WqSVyyGHMx9eoHyceWx5vnDYgrt3+XD6i/dsnAlu9rjf/n3bQ/FtRq6Gf3MND8YHwwuLtqdlsNxSF4rxxQOvf54V3NWNCDc5mP7izJFz3Owe4KpYyNqggrJpZZ9m5IZm0O4K6xXovka3wnL1dyjXr7LFmT3clamp+cZC+ot3vPgBN3vEAuPrG7tv9n+hVGK6wocJQb5VJqexvA0TyjWsbHEmwl3eiHAbu9Jf3PrC+9zwxnFVLOVjtWUHy3tSeYu0sv/bBD7vNVputwrlGla2uFtwlw8rwt2R/uL0M+9wwxvHVbGU1WHZZbA8bixvkVb2N+Xp+70irPqQh1TFf+ehs5mUcvLU1NTuZFv6i7c8/TY3vGFcFkupVcDnY+OLSUJnkVau/6WyqmV5qEcZrLbSyaY2lGtY2eIuwdX27dT+pZn0F7csvMENbxhXxVIhvFn60EaSXqSV87FeBOdjYWEaywMhfM8cpLn12Xezgrtj6qWXXppKf/GG77/GTR/hgyiEh78PhTbpRVo5H+vuYb4WFnawbOvocyFaFm3Pdgnu7mR7R3CvpP+Bmz6+CC6UkVjWU5HZRVq5lx9fsH3OfC0s7OCq6LKKpXMfynWsbHGX4Cqb3BJcmSqn/kGmy9z48YhJSPsmvs3IJa3ci+UWL59G8BVhuSDNFw/3Mtz42IlMSnlxui24881z6X94+M3L3PgRpYF8GZpdBkXqPi3Syr1Y9sYO4V6x/EITku1ppgd3vaW1myllZuIax1WjuvaEfXXLKcKnGblapJWvY3kfXvdKCLaDVluCtELxUf7uz/+VdZlauy64DDAwjW5yV8VSEvLQjpfStD4tH6fNuMKygcmv/+z/8dXLteUVynWsLHF2NF8qwu0eYICfsi1cFkuFOLnGtxm5iji4ztu4anurYoWwv2h55GFIphc9gwvmm6evC27GTxl7R1u4KpYK+UGvm9enFUqVuNVrfdzl04zofliuUA6hIK1Dno9yWnCxdzSKy2KpkErws/g2I5e0sm17zlC2XixXKIfUg9tj6zjfOHBdcHGbilI4fO8n7Ies93xapJVtbwWEUsmvFkCOsXtue+69zB5uY9c1wc26TWF+YeeN31WxVEjpmzx8m5GrFXtamaHo7rF8T2h/OZRr+eYnTmYi3KXZbsHF/MIcLoulfB9UUAZVlfq0Yk8r6yXQ4vLdO7mD9R71kNoTv/ODYz2mF9kIl15cY7jql1NBUWi9t3n4MFM1vWJPK1s1vAjlRcjy/RDStf/oT7/NFkxduaazqQi3qxf33lc+QfQmiMv9rJCKEyaVkne1Yk0rW25XCaV1znLBVAg9zh0eWvkytwc3E+F29+LedfhDhC/QdGhIeyW+pilDj6aGxarhhaLuUI6x5cEeIXVM3P/qZ7k9uN2Cm+nFvf35VYRvQqh62FVkFtKggjJY7jvMW7Gmla22cYUSeVluudIKqaakqAc3K7hdvbi3PP024jchXBZLSYBie3nxbcWYVrbq7xtKq4oEzfIKpQpc3PHiB7k9uBnBTbYyiD7sh08o5uvDYrn3MG/Flla2HH2FYqZvef82lCrwDgpWuwU32dkjuHmD6BnTVz8ui6VCKkwYBusDzbMrtrS/1egrpNGJlvdvQyviLGoJyhPcrtYgbf4igvXislgqxEEFZfBtRm5IkVUZrBpehGLnyP5tfeRMCVrr0tiM4C4zNWhyuCyWin3QueUZoHkrZJ/rLOf/ZvMcsH9bzwppm6unQnlvc7VYcOeSp9L/s/wgEcL6cFksFbuLkWXbwLwVU1rZaq90KO1z7N/Wh4LUogrlXsHdnWxP/883Pf4WQlgjikJdrZhSlHm4nLrEORsdq4YXIfXfWs7uhBYI9AwtmE/2FQvu/OJ0dojBd3/+L8SwBlxOtwl9UIGFFxoXK4a0ssuszjjrN38J4/jqpc3yCq2uREFq3tCCXMHdtHhcS3/DgyfWeFjXgG5wV0seqhzj9fVfXPJLcGNIK1s1vNCLQAjH17Lxi7YSQvJ07/FQnmtenXry+Jb+gjvfPI2ncr24LJZSaiyGQQVlsDxvtWiFnla2mnUIZf/W5Yv8uEvFciFdywpOizyU+0S4ydH0N2lyPQ9rt7jsE1VUxzFuoxcPqxNpilbIaWWrLmB6+Q3lerc8vCM01zsFp12Cuyc5NVhw55N96W+69dl3eVh7/JYf06ACn1OYRSvktLLVdpVQIi/rGR29cIV0PfdYOs4lB0sI7tJs+pvkmsGD2h0ui6VCK7mvAt9m5GqFmla22q5y8o9hHF/LNQuhpZPFzU+cLLR0LBTcPItHzffjYe0Gl3ssoRR+xJRmy1uhppWtelyH4nz092/tXtOhpZNzhs53WToOEtzV9Ddq3BAP6+pxWSylnxtaysaHlxyiAf9ffEJwPiKdXC+zx78YWDDVR3C7h9FvfeF9HtQOcFksFUofoQusDjuP6QFl1YgkFAtUy+5SIb5A9jhMzTVXygtuZjbuloU3eFB7lvLR3jDHOB/rZu55K7QUnFXDi1Amalk2eQlxJvf0M+9kZ+AulBfcJ49vaTXtpn7A9pNf8bCuEJcVmhJyjnF/rBrmxxIVWE3rh7Bfbt3GNMStrp6RfLuTbaUFl1F9fj9wQqmyjDHCiuVBZbWgJ4SCKdLJ9aKi4kzB1JVCXS0W3O59XAwwqsN1w7/mv3Kc+2PdYzZvhZKKs3zsfb93VIxmuTo5pNm3HVRU3J1Obp4eXnDnGrvSP0Q9Rjyoq8HlqLgQ3yBdoT5ln1Yo59ZqL3QIDlOW+8xD3erqmRCUY3gxWHCZHORlOi2Uodm+v/i4WiGkla2mPEMwirFcmxCqL4CKijMFUzuGFtzNyUHn0z9IvUY8qMfDZbFUaNM3XKP0oW8rhLSy1cyC7xXKlq9nPZtC6G/OomLiQROCygvu3uZy+oep14gH9Xi4LJaSTzDHeDh8m5Hre1pZL4RWl+/D0C0XS+mzhfj82Na4UMrwomSEyz5ulbgullI7AMd5OFTR7dvyOa1s2QHJ57nR1oulQh2iIlOozNbr8uiCq33cTD/uI6e+4UE9Ii73DP/0Ncc3NAEoWj6nlV26q8UsCpbb3EJ2vevpv+2zfztQcPP6cRVC86AeDZdvoCHPTfX5vLhYPqeVLftY+1z/oBduqyvEViCRM3C+7/5tScHt7se9/flVHtIj4Hr2J4MKRse3Gbk+F6B8/U+bx9RnD2Wrc4W1Qh4R2uOf3Kf/trzgMh+3En77V3cXNYMKxsPlTGJXy8f2L8tVtD4LruV+8pDrSsr6Jw8luJvtQWu0B42Oa2edUFM2deHjjFy9wPl2nC1PadJsXh+vXe07W10hBwK582/3L81UJbgrtAeNjstKWO0/0ns7PurB9Gn5mFb+xSW7x9PXfXGre+K6PkOtTBaaLTBMO9BwgrsRKtMeNHr05LIoJ9T+trqxbIlXtHxLK1tOffoYjVmObkN/LvW0A80lRysU3F6bR8b1lcN1QQODCqpB0SJpZbfH1/Ly0TTGcnQbehHnMHaOQwtuW3Sb52gPGh6XxVK+7jvFeK5cPdh8SStbL0xTupvotpoVeoviMOP4RhfcTHuQJiTwkO6P62KpUMa1WUHH07flS1rZ+qAI32wdrQ4piKGm5O6XP+oW3D3JqeoFdyNkTv+SG77/GtODBuCyWCpUM/BJ4tp608XyJa1sPXvgk+Ba7rtVJiP058QtT789dDvQ0IK7Wa18Kf2L7mt+yoO6ANfFUgwqcIPS9D4tX168rBpedJYvmQI9V6wO3PAtLT8KudOB5henHQluchTXKRtvobJyU1oJqsU3m0cfxMLyfqNvgmvVi1ovATG0J/akk/c2V4fS0KH+593JdtLKfu+xsMJb1tPKPuyN+1Dooy0Pq5X0sUwqu+nxt0ZOJw8tuKSVy+HjYHOWv0sPYcvRhQ9e1T7s4Vo1Z1GtSgzP9YffvDxWOnlEwSWtPAjLg6BZYS7Ls1yt7jn6JBpWjVm0tRWL013PsIIh08mjCS5p5YFFDT7uA7L8Xop+LN4P1g0vOstyEaJSyRafKaHbN1adTh5JcEkr+/kmygp7WU0rW25hSS/L++BWU8mWsyoW08mjCy4zcimWYvEALIHLXvQqlyJIi8+T135v83jFsm9bZTp5dMHdnWwjrUyxFMvWsphW9ukF1FqGQJW/FquSY5y/XUU6eWTBbUe5zYuklSmWYtlZ1tLKvs0ZtrQfaXXfVhOfYhsH2uOdPGI6eUzB7U4rTz/zDsVSFEuxJrwspZV9MLxILyu9uCo0szjKUNXmoU8ByuOOFz+oJJ08nuDuX5rJjuzTxjLFUizW5JaltLLV/ceiZWEIvV7cLfpOx1aR3EFbpd/5wbFMOjnZV7vgbqaVV9Mf5M5DZ6MVXN88eFlhLktpZavVtf3WJCM4y2Ibw1CCPDSGNpNOXpt68viWyQjuhtKnP8yNj52IsnjKt9QZK+xlJa3sg+FFdk0qraw0skWx1dCJGCPbDj2TgfY2l8fSzLG+eUPpW4ofefEUxVIsS8tCWtn1LGhXS9Fc3VGujpUcm6wtvTDFLLY9vbdid7JtYoK7mVZejrl4Smkg66PHWHEtC2llXwwv8ladrlNK1Vp8fkhs9SIQq9gKbZFmBPfM2Ho59g+YX5qNuXhKY71YLGtLgkfWZ/TlepiBomiLKWQtVUjHWI2cLZbSFmlVxVKVCW5bdJvnYi2eoliKZXFN2hs4hPvChehKyOTSZDUrpvOm/eSYxVbc/+pnlRZLVSy4jYUYi6colmJZXXqgTyqt7JvhRb+laK+KbMGB/2m/BFk+LspKxGZqUcStz75babFUtYLbLp66GlvxFMVSLMtrUq0cEpfQloqaFJnqbytzDGTLqO0miaz1Gg99vljbfvLYfvKryoulKhXcdvFUciz9AW9+4iTFUizWBNek0sq+GV6MsuQqJ6OMLL6l0vV5Y9+vraNYqnrBzSmekgclxVIs1mTWpNLKMrdn2V+uC8N8LZbqcZaaa+wyJ7h5xVO3PfdesCfGaoUhi5VeSm3WfW/gKW576fxM4rrwgXs2IikXxVJuBHfjTSAb5T5y6psgTwxzb1k+rLJ7jlXhq+FFDEsFW4pqKYwqjm57W4EaByrVyCp/WN7YvlBbhBBclg+rbsFlq8XmkvsYe7X9yWkFujo1n2y1LbgbbwTpD618eIgtQgguy4dVt+BSuW9rqSiK9HE5VOjrohXIreDm+CsrL47gslj1r7oF1+Ic1xiX9mktzUa2zuzxL5y1AjkV3PZebnI0/cG3LLyB4LJYE1h1Cq72BlmTXfJAbvyOfdphUYFv995t87QTbXTyQ+eTrVkjDOXHEVwWq95Vp+CGaHjhy1LXBOYVo6H21Z7odj7Z6Y3g5hlhaK4ggsti1bvqFFxVwLLqW+qz/sUlpvqMS4/RxVzzvDNddPaDAzfCQHBZPqw6Bdey4YXEKZR7VoVQShszZGB81LZ6w/dfy7YCLXgnuJtGGKdDNcJAcFkIbjeWrU51v+ozqjVGYuXT/asCKNl0qggKkXUe3VZqdFGv4O5Otmej3Ade/zyIE6X2hzwvVQBLaKJVHffDD39lW7Q0eCD7mTviqx5VFRtZWopif3yhvvNHdOvG6KJWwc2LckMfagAQI9YNL8qM2NNeqKJIvUzX1d4kYVUqXvvf+t30zIYb3dYkuL17uaFVLAPEjlKelteoLkv6PqXl9UIhUVQ0nM0ipKNjCXX23/V9afTzlBHguokruq1FcIlyAcLHsuGFBJFzBGm2vvB+7dFtjYJLlAsQKirksbyUsuU8QYf8vlv30W1tgkuUCxAu2h+1vF77PecIrtPjKjXXPF9HdFuz4BLlAoSIdcOLuv2kwbPotsIB82YEd3N03zJRLkBYWO9pxVcY+kW3tWpgrb8sx2N5W+MCFwKAx1g2vFAxF+cILES3tQtuXpR742MngpyXCxADMmawvOQ1zHkCIT//SUa3kxHcnChXDchcEAD+oYIky0v9s5wnUL1QXROBTAnu5rzcg+k/XA3I209+xYUB4BnWDS+wRgRlUJVJrWPerU3BffL4llajcaCDDQBiwZoHcXppb5lzBDNHzmVTyVen9i/NRCO47Si3sSsb4s8e/4ILBMATrBtedCYEQbzkWjjubS5PTPcm9Yvbots8T5sQgJ9YN7zImxAEcXH786sTsXC0Kbg5Zhj3vvIJFwqAB2iqjuVVZkIQhMuDJ9byLBwXJqp5k/zlrQ+wJzlFmxCAf1g3vBh1QhCEgTKmk24Dsie4tAkBeIfcm/7xb7tiy4SguJGhUm90uzQbveC2zTCWD2fbhB5+8zIXDoBRrBteMCEoXh796be9bUB7klMmtM7Eh8hpE5IrCBcPgE2sG14wIShecmbdXlUmFcHtSi03FiigAvADRZCWFxOC4kStpb1+yclBMzpn5YNs+iyvZlPL6qPiQgKwhWXDCy0mBMWHim23LLwxsVm3/gnu/qWZbAHVrc++y8UEYIh979sWWyYExcldhz80WShlVnA3U8sHsgftvuanXFAARrBueKH+YM5TXGj0niVHKW8EN8+BShVnqjzjwgKYPNYNLxq/4xzFRk7P7ZqlVLJtwZUDVSa1rMozLiyAyaOUreXFhKC4uPvlj0yM3vNWcDdH+B1luAGALawbXuizUTAVDxrr2pNKNtJz65fgqjd3b/Ni+kCqAg3bR4DJoXYbCqbACtPPvJONbq9Y6bn1SnA3C6h2ZKPcO178gAsNYEJYN7xY/RPnKBbuWfzY3HACrwV3s4BqJXtQ73/1My44gAlg3fACh6k4kPVvTlXyGfN6Zv4Dzi9Ob4jupWzVMoYYAPXz9T9tCy4OU+GjbcWcquSr8nFAcB2lljHEAKgX64YXWv/x35yn0Mk3uLCdSvZKcNu2j90ThYRy+FyAAPWwcbuZXn//lnMUOrleyfPN097omDcfVFXL881zjPEDmAy/uGRbcM//jXMUMrlj92RwMb84jeDW5LWsXD6tQgDusW54QYVy2Nz+/GpeKnmHVxrm04fd3M/tGeOnnD4XJIA7tDdqfZ38I+cpVLY1LvSKrUGv5OAEt/Wh9ySncKECqA/rhhdaP77AeQqRXDcpmSIZ9EoOU3DbrUJrtAoB1MNP/mBfcFXUxbkKC20X3vL0270tQMbG7gUtuEWtQjox7OcCVM9v/2pfcP/rfzlPoaGhNTn7tge81S1fP3hRq9Cdh85yoQJUjHXDC60fneU8hUTBvu2q15rl84dvi27zTPak6ERxwQJUg8bd+bBwmQqHB0+s9e7bynHQoxagMAU3x/pRJ+qhlS+5cAEqwLrhRWcd+i3nKgTUb6vJcKHs2wYluK0/YneyPdufqxOmE8cFDDAe6m/1YTV+x7kKgZyRe95YN0YhuEX9ufgtA4zPn772Q3AxvvCfmSPngui3DV5w2/u5ybHsydIJ5EIGGA0fDC86a+0bzpfPaOxqjk/yOR/7beMQ3By/ZebnAoyO9kV9Wuzj+onMLb7zg2O9PskejNyLVnBbf1Dbb3mNIiqA8fHB8CK95PfMefML1drc9Phb3vskRym4RaYYcqLSWxQXOEB5NIHHt6WpRpw7P5BRUUGRlLfmFtEJbusPm0sOZk+iJgtRuQxQnn/82z/B1frZZ+vr3/sl5886uROA9iSngtWlUP+woiIqVS5j/wgwGF8ML/oVUR35iPNoFU15y6lIPhNSkVRUgtsW3eZq9qTKn5MLHqA/r/3eb8HtrL9/2x7dh/WjHe595ZM8sb3ou5MUgqvK5bnmedqFAIbDF8OLYZZS5NqXlgDLKEN2kGp94nzXxwOvf94rtgFWJEcpuO0iqmRr1v5R3Nf8lBsAoAClZGNYP/wV57ou1C2S45EchG0jgpv+Q3cn2zZO7pVsuxCD6wF62bMah9gq4uV814O6RNQt0hvdNnZFo0Ox/KGbke7OrOeymq3p0QXoxjfDi1EXfbv10KfXNsj2HwT3eo9uj+eyRJceXYDrqK0mhvXrP3Ou6xBbtWSG7JGM4PatXO4dXK/pQoguQBsfDS9GWT++wLl2iVowc8V2vnk6Su2J8Y9u/eFzzZU80X3k1DfcKBA1Mozw1fBi2IX3sluxle9BTmS7GnKvLYI7hOjiRgWxo37VWBYVyjWLrVo0IxVbBFc9ujnGGIguxEwohheDFhXK7pC5UK7YBm5sgeCOKLpYQEKs/OYvcQguFcq1iu2l2MUWwU2Lbo4bFaILAFCeXH9kiW0ELlII7lDtQovTiC4AwGjILhexRXCHEN18C0hEFwBgyMhWzn6RWDYiuKMekI23MUQXAKAcuXu2iC2CW/qgyHc5R3Snn3mH6mUAAMQWwa0j0qVlCABiR9m+2557D7FFcBFdAACXYlvgIIXYIrhuqpcluthAAgBi2+mzRWwRXIeiy8ADAIiFwqk/tP4guE5Ed755Lk90macLACGjbB5ii+DWe7AKbCA1T3f2+BfcmAAQHAooFFjkeiMjtgjuJET3hu+/tr6tcYEbFACC4YHXP28FFAwiQHAnK7o5o/2E7M24UQHAdxRA5D3jNjiD2CK49R+8ueRg3gWpZnBcqQDAVwqsGtdbgUbE82wR3IkXUyX7Ni7Cq7hSAYDvKFC4/fnVArFNjvLMR3ANiG5jR6vpO3OB3vT4W7QNAYAXKEBQoJAT1V7deMYt8KxHcO0cyAL/5RsfO7H+4Ik1bmgAMMvDb15uBQj57lGNHTzjEVyDkW5+r64qmO995RNubAAwx/2vflZUiXxJgQTPdgTXdgXznuQUxVQAYJ3cofG0/SC4HlYwH827kOXWwr4uAEwS7dcWTPtZn5pvnqYSGcH1s4I5p5hK6RulcbjxAaBuCp2j2pXIB3l2I7h+F1PtbV7EJAMAJs19zU9bNSUURyG4YRdTFezratQV/boA4BLVjtx56Gzxfi2eyAhueMLbOJB3wSu9Q+sQALhAk35uefrtApvG5Bj7tQhuyCnm7RtvlGt5rUN3v/wRDwgAqIw+LT9Xp+aSp3gmI7gxFFNtzevX7VhC6o2UhwUAjJNCVhtiQQpZ/bXbeRYjuHEd/L3N5bwbQm+kGovFgwMAhkXbUwWuUUz6QXCjj3Z35qWYhYocMMoAgLJoWyq3CrmdQqblB8GFVoo5Z6h9ZwCCfE55mABAEdqGyh080OYiKWQEF7InQ/N1c0b94cUMAEUUFkZRhYzgwqBod2m2yChDPbsUVAGAUP9+YWFUy8gi2ckzFcGFQSdFAxD0ZlpQUEX7EEDcbGtcaI3+LBDbVW1T8SxFcGGoFHNjV54Xs1AjO3u7APHt1SrTVdDuQ2EUgguuCqq0tys/ZiqZAcJHdRyFe7Xq62d2LYILVQlvY6Eo2lUlM9aQAGGiTFahNSNRLYILDqPdueZKwb7N+l2HP2QQAkBAFPbVdvZqiWoRXHAuvIVmGSqk0AguHlYA/jJ7/Iv1m5842acCubHAsxDBhdpEd3G6yBqyU1RFmhnAL7af/Gr9tufeKxJa7dWepgIZwYVJnUBNHyro2xW3P79K7y6AcbQVpC2hwvSxMlr01SK4YOAkqm93Ljma51KV7t2lmhnAHqo+7tNT23aLYuAAggvGTub+pZlWyqngxtWge9nA8ZADML9PuznZZ2mWZxuCC6b3dxs7NqLd80U3skzOH1r5kocegMV9Ws2rnWvs4lmG4IJPJ3cueaqomlnopkd4AepBtRQaudmnzedKa4AJwwYQXPA12l2c7re/K2SArrduHooAExHazX1aqo8RXIhifxfhBagWVR7LerV4dN41S0Zm1SK4EGbE2zLNOD9IeGklAnAotNqnnU/28UxCcCGK/d3Grn7Cq/SX0mAIL0A51HZ3z+LH/Vt8WkKLSxSCC7FGvPtaD4E+wkuqGWBwRDtAaNc2hPYABVEILkB7GlEf4e1UNWMXCdBGL6F3vPjBgGKolu8xQgsILmQuBjlW6eHQp5Wo08eLgQbEil46+/bRdoR27/JhHKIAwYVKhFdzeLc1LvAQhijQFK7CubQILSC4UIHwLvQbjtAZCahiEWbxQoj7s/I6li1qX6Ht7NEitIDgwtgXitqJ5O3a56HTKbB64PXPeViD92ljXcsD9mfXWy+jVB0DggtuhHdpduNtfmXAQ6gVEWhCEdXN4Fs0q62SQdd3e7AA4/IAwYV6It6tLcvI1p5V/4fTrc++29r/4qEOnkez61N7klNM8AEEFyYkvC2v5qcG7fN29nrVRvHwm5d50IM/0WyreDA5JntU7nlAcMHGxbQ72d5KN/cZlJCucCblDHWLrKrqS7T0dFjFfhEQXPAj6pUxe4kHm4ZwK9rARhKqRnaLQ4lsaxZtcpBoFhBc8DHq3dZKx5XY6+2YaugBSYsRjCOyqhm4/fnVcvuyysi09mYpggIEF0K40K739J4pmc5rRSV6cBL5Qpl08VAi2xba8+1MDL2zgOBCsCnnVoXzU8OIr9LOdx3+EC9nuMZDK1+26gBKuD91983KCYqUMSC4EN0FuPHg27SRPF/2oak5o4pklHqm6Cq+VLFaePpO5snflz2q7Q3uOUBwAUYU307Fs2b3yuFKD2XEKawoVrah6uUe5prY9AFfpmcWEFyAsuJbstI5jVKMEmD2f/2LYGePf9GaLSuBLb0X25Uulsg2dnAPAYILMMpFqjaj+WTfZo/v2rACLJtJpaDVeqSICXGzgQxQtC0gMxTt0Q97XlvVxfPN0616APZkAcEFcCHA8nNODg6bek7vASuCUiSlub44X9UjrjrWnehV52CUc7dZWXyUKBYQXIDaxTfZ2mo3Uh+limNGeYineoBVkKPKV6U26QUePS2sfVdFrjqm45yT1jlt9chunOONc801DwgugJULurX3m+xr7+UNv/+b5/8s0VBk1hFi0tLtYqaOsOrY6BgNVTncL4KVUYrOIWliQHABfIuCGztavZfyxi3peFU2NS2hkUGHREd7xBKhEFLU+hv0t+hv0t+mPXD9rSOngvuNuWuliJOdGFAAggsQ2kUvu8mW61VLhM+MUog1bITcQeLVQQVDErU0rqqq07+jE5WmhVSouMzVcdgcaHGmHb02DmjQBdciILgAUUbBqoTeiIQlBm3v5zPOxCd0lBbWvqteaBS5khoGQHABBt4g7T3hnS3xUOpTQlzB3nAAXLwWsbaFdR8mEwAILoCbm6c9kGFHjyCP2K5kX1BbfyuVwgAILoDRm6ydqt5xPWWtvWMJdHNlM3V9nSr3k6/tm6aQUUTn97eENP3ZKFoCcMn/B50KyeS7TVtNAAAAAElFTkSuQmCC", - fileName= - "modelica://SorpLib/Resources/Images/DeltaP.png")}), - Documentation(info="<html> -<p> - This partial model is the basis for the pressure drop correlation models. <br> -</p> - -<h4>Author Information</h4> -<p> - <ul> - <li> - November 28, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); - -end PartialPressureDrop; diff --git a/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/Partial/package.order b/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/Partial/package.order deleted file mode 100644 index 1b8a13e7267887015effecc8651b65ef88e3d839..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/Partial/package.order +++ /dev/null @@ -1 +0,0 @@ -PartialPressureDrop diff --git a/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/package.mo b/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/package.mo deleted file mode 100644 index 72c1b9290a5b00920d4c1e7febf6972575dfa49e..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/package.mo +++ /dev/null @@ -1,8 +0,0 @@ -within SorpLib.Components.OpenAdsorber; -package PressureDropCorrelations - extends SorpLib.Internals.ClassTypes.ModelPackage; - - - - -end PressureDropCorrelations; diff --git a/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/package.order b/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/package.order deleted file mode 100644 index 5d63ff1d5db9235a290ccec60ca3f5c06fc0c2ab..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/PressureDropCorrelations/package.order +++ /dev/null @@ -1 +0,0 @@ -PackedBed_Kast1988 diff --git a/SorpLib/Components/OpenAdsorber/Testers/TestOpenAdsorber.mo b/SorpLib/Components/OpenAdsorber/Testers/TestOpenAdsorber.mo deleted file mode 100644 index d6e3839ecb6b77b2bc0071c88c2870f6075d0b16..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/Testers/TestOpenAdsorber.mo +++ /dev/null @@ -1,62 +0,0 @@ -within SorpLib.Components.OpenAdsorber.Testers; -model TestOpenAdsorber - - inner TIL.SystemInformationManager sim( - redeclare TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1, - redeclare TILMedia.LiquidTypes.TILMedia_Water liquidType1, - redeclare TILMedia.GasTypes.TILMedia_MoistAir gasType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - - TIL.GasComponents.Boundaries.Boundary gasBoundaryA( - phiFixed=80, - boundaryType="m_flow", - gasType=sim.gasType1, - m_flowFixed=-2, - streamVariablesInputTypeConcentration="xi", - TFixed=353.15) - annotation (Placement(transformation(extent={{-44,-10},{-36,10}}))); - TIL.GasComponents.Boundaries.Boundary gasBoundaryB( - phiFixed=80, - boundaryType="p", - streamVariablesInputTypeConcentration="xi", - TFixed=373.15, - pFixed=100000) - annotation (Placement(transformation(extent={{36,-10},{44,10}}))); - - OpenAdsorber openAdsorber( - redeclare Geometry.CylindricAdsorber adsorberGeometry, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - nCells=5, - redeclare model HeatTransfer_gasAdsorbent = - HeatAndMassTransfer.TransportPhenomena.HeatTransfer.PackedBedGas_Kast1988, - redeclare model MassTransfer_diffusion_dp = - HeatAndMassTransfer.TransportPhenomena.MassTransfer.PackedBedGas_Kast1988, - HydraulicMassFlowPosition="gas port B", - xInitial=0.3, - redeclare model WallMaterial = TILMedia.SolidTypes.TILMedia_St35_8, - redeclare model HeatTransfer_gasWall = - HeatAndMassTransfer.TransportPhenomena.HeatTransfer.PackedBedWall_Kast1988, - fixedInitialPressure=true, - redeclare model PressureDropModel = - PressureDropCorrelations.PackedBed_Kast1988, - TInitialGas=293.15, - pInitial=100000, - TInitialAdsorbent=293.15, - TInitialWall=293.15) - annotation (Placement(transformation(extent={{-8,-14},{16,14}}))); - -equation - connect(openAdsorber.gasPortB, gasBoundaryB.port) annotation (Line( - points={{16.2,0},{24,0},{40,0}}, - color={255,153,0}, - thickness=0.5)); - connect(openAdsorber.gasPortA, gasBoundaryA.port) annotation (Line( - points={{-7.8,0},{-24,0},{-40,0}}, - color={255,153,0}, - thickness=0.5)); - annotation (Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, - -100},{100,100}})), - experiment(StopTime=200), - __Dymola_experimentSetupOutput); -end TestOpenAdsorber; diff --git a/SorpLib/Components/OpenAdsorber/Testers/TestOpenAdsorber2.mo b/SorpLib/Components/OpenAdsorber/Testers/TestOpenAdsorber2.mo deleted file mode 100644 index 47952cc521ac5c8b80695547128696fb63dfad42..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/Testers/TestOpenAdsorber2.mo +++ /dev/null @@ -1,83 +0,0 @@ -within SorpLib.Components.OpenAdsorber.Testers; -model TestOpenAdsorber2 - - inner TIL.SystemInformationManager sim( - redeclare TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1, - redeclare TILMedia.LiquidTypes.TILMedia_Water liquidType1, - redeclare TILMedia.GasTypes.TILMedia_MoistAir gasType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - - TIL.GasComponents.Boundaries.Boundary gasBoundaryB( - phiFixed=80, - boundaryType="p", - streamVariablesInputTypeConcentration="xi", - TFixed=373.15, - pFixed=100000) - annotation (Placement(transformation(extent={{36,-10},{44,10}}))); - - OpenAdsorber openAdsorber( - redeclare Geometry.CylindricAdsorber adsorberGeometry, - redeclare model AdsorbentAdsorbate = - Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe, - redeclare model WallMaterial = TILMedia.SolidTypes.TILMedia_Steel, - nCells=5, - redeclare model HeatTransfer_gasAdsorbent = - HeatAndMassTransfer.TransportPhenomena.HeatTransfer.PackedBedGas_Kast1988, - HydraulicMassFlowPosition="gas port B", - redeclare model HeatTransfer_gasWall = - HeatAndMassTransfer.TransportPhenomena.HeatTransfer.PackedBedWall_Kast1988, - xInitial=0.025, - generateEventsAtFlowReversal=false, - fixedInitialPressure=true, - fixedInitialPressure_firstCell=false, - redeclare model MassTransfer_diffusion_dp = - HeatAndMassTransfer.TransportPhenomena.MassTransfer.PackedBedGas_Kast1988, - redeclare model PressureDropModel = - PressureDropCorrelations.PackedBed_Kast1988, - TInitialGas=353.15, - pInitial=100000, - TInitialAdsorbent=353.15, - TInitialWall=353.15) - annotation (Placement(transformation(extent={{-13,-14},{13,14}}))); - - TIL.GasComponents.Boundaries.Boundary gasBoundaryA( - phiFixed=80, - boundaryType="p", - streamVariablesInputTypeConcentration="xi", - mixingRatioFixed={0.01,1}, - TFixed=303.15, - pFixed=150000) - annotation (Placement(transformation(extent={{-44,-10},{-36,10}}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary(TFixed=303.15) - annotation (Placement(transformation( - extent={{-4,-6},{4,6}}, - rotation=-90, - origin={0,44}))); - HeatTransfer.HeatTransfer heatTransfer(n=openAdsorber.nCells, redeclare model - HeatTransfer = HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=100)) annotation (Placement(transformation( - extent={{-8,-4},{8,4}}, - rotation=-90, - origin={0,28}))); -equation - connect(openAdsorber.gasPortB, gasBoundaryB.port) annotation (Line( - points={{13.2167,0},{13.2167,0},{40,0}}, - color={255,153,0}, - thickness=0.5)); - connect(gasBoundaryA.port, openAdsorber.gasPortA) annotation (Line( - points={{-40,0},{-12.7833,0}}, - color={255,153,0}, - thickness=0.5)); - connect(openAdsorber.heatPort, heatTransfer.heatPortB) annotation (Line( - points={{0,14},{0,14},{0,20}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransfer.heatPortA, heatBoundary.heatPort) annotation (Line( - points={{0,36},{0,44}}, - color={204,0,0}, - thickness=0.5)); - annotation (Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100, - -100},{100,100}})), - experiment(StopTime=200), - __Dymola_experimentSetupOutput); -end TestOpenAdsorber2; diff --git a/SorpLib/Components/OpenAdsorber/Testers/package.mo b/SorpLib/Components/OpenAdsorber/Testers/package.mo deleted file mode 100644 index 4f9323ec60336e112a6ded087bc9da0bda89c535..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/Testers/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.OpenAdsorber; -package Testers - extends SorpLib.Internals.ClassTypes.ApplicationPackage; - -end Testers; diff --git a/SorpLib/Components/OpenAdsorber/Testers/package.order b/SorpLib/Components/OpenAdsorber/Testers/package.order deleted file mode 100644 index 3789a52968c672711ece2d3a55cb81a16bcf4925..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/Testers/package.order +++ /dev/null @@ -1,2 +0,0 @@ -TestOpenAdsorber -TestOpenAdsorber2 diff --git a/SorpLib/Components/OpenAdsorber/package.mo b/SorpLib/Components/OpenAdsorber/package.mo deleted file mode 100644 index 255df9383b19c34b15aa7edd88bdcd4e8d52b1a5..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/package.mo +++ /dev/null @@ -1,13 +0,0 @@ -within SorpLib.Components; -package OpenAdsorber - - - extends SorpLib.Internals.ClassTypes.ComponentPackage; - - - - - - - annotation (Icon(graphics)); -end OpenAdsorber; diff --git a/SorpLib/Components/OpenAdsorber/package.order b/SorpLib/Components/OpenAdsorber/package.order deleted file mode 100644 index b9483c606fde5b5a700c880129611652bd0571ab..0000000000000000000000000000000000000000 --- a/SorpLib/Components/OpenAdsorber/package.order +++ /dev/null @@ -1,5 +0,0 @@ -OpenAdsorber -Geometry -HeatAndMassTransfer -PressureDropCorrelations -Testers diff --git a/SorpLib/Components/Pumps/AffinityPump.mo b/SorpLib/Components/Pumps/AffinityPump.mo new file mode 100644 index 0000000000000000000000000000000000000000..b21eb5121a12ca157cdb292fef276dfcbaa4192d --- /dev/null +++ b/SorpLib/Components/Pumps/AffinityPump.mo @@ -0,0 +1,132 @@ +within SorpLib.Components.Pumps; +model AffinityPump "Model of a pump based on affinity laws" + extends BaseClasses.PartialAffinityPump( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculation of fluid properties + // + rho = Medium.density_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1, inStream(port_a.Xi_outflow), {1-sum(inStream(port_a.Xi_outflow))})) + "Instreaming density"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The affinity pump can be used to prescribe the mass or volume flow rate in hydraulic +components, such as tubes or heat exchangers. The model assumes a non-constant pump +efficiency that depends on the volume flow rate. Changes compared to a nominal operating +point are considered by affinity laws. + +<h4>Main equations</h4> +<p> +The model calculates the hydraulic, shaft, and drive power transmitted to the fluid +or required to drive the pump. The hydraulic power <i>P<sub>hydraulic</sub></i> +transmitted to the fluid is defined as: +</p> +<pre> + P<sub>hydraulic</sub> = ṁ / ρ<sub>in</sub> * Δp; +</pre> +<p> +Herein, <i>ṁ</i> is the mass flow rate, <i>ρ<sub>in</sub></i> describes the +fluid density at the inlet, and <i>Δp = p<sub>b</sub> - p<sub>a</sub></i> is the +pressure difference between port b and a. The mass flow rate <i>ṁ</i> follows +from the volume flow rate <i>V<sub>flow</sub></i> that depends on the rotational speed +<i>n</i>, the nominal volume flow rate <i>V<sub>flow,ref</sub></i>, and the nominal +rotational speed <i>n<sub>ref</sub></i>: +</p> +<pre> + V<sub>flow</sub> = ṁ / ρ<sub>in</sub> = V<sub>flow,ref</sub> * n / n<sub>ref</sub>; +</pre> +<p> +The shaft power <i>P<sub>shaft</sub></i> depends on the pump efficiency +<i>η<sub>pump</sub></i> and is defined as: +</p> +<pre> + P<sub>shaft</sub> = P<sub>hydraulic</sub> / η<sub>pump</sub>; +</pre> +<p> +with +</p> +<pre> + η<sub>pump</sub> = η<sub>pump,ref</sub> * (1 - f<sub>loss</sub> * ((ṁ / ρ<sub>in</sub>) / V<sub>flow,ref</sub> - 1) ^ 2); +</pre> +<p> +Herein, <i>f<sub>loss</sub></i> is a loss factor describing the dependency on the volume +flow rate, <i>η<sub>pump,ref</sub></i> is the efficiency at the nominal operating point, +and <i>V<sub>flow,ref</sub></i> is the nominal volume flow rate. The shaft power is completly +transmitted to the fluid, thus increasing the outflowing specific enthalpy of the fluid. +<br/><br/> +The drive power <i>P<sub>drive</sub></i> is required to drive the pump, depends on the +drive efficienciy <i>η<sub>drive</sub></i>, and is defined as: +</p> +<pre> + P<sub>drive</sub> = P<sub>shaft</sub> / η<sub>drive</sub>; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No flow reversal + </li> + <li> + Affinity laws apply to describe changes in operating conditions + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The affinity pump is typically used to prescripe the mass or volume flow rate +in hydraulic components, such as tubes or heat exchangers, if process controlelrs +are investigated and the flow rate changes. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>assumeIsenthalpicPump</i>: + Defines if the hydraulic losses are considered in the energy balance. + </li> + <li> + <i>calculateDrivePower</i>: + Defines if the driving power is calculates within the model. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 9, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AffinityPump; diff --git a/SorpLib/Components/Pumps/BaseClasses/PartialAffinityPump.mo b/SorpLib/Components/Pumps/BaseClasses/PartialAffinityPump.mo new file mode 100644 index 0000000000000000000000000000000000000000..3388bae3002ebe0821a2f0aa7a0119f5acbf9e03 --- /dev/null +++ b/SorpLib/Components/Pumps/BaseClasses/PartialAffinityPump.mo @@ -0,0 +1,142 @@ +within SorpLib.Components.Pumps.BaseClasses; +partial model PartialAffinityPump + "Base model for all pumps using affinity laws" + extends SorpLib.Components.Pumps.BaseClasses.PartialPump; + + // + // Definition of paramteres describring the pump's characteristics + // + parameter Modelica.Units.SI.Frequency n_ref = 50 + "Nominal rotational speed" + annotation (Dialog(tab="General", group="Pump Characteristics - Nominal point")); + parameter Modelica.Units.SI.VolumeFlowRate V_flow_ref = 10/1000/60 + "Nominal volume flow rate" + annotation (Dialog(tab="General", group="Pump Characteristics - Nominal point")); + parameter Modelica.Units.SI.Efficiency eta_pump_ref = 0.4 + "Nominal pump efficiency" + annotation (Dialog(tab="General", group="Pump Characteristics - Nominal point")); + parameter Real f_loss = 0.3 + "Loss factor describing the pump efficiency" + annotation (Dialog(tab="General", group="Pump Characteristics - Nominal point")); + + // + // Definition of parameters describing the inputs + // + parameter Boolean use_nInput = false + "=true, if n is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Inputs"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Frequency n_fixed = 50 + "Fixed rotational speed" + annotation (Dialog(tab="General",group="Inputs", + enable=not use_nInput)); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput n_input(final unit="1/s") if + use_nInput + "Input for rotational speed" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=90, + origin={0,-90}), + iconTransformation(extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-80}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput n_internal(final unit="1/s") + "Needed for connecting to conditional connector"; + + // + // Definition of variables + // +public + Modelica.Units.SI.Efficiency eta_pump + "Pump efficiency"; + +equation + // + // Assertions + // + assert(n_internal >= 0, + "Rotational speed cannot be negative!", + level=AssertionLevel.error); + + // + // Connectors + // + connect(n_internal, n_input); + + if not use_nInput then + n_internal = n_fixed + "Needed for connecting to conditional connector"; + end if; + + // + // Mass balance + // + m_flow = V_flow * rho + "Mass flow rate at port a"; + V_flow = V_flow_ref * (n_internal / n_ref) + "Volume flow rate at port a (affinity law)"; + + // + // Energy balance + // + if assumeIsenthalpicPump then + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy due to + forbidden flow revesal"; + port_b.h_outflow = inStream(port_a.h_outflow) + (1/eta_pump - 1) * dp / rho + "Increase of specific enthalpy due to internal losses of the pump"; + + else + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + port_b.h_outflow = inStream(port_a.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + + end if; + + // + // Power calculations + // + eta_pump = eta_pump_ref * (1 - f_loss * (V_flow / V_flow_ref - 1) ^ 2) + "Efficiency ot the pump dependent on the volume flow rate"; + + P_shaft = P_hydraulic / eta_pump + "Shaft power consumption of pump"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all pumps using affinity laws and volume- +flow-dependent efficiencies. It defines fundamental parameters and variables required +by all affinity pumps. Models that inherit properties from this partial model have +to redeclare the fluid ports. Moreover, the instreaming density must be calculated. +In this context, appropriate fluid property models are required. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Instreaming density <i>rho</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 9, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialAffinityPump; diff --git a/SorpLib/Components/Pumps/BaseClasses/PartialPump.mo b/SorpLib/Components/Pumps/BaseClasses/PartialPump.mo new file mode 100644 index 0000000000000000000000000000000000000000..bfbe364e1e2aa053560177725dae371e4f04bd0b --- /dev/null +++ b/SorpLib/Components/Pumps/BaseClasses/PartialPump.mo @@ -0,0 +1,185 @@ +within SorpLib.Components.Pumps.BaseClasses; +partial model PartialPump "Base model for all pumps" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of paramteres describring the pump's characteristics + // + parameter Boolean assumeIsenthalpicPump = false + " = true, if internal losses do not influence the energy balance" + annotation (Dialog(tab="General", group="Pump Characteristics")); + parameter Boolean calculateDrivePower = true + " = true, if drive power is calcualted" + annotation (Dialog(tab="General", group="Pump Characteristics")); + + parameter Modelica.Units.SI.Efficiency eta_drive = 0.9 + "Efficiency of drive that is used to calculate drive power" + annotation (Dialog(tab="General", group="Pump Characteristics", + enable=calculateDrivePower)); + + // + // Definition or initialisation parameters + // + parameter Modelica.Units.SI.MassFlowRate m_flow_start = 1e-4 + "Start value for mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=m_flow_start)) + "Fluid port a" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}), + iconTransformation(extent={{-90,-10},{-70,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-m_flow_start)) + "Fluid port b" + annotation (Placement(transformation(extent={{70,-10},{90,10}}), + iconTransformation(extent={{70,-10},{90,10}})), + choicesAllMatching=true); + + // + // Definition of variables + // + Modelica.Units.SI.Density rho + "Instreaming density"; + + Modelica.Units.SI.PressureDifference dp + "Pressure difference between port a and b"; + Modelica.Units.SI.MassFlowRate m_flow + "Mass flow rate"; + Modelica.Units.SI.VolumeFlowRate V_flow + "Volume flow rate"; + + Modelica.Units.SI.Power P_hydraulic + "Hydraulic power consumption of the pump"; + Modelica.Units.SI.Power P_shaft + "Shaft power consumption of the pump"; + Modelica.Units.SI.Power P_drive + "Drive power consumption of the pump"; + Modelica.Units.SI.Power P_loss_internal + "Internal power losses of the pump (i.e., increase of outflowing specific + enthalpy)"; + +equation + // + // Assertions + // + assert(m_flow >= 0, + "Pump model cannot handle flow reversal!", + level=AssertionLevel.error); + + // + // Momentum balance + // + dp = port_b.p - port_a.p + "Pressure difference between port b and a"; + + // + // Mass balance + // + 0 = port_a.m_flow + port_b.m_flow + "Steady-state mass balance"; + + port_a.Xi_outflow = inStream(port_b.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + port_b.Xi_outflow = inStream(port_a.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + + port_a.m_flow = m_flow + "Mass flow rate at port a"; + + // + // Power calculations + // + P_hydraulic = V_flow * dp + "Hydraulic power consumption of the pump"; + P_drive = if calculateDrivePower then P_shaft / eta_drive else 0 + "Drive power consumption of pump"; + P_loss_internal = P_shaft - P_hydraulic + "Internal power losses of pump (i.e., increase outflowing specific enthalpy)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all pumps. It defines fundamental +parameters and variables required by all pumps. Models that inherit properties +from this partial model have to redeclare the fluid ports. Moreover, the mass +and energy balances must be completed, and the power calculations must be added. +In this context, appropriate fluid property models are required. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Instreaming density <i>rho</i>. + </li> + <br/> + <li> + Mass flow rate <i>m_flow</i> at port a. + </li> + <li> + Volume flow rate <i>V_flow</i> at port a. + </li> + <br/> + <li> + Outflowing specific enthalpy <i>port_a.h_outflow</i> at port a. + </li> + <li> + Outflowing specific enthalpy <i>port_b.h_outflow</i> at port b. + </li> + <br/> + <li> + Shaft power <i>P_shaft</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 8, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ + Ellipse( + extent={{-80,-80},{80,80}}, + lineColor={28,108,200}, + fillColor={28,108,200}, + fillPattern=FillPattern.Sphere), + Polygon( + points={{-68,42},{-68,-42},{80,0},{-68,42}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Line( + points={{40,0},{-50,0}}, + color={0,0,0}, + arrow={Arrow.Filled,Arrow.None})})); +end PartialPump; diff --git a/SorpLib/Components/Pumps/BaseClasses/PartialSimplePump.mo b/SorpLib/Components/Pumps/BaseClasses/PartialSimplePump.mo new file mode 100644 index 0000000000000000000000000000000000000000..09f91dcf97d31bb554dbae18a15a3be8039719d2 --- /dev/null +++ b/SorpLib/Components/Pumps/BaseClasses/PartialSimplePump.mo @@ -0,0 +1,173 @@ +within SorpLib.Components.Pumps.BaseClasses; +partial model PartialSimplePump + "Base model for all simple pumps with constant efficiencies" + extends SorpLib.Components.Pumps.BaseClasses.PartialPump( + final calculateDrivePower=true); + + // + // Definition of paramteres describring the pump's characteristics + // + parameter Modelica.Units.SI.Efficiency eta_pump = 0.4 + "Efficiency of pump that is used to calculate shaft power" + annotation (Dialog(tab="General", group="Pump Characteristics")); + + // + // Definition of parameters describing the inputs + // + parameter SorpLib.Choices.PrescripedPumpVariable prescribedInput= + SorpLib.Choices.PrescripedPumpVariable.V_flow + "Prescribed input variable" + annotation (Dialog(tab="General", group="Inputs")); + + parameter Boolean use_mFlowInput = false + "=true, if m_flow is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Inputs", + enable=(prescribedInput == + SorpLib.Choices.PrescripedPumpVariable.m_flow)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.MassFlowRate m_flow_fixed = 0.1 + "Fixed mass flow rate" + annotation (Dialog(tab="General",group="Inputs", + enable=(prescribedInput == + SorpLib.Choices.PrescripedPumpVariable.m_flow) + and not use_mFlowInput)); + + parameter Boolean use_VFlowInput = false + "=true, if V_flow is defined by input; otherwise, fixed value is used" + annotation (Dialog(tab="General",group="Inputs", + enable=(prescribedInput == + SorpLib.Choices.PrescripedPumpVariable.V_flow)), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.VolumeFlowRate V_flow_fixed = 10/1000/60 + "Fixed volume flow rate" + annotation (Dialog(tab="General",group="Inputs", + enable=(prescribedInput == + SorpLib.Choices.PrescripedPumpVariable.V_flow) + and not use_VFlowInput)); + + // + // Definition of connectors + // + Modelica.Blocks.Interfaces.RealInput m_flow_input(final unit="kg/s") if + (prescribedInput == SorpLib.Choices.PrescripedPumpVariable.m_flow and + use_mFlowInput) + "Input for mass flow rate" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=90, + origin={0,-90}), + iconTransformation(extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-80}))); + + Modelica.Blocks.Interfaces.RealInput V_flow_input(final unit="m3/s") if + (prescribedInput == SorpLib.Choices.PrescripedPumpVariable.V_flow and + use_VFlowInput) + "Input for volume flow rate" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=90, + origin={30,-90}), + iconTransformation(extent={{-10,-10},{10,10}}, + rotation=90, + origin={30,-80}))); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput m_flow_internal(final unit="kg/s") + "Needed for connecting to conditional connector"; + Modelica.Blocks.Interfaces.RealInput V_flow_internal(final unit="m3/s") + "Needed for connecting to conditional connector"; + +equation + // + // Connectors + // + connect(m_flow_internal, m_flow_input); + connect(V_flow_internal, V_flow_input); + + if not use_mFlowInput then + m_flow_internal = m_flow_fixed + "Needed for connecting to conditional connector"; + end if; + if not use_VFlowInput then + V_flow_internal = V_flow_fixed + "Needed for connecting to conditional connector"; + end if; + + // + // Mass balance + // + if prescribedInput == SorpLib.Choices.PrescripedPumpVariable.m_flow then + m_flow = m_flow_internal + "Mass flow rate at port a"; + V_flow = m_flow_internal / rho + "Volume flow rate at port a"; + + elseif prescribedInput == SorpLib.Choices.PrescripedPumpVariable.V_flow then + m_flow = V_flow_internal * rho + "Mass flow rate at port a"; + V_flow = V_flow_internal + "Volume flow rate at port a"; + + end if; + + // + // Energy balance + // + if assumeIsenthalpicPump then + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy due to + forbidden flow revesal"; + port_b.h_outflow = inStream(port_a.h_outflow) + (1/eta_pump - 1) * dp / rho + "Increase of specific enthalpy due to internal losses of the pump"; + + else + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + port_b.h_outflow = inStream(port_a.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + + end if; + + // + // Power calculations + // + P_shaft = P_hydraulic / eta_pump + "Shaft power consumption of pump"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all simple pumps with constant efficiencies. +It defines fundamental parameters and variables required by all simple pumps. Models +that inherit properties from this partial model have to redeclare the fluid ports. +Moreover, the instreaming density must be calculated. In this context, appropriate +fluid property models are required. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Instreaming density <i>rho</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 8, 2024, by Mirko Engelpracht:<br/> + Adaptations due to restructering the library and documentation. + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialSimplePump; diff --git a/SorpLib/Components/Pumps/BaseClasses/package.mo b/SorpLib/Components/Pumps/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..89baf30b5f672e285ff248a727c9ed26d7436c43 --- /dev/null +++ b/SorpLib/Components/Pumps/BaseClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Pumps; +package BaseClasses "Base models and functions for all pumps" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial pump models, containing fundamental definitions for +pumps. The content of this package is only of interest when adding new pumps to +the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Components/Pumps/BaseClasses/package.order b/SorpLib/Components/Pumps/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c6c3711be34479e1c6b3d3db974d805714e5bf81 --- /dev/null +++ b/SorpLib/Components/Pumps/BaseClasses/package.order @@ -0,0 +1,3 @@ +PartialPump +PartialSimplePump +PartialAffinityPump diff --git a/SorpLib/Components/Pumps/SimplePump.mo b/SorpLib/Components/Pumps/SimplePump.mo new file mode 100644 index 0000000000000000000000000000000000000000..527c17cf8e43c5454cb12d5b7653e85ab05ed177 --- /dev/null +++ b/SorpLib/Components/Pumps/SimplePump.mo @@ -0,0 +1,120 @@ +within SorpLib.Components.Pumps; +model SimplePump "Model of a simple pump with constant efficiencies" + extends BaseClasses.PartialSimplePump( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculation of fluid properties + // + rho = Medium.density_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1, inStream(port_a.Xi_outflow), {1-sum(inStream(port_a.Xi_outflow))})) + "Instreaming density"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The simple pump can be used to prescribe the mass or volume flow rate in hydraulic +components, such as tubes or heat exchangers. The model assumes constant efficiencies +and can be used for (ideal) liquids. + +<h4>Main equations</h4> +<p> +The model calculates the hydraulic, shaft, and drive power transmitted to the fluid +or required to drive the pump. The hydraulic power <i>P<sub>hydraulic</sub></i> +transmitted to the fluid is defined as: +</p> +<pre> + P<sub>hydraulic</sub> = ṁ / ρ<sub>in</sub> * Δp; +</pre> +<p> +Herein, <i>ṁ</i> is the mass flow rate, <i>ρ<sub>in</sub></i> describes the +fluid density at the inlet, and <i>Δp = p<sub>b</sub> - p<sub>a</sub></i> is the +pressure difference between port b and a. +<br/><br/> +The shaft power <i>P<sub>shaft</sub></i> depends on the pump efficiency +<i>η<sub>pump</sub></i> and is defined as: +</p> +<pre> + P<sub>shaft</sub> = P<sub>hydraulic</sub> / η<sub>pump</sub>; +</pre> +<p> +The shaft power is completly transmitted to the fluid, thus increasing the outflowing +specific enthalpy of the fluid. +<br/><br/> +The drive power <i>P<sub>drive</sub></i> is required to drive the pump, depends on the +drive efficienciy <i>η<sub>drive</sub></i>, and is defined as: +</p> +<pre> + P<sub>drive</sub> = P<sub>shaft</sub> / η<sub>drive</sub>; +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Steady-state process + </li> + <li> + No flow reversal + </li> + <li> + Constant efficiencies + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The simple pump is typically used to prescripe the mass or volume flow rate +in hydraulic components, such as tubes or heat exchangers. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>prescribedInput</i>: + Defines the variable that is prescribed (i.e., mass flow rate or volume + flow rate). + </li> + <li> + <i>assumeIsenthalpicPump</i>: + Defines if the hydraulic losses are considered in the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 8, 2024, by Mirko Engelpracht:<br/> + Adaptations due to restructering the library and documentation. + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SimplePump; diff --git a/SorpLib/Components/Pumps/Tester/Test_AffinityPump.mo b/SorpLib/Components/Pumps/Tester/Test_AffinityPump.mo new file mode 100644 index 0000000000000000000000000000000000000000..aa49ea71fa102f8a3c36839a4f62dd94c2d527d6 --- /dev/null +++ b/SorpLib/Components/Pumps/Tester/Test_AffinityPump.mo @@ -0,0 +1,100 @@ +within SorpLib.Components.Pumps.Tester; +model Test_AffinityPump "Tester for the affinity pump" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Pumps.AffinityPump pump( + use_nInput=true, + redeclare final package Medium = Medium) "Affinity pump" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + + SorpLib.Components.Fittings.Resistors.LiquidTubeResistance pressureLoss( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.PortAInlet, + frictionPressureLoss=true, + fittingPressureLosss=false, + redeclare model PressureLossModel = + Fittings.PressureLossCorrelations.TubeInside.Blasius, + redeclare final package Medium = Medium) "Pressure loss model" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_n( + amplitude=50, + f=1/250, + offset=50) + "Input signal for the rotational speed" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}}))); + +equation + // + // Connections + // + connect(fs_a.port, pump.port_a) annotation (Line( + points={{-60,0},{-38,0}}, + color={28,108,200}, + thickness=1)); + connect(pressureLoss.port_a, pump.port_b) annotation (Line( + points={{22,0},{-22,0}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, pressureLoss.port_b) annotation (Line( + points={{60,0},{38,0}}, + color={28,108,200}, + thickness=1)); + + connect(input_n.y, pump.n_input) + annotation (Line(points={{-59,-30},{-30,-30},{-30,-8}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the affinity pump. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 9, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_AffinityPump; diff --git a/SorpLib/Components/Pumps/Tester/Test_SimplePump.mo b/SorpLib/Components/Pumps/Tester/Test_SimplePump.mo new file mode 100644 index 0000000000000000000000000000000000000000..847aa84cf3317f7d6f2070b14a42b7fb89f5deba --- /dev/null +++ b/SorpLib/Components/Pumps/Tester/Test_SimplePump.mo @@ -0,0 +1,104 @@ +within SorpLib.Components.Pumps.Tester; +model Test_SimplePump "Tester for the simple pump" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of multi ports + // + SorpLib.Components.Pumps.SimplePump pump( + use_VFlowInput=true, + redeclare final package Medium = Medium) "Simple pump" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + + SorpLib.Components.Fittings.Resistors.LiquidTubeResistance pressureLoss( + positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.PortAInlet, + frictionPressureLoss=true, + fittingPressureLosss=false, + redeclare model PressureLossModel = + Fittings.PressureLossCorrelations.TubeInside.Blasius, + redeclare final package Medium = Medium) "Pressure loss model" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_VFlow( + amplitude=10/1000/60, + f=1/250, + offset=10/1000/60) + "Input signal for volume flow rate" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}}))); + +equation + // + // Connections + // + connect(fs_a.port, pump.port_a) annotation (Line( + points={{-60,0},{-38,0}}, + color={28,108,200}, + thickness=1)); + connect(pressureLoss.port_a, pump.port_b) annotation (Line( + points={{22,0},{-22,0}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, pressureLoss.port_b) annotation (Line( + points={{60,0},{38,0}}, + color={28,108,200}, + thickness=1)); + + connect(input_VFlow.y, pump.V_flow_input) + annotation (Line(points={{-59,-30},{-27,-30},{-27,-8}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the simple pump. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 8, 2024, by Mirko Engelpracht:<br/> + Adaptations due to restructering the library and documentation. + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_SimplePump; diff --git a/SorpLib/Components/Pumps/Tester/package.mo b/SorpLib/Components/Pumps/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..1eeb651dd18d3c0c72fcd3b106ed6470d1b2c7bd --- /dev/null +++ b/SorpLib/Components/Pumps/Tester/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Pumps; +package Tester "Models to test and varify pump models" + extends Modelica.Icons.ExamplesPackage; + + + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented pumps. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Pumps/Tester/package.order b/SorpLib/Components/Pumps/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6fed2df054d0b5e19abd7ee22db02427b1f13c4c --- /dev/null +++ b/SorpLib/Components/Pumps/Tester/package.order @@ -0,0 +1,2 @@ +Test_SimplePump +Test_AffinityPump diff --git a/SorpLib/Components/Pumps/package.mo b/SorpLib/Components/Pumps/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..19a59155361c80e8e4d1dc660b24b4b17d487a18 --- /dev/null +++ b/SorpLib/Components/Pumps/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components; +package Pumps "Pumps to move fluids" + extends SorpLib.Icons.PumpsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains pumps. Ready-to-use models are based on the Modelica +Standard library (MSL). Pumps are used to prescripe a mass or volume flow rate +to a hydraulic fluid. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Pumps; diff --git a/SorpLib/Components/Pumps/package.order b/SorpLib/Components/Pumps/package.order new file mode 100644 index 0000000000000000000000000000000000000000..8a485fb6a6c8910a1349d0c086051b4dd965c72c --- /dev/null +++ b/SorpLib/Components/Pumps/package.order @@ -0,0 +1,4 @@ +BaseClasses +SimplePump +AffinityPump +Tester diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/DensitySensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/DensitySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..659482ce524eda79e36f106628453c2a5277aa50 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/DensitySensor.mo @@ -0,0 +1,70 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model DensitySensor "Density sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialAbsoluteFluidSensor( + final no_components=Medium.nX, + value_initial=1e3); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Set port values + // + valueNonDelayed = Medium.density_phX( + p=port.p, + h=inStream(port.h_outflow), + X=cat(1,inStream(port.Xi_outflow),{1-sum(inStream(port.Xi_outflow))})) + "Density"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This density sensor reads the density in kg/m<sup>3</sup>. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,74},{50,-26}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="ρ"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value,significantDigits=3) + " kg/m³")})); +end DensitySensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/MassFlowRateSensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/MassFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..d1af3a761e8c6ed84906b4805fafa5eb1a5465c8 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/MassFlowRateSensor.mo @@ -0,0 +1,82 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model MassFlowRateSensor "Mass flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialFlowFluidSensor( + final no_components=Medium.nX, + value_initial=0.1); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the sensor setup + // + parameter Boolean flowDirectionAB = true + " = true, if mass flows from port a to b (i.e., positive value); otherwise, + mass flows from port b to a" + annotation (Dialog(tab="General", group="Sensor Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + +equation + // + // Set port values + // + valueNonDelayed = if flowDirectionAB then port_a.m_flow else port_b.m_flow + "Mass flow rate"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass flow rate sensor reads the mass flow rate in kg/s. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + Added functionality and documentation. + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,64},{50,-36}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="ṁ"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value,significantDigits=3) + " kg/s")})); +end MassFlowRateSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/MassFractionSensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/MassFractionSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..cdbbd49a956ae111e82597c45ed2bf9e184f6b1f --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/MassFractionSensor.mo @@ -0,0 +1,78 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model MassFractionSensor "Mass fraction sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialAbsoluteFluidSensor( + final no_components=Medium.nX, + value_initial=0.1); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the sensor setup + // + parameter Integer ind_component(min=1, max=no_components) = 1 + "Index of the component to read" + annotation (Dialog(tab="General", group="Sensor Setup", + enable=(Medium.nX>1)), + Evaluate=true, + HideResult=true); + +equation + // + // Set port values + // + valueNonDelayed = if ind_component < Medium.nX then + inStream(port.Xi_outflow[ind_component]) else 1-sum(inStream(port.Xi_outflow)) + "Mass fraction"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass fraction sensor reads the mass fraction of the specified component in +kg/kg. It is possible to select that the sensor value <i>value</i> is delayed by +using a time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="xi"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value,significantDigits=3) + " kg/kg")})); +end MassFractionSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/MassFractionsSensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/MassFractionsSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..30a8c52fb17d3947952d9d7bbf574da66e7f6850 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/MassFractionsSensor.mo @@ -0,0 +1,175 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model MassFractionsSensor + "Mass fractions sensor" + + // + // Definition of parameters regarding the medium + // + final parameter Integer no_components = Medium.nX + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of setup parameters + // + parameter Boolean useTimeConstant = false + " = true, if time constant is used (i.e., sensor value is returned delayed)" + annotation (Dialog(tab="General", group="Sensor Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + parameter Modelica.Units.SI.Time tau = 1 + "Time constant for delay" + annotation (Dialog(tab="General", group="Sensor Setup", + enable=useTimeConstant)); + + // + // Definition or initialisation parameters + // + parameter Integer initialisationType(min=1, max=3) = 1 + "Initialisation type: Fixed, steady-state, or free" + annotation (Dialog(tab="Initialisation", group="Type", + enable=useTimeConstant), + choices( + choice=1 "Fixed", + choice=2 "Steady-state", + choice=3 "Free")); + + parameter Real[no_components] value_initial= + fill(1/no_components, no_components) + "Initial values of sensor value if it is delayed" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=useTimeConstant)); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of outputs + // + Modelica.Blocks.Interfaces.RealOutput[no_components] value( + start=value_initial) + "Sensor values that might be delayed by a time constant" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,68}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,68}))); + + // + // Definition of variables + // + Real[no_components] valueNonDelayed + "Non-delayed sensor values"; + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid port" + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}), + iconTransformation(extent={{-10,-90},{10,-70}})), + choicesAllMatching=true); + +initial equation + if useTimeConstant then + if initialisationType==1 then + value = value_initial + "Fixed intial values"; + + elseif initialisationType==2 then + der(value) = zeros(no_components) + "Steady-state initialisations"; + + end if; + end if; + +equation + // + // Delay sensor value if necessary + // + if useTimeConstant then + der(value) = (valueNonDelayed .- value) ./ tau + "Delayed sensor values"; + + else + value = valueNonDelayed + "Non-delayed sensor values"; + + end if; + + // + // Set port values + // + port.m_flow = 0 + "Mass flow rate"; + port.h_outflow = 0 + "Specific enthalpy leaving the port: Dummy value"; + port.Xi_outflow = fill(1/no_components, no_components-1) + "Independent mass fractions leaving the port: Dummy value"; + + valueNonDelayed = + cat(1, inStream(port.Xi_outflow), {1-sum(inStream(port.Xi_outflow))}) + "Mass fractions"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass fractions sensor reads all mass fractions in kg/kg. It is possible to +select that the sensor values <i>value</i> are delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces dynamic states variable, it can be used to break +algebraic loops. The non-delayed sensor values can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Ellipse( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), Text( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="xi")})); +end MassFractionsSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/PressureDifferenceSensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/PressureDifferenceSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..94a60955ed0cb2373ff3336d9bfac334203b08d9 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/PressureDifferenceSensor.mo @@ -0,0 +1,80 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model PressureDifferenceSensor "Pressure difference sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialFlowFluidSensor( + final no_components=Medium.nX, + value_initial=0); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the sensor setup + // + parameter Boolean flowDirectionAB = true + " = true, pressure difference is calculated between port a and b (i.e., + positive value); otherwise, pressure difference is claculated between port + b and a" + annotation (Dialog(tab="General", group="Sensor Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + +equation + // + // Set port values + // + valueNonDelayed = if flowDirectionAB then port_a.p-port_b.p else + port_b.p-port_a.p + "Pressure difference"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This pressure difference sensor reads the pressure difference in Pa. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-40,64},{40,-36}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="Δp"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value/100,significantDigits=3) + " mbar")})); +end PressureDifferenceSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/PressureSensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/PressureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..24986943f63cea5a60ad18c67a5bef16ad1b2986 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/PressureSensor.mo @@ -0,0 +1,67 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model PressureSensor "Pressure sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialAbsoluteFluidSensor( + final no_components=Medium.nX, + value_initial=1e5); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Set port values + // + port.p = valueNonDelayed + "Pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This pressure sensor reads the absolute pressure in Pa. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,72},{50,-28}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="p"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value/100,significantDigits=3) + " mbar")})); +end PressureSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/SpecificEnthalpySensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/SpecificEnthalpySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..d1d44e024b1bcef1657bdd861e1c23f7631e3e74 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/SpecificEnthalpySensor.mo @@ -0,0 +1,67 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model SpecificEnthalpySensor "Specific enthalpy sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialAbsoluteFluidSensor( + final no_components=Medium.nX, + value_initial=1e5); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Set port values + // + valueNonDelayed = inStream(port.h_outflow) + "Specific enthalpy"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This specific enthalpy sensor reads the specific enthalpy in J/kg. It is possible +to select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="h"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value/1000,significantDigits=3) + " kJ/kg")})); +end SpecificEnthalpySensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/SpecificEntropySensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/SpecificEntropySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..12589561055a1349603cf5110e33ace929daed8e --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/SpecificEntropySensor.mo @@ -0,0 +1,70 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model SpecificEntropySensor "Specific entropy sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialAbsoluteFluidSensor( + final no_components=Medium.nX, + value_initial=1e3); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Set port values + // + valueNonDelayed = Medium.specificEntropy(Medium.setState_phX( + p=port.p, + h=inStream(port.h_outflow), + X=cat(1,inStream(port.Xi_outflow),{1-sum(inStream(port.Xi_outflow))}))) + "Specific entropy"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This specific entropy sensor reads the specific entropy in J/kg/K. It is possible +to select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,66},{50,-34}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="s"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value,significantDigits=3) + " J/kg/K")})); +end SpecificEntropySensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/TemperatureDifferenceSensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/TemperatureDifferenceSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..d7c282a3cf335eaa5cd7fa35a263caf1239fd54e --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/TemperatureDifferenceSensor.mo @@ -0,0 +1,95 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model TemperatureDifferenceSensor + "Temperature difference sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialFlowFluidSensor( + final no_components=Medium.nX, + value_initial=0); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the sensor setup + // + parameter Boolean flowDirectionAB = true + " = true, temperature difference is calculated between port a and b (i.e., + positive value); otherwise, temperature difference is claculated between port + b and a" + annotation (Dialog(tab="General", group="Sensor Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Temperature T_a = Medium.temperature_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1,inStream(port_a.Xi_outflow),{1-sum(inStream(port_a.Xi_outflow))})) + "Temperature at port a"; + Modelica.Units.SI.Temperature T_b = Medium.temperature_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=cat(1,inStream(port_b.Xi_outflow),{1-sum(inStream(port_b.Xi_outflow))})) + "Temperature at port b"; + +equation + // + // Set port values + // + valueNonDelayed = if flowDirectionAB then T_a-T_b else T_b-T_a + "Temperature difference"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature difference sensor reads the temperature difference in K. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-40,64},{40,-36}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="ΔT"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value,significantDigits=3) + " K")})); +end TemperatureDifferenceSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/TemperatureSensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/TemperatureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..cefb49e9a584146c53324a1315d6fbedd11da3b6 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/TemperatureSensor.mo @@ -0,0 +1,70 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model TemperatureSensor "Temperature sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialAbsoluteFluidSensor( + final no_components=Medium.nX, + value_initial=298.15); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Set port values + // + valueNonDelayed = Medium.temperature_phX( + p=port.p, + h=inStream(port.h_outflow), + X=cat(1,inStream(port.Xi_outflow),{1-sum(inStream(port.Xi_outflow))})) + "Temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature sensor reads the absolute temperature in K. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="T"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value-273.15,significantDigits=3) + " °C")})); +end TemperatureSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/ThermodynamicStateSensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/ThermodynamicStateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..be8feaca490dead6d70be700c42b3fbbb40c7dce --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/ThermodynamicStateSensor.mo @@ -0,0 +1,137 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model ThermodynamicStateSensor + "Thermodynamic state sensor" + + // + // Definition of parameters regarding the medium + // + final parameter Integer no_components = Medium.nX + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p + "Pressure"; + Modelica.Units.SI.Temperature T + "Temperature"; + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy"; + Modelica.Units.SI.SpecificInternalEnergy u + "Specific internal energy"; + Modelica.Units.SI.SpecificEntropy s + "Specific entropy"; + Modelica.Units.SI.SpecificGibbsFreeEnergy g + "Specific free enthalpy (i.e., Gibbs free energy)"; + Modelica.Units.SI.SpecificHelmholtzFreeEnergy a + "Specific free energy (i.e., Helmholts free energy)"; + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid port" + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}), + iconTransformation(extent={{-10,-90},{10,-70}})), + choicesAllMatching=true); + + // + // Definitio of protected variables + // +protected + Medium.ThermodynamicState state = Medium.setState_phX( + p=p, + h=h, + X=cat(1,inStream(port.Xi_outflow),{1-sum(inStream(port.Xi_outflow))})) + "State record"; + +equation + // + // Set port values + // + port.m_flow = 0 + "Mass flow rate"; + port.h_outflow = 0 + "Specific enthalpy leaving the port: Dummy value"; + port.Xi_outflow = fill(1/no_components, no_components-1) + "Independent mass fractions leaving the port: Dummy value"; + + // + // Calculate state variables + // + p = port.p + "Pressure"; + T = Medium.temperature(state=state) + "Temperature"; + v = 1/Medium.density(state=state) + "Specific volume"; + h = inStream(port.h_outflow) + "Specific enthalpy"; + u = h - p*v + "Specific internal energy"; + s = Medium.specificEntropy(state=state) + "Specific entropy"; + g = h - T*s + "Specific free enthalpy (i.e., Gibbs free energy)"; + a = u - T*s + "Specific free energy (i.e., Helmholts free energy)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This thermodynamic state sensor reads all thermodynamic state variables. I.e., +pressure <i>p</i>, temperature <i>T</i>, specific volume <i>v</i>, specific +enthalpy <i>h</i>, specific internal energy <i>u</i>, specific entropy <i>s</i>, +specific free enthalpy (i.e., Gibbs free energy <i>g</i>, and specific free +energy (i.e., Helmholts free energy) <i>a</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Ellipse( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), Text( + extent={{-40,60},{40,-40}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="state")})); +end ThermodynamicStateSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/VolumeFlowRateSensor.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/VolumeFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..ccde68b494d7fd2129b520c959b4fe4a46400ebf --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/VolumeFlowRateSensor.mo @@ -0,0 +1,115 @@ +within SorpLib.Components.Sensors.BaseClasses.FluidMSL; +partial model VolumeFlowRateSensor "Volume flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialFlowFluidSensor( + final no_components=Medium.nX, + value_initial=10/60000); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of parameters regarding the sensor setup + // + parameter Boolean flowDirectionAB = true + " = true, if mass flows from port a to b (i.e., positive value); otherwise, + mass flows from port b to a" + annotation (Dialog(tab="General", group="Sensor Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + + // + // Definition of advanced parameters + // + parameter Modelica.Units.SI.MassFlowRate m_flow_small = 1e-5 + "Mass flow rate used to regulate flow-dependent properties (i.e., density)" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult = true); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Density rho_a = Medium.density_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1,inStream(port_a.Xi_outflow),{1-sum(inStream(port_a.Xi_outflow))})) + "Density at port a"; + Modelica.Units.SI.Density rho_b = Medium.density_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=cat(1,inStream(port_b.Xi_outflow),{1-sum(inStream(port_b.Xi_outflow))})) + "Density at port b"; + Modelica.Units.SI.Density rho = if avoid_events then + SorpLib.Numerics.regStep_noEvent( + x=port_a.m_flow, + y1=rho_a, + y2=rho_b, + x_small=m_flow_small) else + SorpLib.Numerics.regStep( + x=port_a.m_flow, + y1=rho_a, + y2=rho_b, + x_small=m_flow_small) + "Actual density"; + +equation + // + // Set port values + // + valueNonDelayed = if flowDirectionAB then port_a.m_flow/rho else + port_b.m_flow/rho + "Volume flow rate"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This volume flow rate sensor reads the volume flow rate in m<sup>3</sup>/s. It +is possible to select that the sensor value <i>value</i> is delayed by using a +time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,54},{50,-46}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="V̇"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value*60000,significantDigits=3) + " l/min")})); +end VolumeFlowRateSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/package.mo b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..41da62dbd2ddad1e7c6ca73adbceaf94c6314994 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Components.Sensors.BaseClasses; +package FluidMSL "Base models for all fluid sensors based on the MSL" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial fluid sensors, containing fundamental +definitions for sensors. These fluid sensors are based on the open- +source Modelica Standard Library (MSL). The content of this package +is only of interest when adding new sensors to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end FluidMSL; diff --git a/SorpLib/Components/Sensors/BaseClasses/FluidMSL/package.order b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c4626765fe6b3fcadd7a4171f9506d5455fffcc2 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/FluidMSL/package.order @@ -0,0 +1,12 @@ +PressureSensor +TemperatureSensor +DensitySensor +SpecificEnthalpySensor +SpecificEntropySensor +MassFractionSensor +MassFractionsSensor +ThermodynamicStateSensor +MassFlowRateSensor +VolumeFlowRateSensor +PressureDifferenceSensor +TemperatureDifferenceSensor diff --git a/SorpLib/Components/Sensors/BaseClasses/PartialAbsoluteFluidSensor.mo b/SorpLib/Components/Sensors/BaseClasses/PartialAbsoluteFluidSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..cbbb8053977636c28466305df293e544792317b0 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/PartialAbsoluteFluidSensor.mo @@ -0,0 +1,72 @@ +within SorpLib.Components.Sensors.BaseClasses; +partial model PartialAbsoluteFluidSensor + "Base model for all fluid-based absolute sensors" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + extends SorpLib.Components.Sensors.BaseClasses.PartialSensor; + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid port" + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}), + iconTransformation(extent={{-10,-90},{10,-70}})), + choicesAllMatching=true); + +equation + // + // Set port values + // + port.m_flow = 0 + "Mass flow rate"; + port.h_outflow = 0 + "Specific enthalpy leaving the port: Dummy value"; + port.Xi_outflow = fill(1/no_components, no_components-1) + "Independent mass fractions leaving the port: Dummy value"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model is the base model for all fluid-based absolute sensors. It defines +fundamental parameters and variables required by all sensors. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Ellipse( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1)})); +end PartialAbsoluteFluidSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/PartialFlowFluidSensor.mo b/SorpLib/Components/Sensors/BaseClasses/PartialFlowFluidSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..8265ecb03a6857d355436d03f2d9f38ef0837365 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/PartialFlowFluidSensor.mo @@ -0,0 +1,80 @@ +within SorpLib.Components.Sensors.BaseClasses; +partial model PartialFlowFluidSensor + "Base model for all fluid-based flow sensors" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + extends SorpLib.Components.Sensors.BaseClasses.PartialSensor; + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid port a" + annotation (Placement(transformation(extent={{-60,-90},{-40,-70}}), + iconTransformation(extent={{-60,-90},{-40,-70}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid port b" + annotation (Placement(transformation(extent={{40,-90},{60,-70}}), + iconTransformation(extent={{40,-90},{60,-70}})), + choicesAllMatching=true); + +equation + // + // Connections + // + connect(port_a, port_b) + annotation (Line(points={{-50,-80},{50,-80}}, color={0,0,0})); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model is the base model for all fluid-based flow sensors. It defines +fundamental parameters and variables required by all sensors. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + Added functionality and documentation. + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Ellipse( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1)})); +end PartialFlowFluidSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/PartialRelativeFluidSensor.mo b/SorpLib/Components/Sensors/BaseClasses/PartialRelativeFluidSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..ee61b63cd6b4a325ff0a013733a5a49d7cc08f04 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/PartialRelativeFluidSensor.mo @@ -0,0 +1,88 @@ +within SorpLib.Components.Sensors.BaseClasses; +partial model PartialRelativeFluidSensor + "Base model for all fluid-based relative sensors" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + extends SorpLib.Components.Sensors.BaseClasses.PartialSensor; + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid port a" + annotation (Placement(transformation(extent={{-60,-90},{-40,-70}}), + iconTransformation(extent={{-60,-90},{-40,-70}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components) + "Fluid port b" + annotation (Placement(transformation(extent={{40,-90},{60,-70}}), + iconTransformation(extent={{40,-90},{60,-70}})), + choicesAllMatching=true); + +equation + // + // Set port values + // + port_a.m_flow = 0 + "Mass flow rate"; + port_b.m_flow = 0 + "Mass flow rate"; + + port_a.h_outflow = 0 + "Specific enthalpy leaving the port: Dummy value"; + port_b.h_outflow = 0 + "Specific enthalpy leaving the port: Dummy value"; + + port_a.Xi_outflow = fill(1/no_components, no_components-1) + "Independent mass fractions leaving the port: Dummy value"; + port_b.Xi_outflow = fill(1/no_components, no_components-1) + "Independent mass fractions leaving the port: Dummy value"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model is the base model for all fluid-based relative sensors. It defines +fundamental parameters and variables required by all sensors. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Ellipse( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1)})); +end PartialRelativeFluidSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/PartialSensor.mo b/SorpLib/Components/Sensors/BaseClasses/PartialSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..7f852a255bb11c172b548d79792db7cfd71a3a61 --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/PartialSensor.mo @@ -0,0 +1,126 @@ +within SorpLib.Components.Sensors.BaseClasses; +partial model PartialSensor + "Base model for all sensors" + + // + // Definition of setup parameters + // + parameter Boolean useTimeConstant = false + " = true, if time constant is used (i.e., sensor value is returned delayed)" + annotation (Dialog(tab="General", group="Sensor Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + parameter Modelica.Units.SI.Time tau = 1 + "Time constant for delay" + annotation (Dialog(tab="General", group="Sensor Setup", + enable=useTimeConstant)); + + // + // Definition or initialisation parameters + // + parameter Integer initialisationType(min=1, max=3) = 1 + "Initialisation type: Fixed, steady-state, or free" + annotation (Dialog(tab="Initialisation", group="Type", + enable=useTimeConstant), + choices( + choice=1 "Fixed", + choice=2 "Steady-state", + choice=3 "Free")); + + parameter Real value_initial = 1 + "Initial value of sensor value if it is delayed" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=useTimeConstant)); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of outputs + // + Modelica.Blocks.Interfaces.RealOutput value( + start=value_initial) + "Sensor value that might be delayed by a time constant" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,68}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,68}))); + + // + // Definition of variables + // + Real valueNonDelayed + "Non-delayed sensor value"; + +initial equation + if useTimeConstant then + if initialisationType==1 then + value = value_initial + "Fixed intial value"; + + elseif initialisationType==2 then + der(value) = 0 + "Steady-state initialisation"; + + end if; + end if; + +equation + // + // Delay sensor value if necessary + // + if useTimeConstant then + der(value) = (valueNonDelayed - value) / tau + "Delayed sensor value"; + + else + value = valueNonDelayed + "Non-delayed sensor value"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model is the base model for all sensors. It defines fundamental parameters +and variables required by all sensors. It is possible to select that the sensor +value <i>value</i> is delayed by using a time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Ellipse( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1)})); +end PartialSensor; diff --git a/SorpLib/Components/Sensors/BaseClasses/package.mo b/SorpLib/Components/Sensors/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..568f0d0828db2e363aa64db09ecb89f7c1119e9c --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Sensors; +package BaseClasses "Base models for all sensors" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial sensors, containing fundamental definitions +for sensors. The content of this package is only of interest when adding +new sensors to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Components/Sensors/BaseClasses/package.order b/SorpLib/Components/Sensors/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..cca0fc78335f46ae0155137506d5b35c68df212b --- /dev/null +++ b/SorpLib/Components/Sensors/BaseClasses/package.order @@ -0,0 +1,5 @@ +PartialSensor +PartialAbsoluteFluidSensor +PartialRelativeFluidSensor +PartialFlowFluidSensor +FluidMSL diff --git a/SorpLib/Components/Sensors/GasSensors/DensitySensor.mo b/SorpLib/Components/Sensors/GasSensors/DensitySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..060e68d964fe6e3f30fa97f2e423ca8dd453dc37 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/DensitySensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.GasSensors; +model DensitySensor "Density sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.DensitySensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This density sensor reads the density in kg/m<sup>3</sup>. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DensitySensor; diff --git a/SorpLib/Components/Sensors/GasSensors/MassFlowRateSensor.mo b/SorpLib/Components/Sensors/GasSensors/MassFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..bdffbaf0beb97345bf7c8b3f698cc73674b043bb --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/MassFlowRateSensor.mo @@ -0,0 +1,42 @@ +within SorpLib.Components.Sensors.GasSensors; +model MassFlowRateSensor "Mass flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFlowRateSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass flow rate sensor reads the mass flow rate in kg/s. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + Added functionality and documentation. + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={244,125,35}, + thickness=1)})); +end MassFlowRateSensor; diff --git a/SorpLib/Components/Sensors/GasSensors/MassFractionSensor.mo b/SorpLib/Components/Sensors/GasSensors/MassFractionSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..0464baffcab7505d428e4927e3aa100e323c8d2b --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/MassFractionSensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.GasSensors; +model MassFractionSensor "Mass fraction sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFractionSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass fraction sensor reads the mass fraction of the specified component in +kg/kg. It is possible to select that the sensor value <i>value</i> is delayed by +using a time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MassFractionSensor; diff --git a/SorpLib/Components/Sensors/GasSensors/MassFractionsSensor.mo b/SorpLib/Components/Sensors/GasSensors/MassFractionsSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..b354fe02c5cd8cf9561c801890c869c63c36ef51 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/MassFractionsSensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.GasSensors; +model MassFractionsSensor "Mass fractions sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFractionsSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass fractions sensor reads all mass fractions in kg/kg. It is possible to +select that the sensor values <i>value</i> are delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces dynamic states variable, it can be used to break +algebraic loops. The non-delayed sensor values can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MassFractionsSensor; diff --git a/SorpLib/Components/Sensors/GasSensors/PressureDifferenceSensor.mo b/SorpLib/Components/Sensors/GasSensors/PressureDifferenceSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..59cc748ffdb6e02f056333262017f34eb5562be8 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/PressureDifferenceSensor.mo @@ -0,0 +1,39 @@ +within SorpLib.Components.Sensors.GasSensors; +model PressureDifferenceSensor "Pressure difference sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.PressureDifferenceSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This pressure difference sensor reads the pressure difference in Pa. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={244,125,35}, + thickness=1)})); +end PressureDifferenceSensor; diff --git a/SorpLib/Components/Sensors/GasSensors/PressureSensor.mo b/SorpLib/Components/Sensors/GasSensors/PressureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..4b728c942484f09861f4f0be432745ae0495bc63 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/PressureSensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.GasSensors; +model PressureSensor "Pressure sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.PressureSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This pressure sensor reads the pressure temperature in Pa. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PressureSensor; diff --git a/SorpLib/Components/Sensors/GasSensors/SpecificEnthalpySensor.mo b/SorpLib/Components/Sensors/GasSensors/SpecificEnthalpySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..814720ec1e52a4413b5e6219cb021b07fb833bb0 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/SpecificEnthalpySensor.mo @@ -0,0 +1,35 @@ +within SorpLib.Components.Sensors.GasSensors; +model SpecificEnthalpySensor "Specific enthalpy sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.SpecificEnthalpySensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This specific enthalpy sensor reads the specific enthalpy in J/kg. It is possible +to select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SpecificEnthalpySensor; diff --git a/SorpLib/Components/Sensors/GasSensors/SpecificEntropySensor.mo b/SorpLib/Components/Sensors/GasSensors/SpecificEntropySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..db16007cb090846948c2c856c63e04f42c757e36 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/SpecificEntropySensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.GasSensors; +model SpecificEntropySensor "Specific entropy sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.SpecificEntropySensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This specific entropy sensor reads the specific entropy in J/kg/K. It is possible +to select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SpecificEntropySensor; diff --git a/SorpLib/Components/Sensors/GasSensors/TemperatureDifferenceSensor.mo b/SorpLib/Components/Sensors/GasSensors/TemperatureDifferenceSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..247b47aa4c7d28ef9148a175bb6be6ed51e1e6e2 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/TemperatureDifferenceSensor.mo @@ -0,0 +1,39 @@ +within SorpLib.Components.Sensors.GasSensors; +model TemperatureDifferenceSensor "Temperature difference sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.TemperatureDifferenceSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature difference sensor reads the temperature difference in K. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={244,125,35}, + thickness=1)})); +end TemperatureDifferenceSensor; diff --git a/SorpLib/Components/Sensors/GasSensors/TemperatureSensor.mo b/SorpLib/Components/Sensors/GasSensors/TemperatureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..59396f5a73c2f4b935631c6c7c67de8935778c61 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/TemperatureSensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.GasSensors; +model TemperatureSensor "Temperature sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.TemperatureSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature sensor reads the absolute temperature in K. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end TemperatureSensor; diff --git a/SorpLib/Components/Sensors/GasSensors/Tester/Test_GasSensors.mo b/SorpLib/Components/Sensors/GasSensors/Tester/Test_GasSensors.mo new file mode 100644 index 0000000000000000000000000000000000000000..0821f84fa63ddff4febd60dd4dd0ee4c625b2157 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/Tester/Test_GasSensors.mo @@ -0,0 +1,218 @@ +within SorpLib.Components.Sensors.GasSensors.Tester; +model Test_GasSensors "Tester for gas / gas mixture sensors" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true) "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.GasSource fs_b( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + use_TInput=true) "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of sensors + // + SorpLib.Components.Sensors.GasSensors.PressureSensor pSensor + "Pressure sensor" + annotation (Placement(transformation(extent={{-50,-2},{-30,18}}))); + SorpLib.Components.Sensors.GasSensors.TemperatureSensor TSensor_a + "Temperature sensor at port a" + annotation (Placement(transformation(extent={{-50,58},{-30,78}}))); + SorpLib.Components.Sensors.GasSensors.TemperatureSensor TSensor_b( + useTimeConstant=true, tau=10) "Temperature sensor at port b" + annotation (Placement(transformation(extent={{30,-82},{50,-62}}))); + SorpLib.Components.Sensors.GasSensors.DensitySensor rhoSensor_a + "Density sensor at port a" + annotation (Placement(transformation(extent={{-30,58},{-10,78}}))); + SorpLib.Components.Sensors.GasSensors.DensitySensor rhoSensor_b( + useTimeConstant=true, tau=10) "Density sensor at port b" + annotation (Placement(transformation(extent={{10,-82},{30,-62}}))); + SorpLib.Components.Sensors.GasSensors.SpecificEnthalpySensor hSensor_a + "Specific enthalpy sensor at port a" + annotation (Placement(transformation(extent={{-10,58},{10,78}}))); + SorpLib.Components.Sensors.GasSensors.SpecificEnthalpySensor hSensor_b( + useTimeConstant=true, tau=10) "Specific enthalpy sensor at port b" + annotation (Placement(transformation(extent={{-10,-82},{10,-62}}))); + SorpLib.Components.Sensors.GasSensors.SpecificEntropySensor sSensor_a + "Specific entropy sensor at port a" + annotation (Placement(transformation(extent={{10,58},{30,78}}))); + SorpLib.Components.Sensors.GasSensors.SpecificEntropySensor sSensor_b( + useTimeConstant=true, tau=10) "Specific entropy sensor at port b" + annotation (Placement(transformation(extent={{-30,-82},{-10,-62}}))); + SorpLib.Components.Sensors.GasSensors.MassFractionsSensor xiSensor_a + "Mass fractions sensor at port a" + annotation (Placement(transformation(extent={{30,58},{50,78}}))); + SorpLib.Components.Sensors.GasSensors.MassFractionsSensor xiSensor_b( + useTimeConstant=true, tau=10) "Mass fractions sensor at port b" + annotation (Placement(transformation(extent={{-50,-82},{-30,-62}}))); + SorpLib.Components.Sensors.GasSensors.ThermodynamicStateSensor stateSensor_a + "Thermodynamic state sensor at port a" + annotation (Placement(transformation(extent={{50,58},{70,78}}))); + SorpLib.Components.Sensors.GasSensors.ThermodynamicStateSensor stateSensor_b + "Thermodynamic state sensor at port b" + annotation (Placement(transformation(extent={{-70,-82},{-50,-62}}))); + + SorpLib.Components.Sensors.GasSensors.MassFlowRateSensor mFlowSensor + "Mass flow rate sensor" + annotation (Placement(transformation(extent={{-30,-2},{-10,18}}))); + SorpLib.Components.Sensors.GasSensors.VolumeFlowRateSensor VFlowSensor + "Volume flow rate sensor" + annotation (Placement(transformation(extent={{-10,-2},{10,18}}))); + SorpLib.Components.Sensors.GasSensors.PressureDifferenceSensor dpSensor + "Pressure difference sensor" + annotation (Placement(transformation(extent={{10,-2},{30,18}}))); + SorpLib.Components.Sensors.GasSensors.TemperatureDifferenceSensor dTSensor + "Temperature difference sensor" + annotation (Placement(transformation(extent={{30,-2},{50,18}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Ramp input_mFlowVar( + height=60/60, + duration=2500, + offset=-30/60, + startTime=0) + "Ramp to simulate input signal of mass flow rate" + annotation (Placement(transformation(extent={{-100,10},{-80,30}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_TVar_a( + height=80, + duration=2500, + offset=293.15, + startTime=0) + "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{-100,-10},{-80,-30}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_pVar( + height=-(10e5 - 1e3), + duration=2500, + offset=10e5, + startTime=0) + "Ramp to simulate input signal of pressure" + annotation (Placement(transformation(extent={{100,10},{80,30}})), + HideResult=true); + Modelica.Blocks.Sources.Sine input_TVar_b( + amplitude=25, + f=1/250, + offset=273.15 + 50) + "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{100,-10},{80,-30}})), + HideResult=true); + +equation + // + // Connections + // + connect(input_mFlowVar.y, fs_a.m_flow_input) annotation (Line(points={{-79,20}, + {-70,20},{-70,2},{-61.2,2}}, color={0,0,127})); + connect(input_TVar_a.y, fs_a.T_input) annotation (Line(points={{-79,-20},{-70, + -20},{-70,-2},{-61.2,-2}}, color={0,0,127})); + connect(input_pVar.y, fs_b.p_input) annotation (Line(points={{79,20},{70,20},{ + 70,5},{61.2,5}}, color={0,0,127})); + connect(input_TVar_b.y, fs_b.T_input) annotation (Line(points={{79,-20},{70,-20}, + {70,-2},{61.2,-2}}, color={0,0,127})); + + connect(fs_a.port, TSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{-40,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, rhoSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{-20,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, hSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{0,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, sSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{20,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, xiSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{40,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, stateSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{60,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, TSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{40,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, rhoSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{20,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, hSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{0,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, sSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-20,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, xiSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-40,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, stateSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-60,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, pSensor.port) annotation (Line( + points={{-60,0},{-40,0}}, + color={244,125,35}, + thickness=1)); + connect(pSensor.port, mFlowSensor.port_a) annotation (Line( + points={{-40,0},{-25,0}}, + color={244,125,35}, + thickness=1)); + connect(mFlowSensor.port_b, VFlowSensor.port_a) annotation (Line( + points={{-15,0},{-5,0}}, + color={244,125,35}, + thickness=1)); + connect(VFlowSensor.port_b, dpSensor.port_a) annotation (Line( + points={{5,0},{15,0}}, + color={244,125,35}, + thickness=1)); + connect(dpSensor.port_b, dTSensor.port_a) annotation (Line( + points={{25,0},{35,0}}, + color={244,125,35}, + thickness=1)); + connect(dTSensor.port_b, fs_b.port) annotation (Line( + points={{45,0},{60,0}}, + color={244,125,35}, + thickness=1)); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks all gas / gas mixture sensors. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasSensors; diff --git a/SorpLib/Components/Sensors/GasSensors/Tester/package.mo b/SorpLib/Components/Sensors/GasSensors/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..303659c7b416f8d8358ac7c2f4306cbdb17f3a2d --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Sensors.GasSensors; +package Tester "Models to test and varify models for gas / gas mixture sensors" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented gas / gas +mixture sensors. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Sensors/GasSensors/Tester/package.order b/SorpLib/Components/Sensors/GasSensors/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..242ac2d1f8a7733c243a5de43f2c3c18ff8e0cb4 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/Tester/package.order @@ -0,0 +1 @@ +Test_GasSensors diff --git a/SorpLib/Components/Sensors/GasSensors/ThermodynamicStateSensor.mo b/SorpLib/Components/Sensors/GasSensors/ThermodynamicStateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..c3bad4587bb8f66e9e4494a1b70552eb110e16ac --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/ThermodynamicStateSensor.mo @@ -0,0 +1,29 @@ +within SorpLib.Components.Sensors.GasSensors; +model ThermodynamicStateSensor "Thermodynamic state sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.ThermodynamicStateSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This thermodynamic state sensor reads all thermodynamic state variables. I.e., +pressure <i>p</i>, temperature <i>T</i>, specific volume <i>v</i>, specific +enthalpy <i>h</i>, specific internal energy <i>u</i>, specific entropy <i>s</i>, +specific free enthalpy (i.e., Gibbs free energy <i>g</i>, and specific free +energy (i.e., Helmholts free energy) <i>a</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ThermodynamicStateSensor; diff --git a/SorpLib/Components/Sensors/GasSensors/VolumeFlowRateSensor.mo b/SorpLib/Components/Sensors/GasSensors/VolumeFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..5af0e0f0ea4a9cfe2f20cad2fb5a010ddb0e6ba2 --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/VolumeFlowRateSensor.mo @@ -0,0 +1,38 @@ +within SorpLib.Components.Sensors.GasSensors; +model VolumeFlowRateSensor "Volume flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.VolumeFlowRateSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This volume flow rate sensor reads the volume flow rate in m<sup>3</sup>/s. It +is possible to select that the sensor value <i>value</i> is delayed by using a +time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={244,125,35}, + thickness=1)})); +end VolumeFlowRateSensor; diff --git a/SorpLib/Components/Sensors/GasSensors/package.mo b/SorpLib/Components/Sensors/GasSensors/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b1c4f235e01f0fe9e225ad21562ae9d642739c1f --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Components.Sensors; +package GasSensors "Gas / Gas mixture sensors" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains gas / gas mixture sensors based on the open-source Modelica +Standard Library (MSL). It implements absolute sensors, which are only connected to +one fluid port, as well as relative and flow sensors, which are connected between +two fluid ports. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasSensors; diff --git a/SorpLib/Components/Sensors/GasSensors/package.order b/SorpLib/Components/Sensors/GasSensors/package.order new file mode 100644 index 0000000000000000000000000000000000000000..675912cb1c4715f4e8fc7ad71162280999d8969c --- /dev/null +++ b/SorpLib/Components/Sensors/GasSensors/package.order @@ -0,0 +1,13 @@ +PressureSensor +TemperatureSensor +DensitySensor +SpecificEnthalpySensor +SpecificEntropySensor +MassFractionSensor +MassFractionsSensor +ThermodynamicStateSensor +MassFlowRateSensor +VolumeFlowRateSensor +PressureDifferenceSensor +TemperatureDifferenceSensor +Tester diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/DensitySensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/DensitySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..3ee4d4bbd7879175b97ae3dc417f5f478556c949 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/DensitySensor.mo @@ -0,0 +1,35 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model DensitySensor "Density sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.DensitySensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This density sensor reads the density in kg/m<sup>3</sup>. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DensitySensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/MassFlowRateSensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/MassFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..ae0976476c6bd941f4f4fb0353a729ca2fda9ba7 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/MassFlowRateSensor.mo @@ -0,0 +1,43 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model MassFlowRateSensor "Mass flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFlowRateSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass flow rate sensor reads the mass flow rate in kg/s. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + Added functionality and documentation. + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={244,125,35}, + thickness=1)})); +end MassFlowRateSensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/MassFractionSensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/MassFractionSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..c1928bae08d172453cf85acf40a8ab8207005bc5 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/MassFractionSensor.mo @@ -0,0 +1,35 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model MassFractionSensor "Mass fraction sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFractionSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass fraction sensor reads the mass fraction of the specified component in +kg/kg. It is possible to select that the sensor value <i>value</i> is delayed by +using a time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MassFractionSensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/MassFractionsSensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/MassFractionsSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..dd24d3c462b7643f081052d44211a1d9cd96c4d8 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/MassFractionsSensor.mo @@ -0,0 +1,35 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model MassFractionsSensor "Mass fractions sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFractionsSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass fractions sensor reads all mass fractions in kg/kg. It is possible to +select that the sensor values <i>value</i> are delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces dynamic states variable, it can be used to break +algebraic loops. The non-delayed sensor values can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MassFractionsSensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/PressureDifferenceSensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/PressureDifferenceSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..754abecce1b483fcda9b24dc197f26b5af2d0342 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/PressureDifferenceSensor.mo @@ -0,0 +1,40 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model PressureDifferenceSensor "Pressure difference sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.PressureDifferenceSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This pressure difference sensor reads the pressure difference in Pa. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={244,125,35}, + thickness=1)})); +end PressureDifferenceSensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/PressureSensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/PressureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..50c936579a239b27d8c18996d8a7456ca7523bf1 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/PressureSensor.mo @@ -0,0 +1,35 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model PressureSensor "Pressure sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.PressureSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This pressure sensor reads the pressure temperature in Pa. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PressureSensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/RelativeHumiditySensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/RelativeHumiditySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..90ebd8f6044311d03771e2107d06730a08479482 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/RelativeHumiditySensor.mo @@ -0,0 +1,77 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model RelativeHumiditySensor "Relative humidity sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialAbsoluteFluidSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + final no_components=Medium.nX, + value_initial=0.1); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +protected + Medium.ThermodynamicState state = Medium.setState_phX( + p=port.p, + h=inStream(port.h_outflow), + X=cat(1,inStream(port.Xi_outflow),{1-sum(inStream(port.Xi_outflow))})) + "State record"; + +equation + // + // Calculate properties + // + valueNonDelayed = Medium.relativeHumidity(state=state) + "Relative humidity"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This relative humidity sensor reads the relative humidity quality in 0-1. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,74},{50,-26}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="φ"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value*100,significantDigits=3) + " %%rF")})); +end RelativeHumiditySensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/SpecificEnthalpySensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/SpecificEnthalpySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..f11f80894f68e47f1c8c1c2e84cd1a1c3bfe8462 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/SpecificEnthalpySensor.mo @@ -0,0 +1,36 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model SpecificEnthalpySensor "Specific enthalpy sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.SpecificEnthalpySensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This specific enthalpy sensor reads the specific enthalpy in J/kg. It is possible +to select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SpecificEnthalpySensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/SpecificEntropySensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/SpecificEntropySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..88600a5ffd0ea44ec537e637d545e6fb8ffc0e43 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/SpecificEntropySensor.mo @@ -0,0 +1,35 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model SpecificEntropySensor "Specific entropy sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.SpecificEntropySensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This specific entropy sensor reads the specific entropy in J/kg/K. It is possible +to select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SpecificEntropySensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/TemperatureDifferenceSensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/TemperatureDifferenceSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..4d10c74038bd20f9856eb90e7525cce47ebf0737 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/TemperatureDifferenceSensor.mo @@ -0,0 +1,40 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model TemperatureDifferenceSensor "Temperature difference sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.TemperatureDifferenceSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature difference sensor reads the temperature difference in K. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={244,125,35}, + thickness=1)})); +end TemperatureDifferenceSensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/TemperatureSensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/TemperatureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..13a9458b8cffcc5110bbd225f824f58a4de5d50d --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/TemperatureSensor.mo @@ -0,0 +1,35 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model TemperatureSensor "Temperature sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.TemperatureSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature sensor reads the absolute temperature in K. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end TemperatureSensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/Tester/Test_GasSensors.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/Tester/Test_GasSensors.mo new file mode 100644 index 0000000000000000000000000000000000000000..23fab99abaeeb6af6430ddc7ab525ef0a9e81117 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/Tester/Test_GasSensors.mo @@ -0,0 +1,232 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors.Tester; +model Test_GasSensors "Tester for gas / gas mixture sensors" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true) "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource fs_b( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + use_TInput=true) "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of sensors + // + SorpLib.Components.Sensors.GasVaporMixtureSenors.PressureSensor pSensor + "Pressure sensor" + annotation (Placement(transformation(extent={{-50,-2},{-30,18}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.TemperatureSensor TSensor_a + "Temperature sensor at port a" + annotation (Placement(transformation(extent={{-50,58},{-30,78}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.TemperatureSensor TSensor_b( + useTimeConstant=true, tau=10) "Temperature sensor at port b" + annotation (Placement(transformation(extent={{30,-82},{50,-62}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.DensitySensor rhoSensor_a + "Density sensor at port a" + annotation (Placement(transformation(extent={{-30,58},{-10,78}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.DensitySensor rhoSensor_b( + useTimeConstant=true, tau=10) "Density sensor at port b" + annotation (Placement(transformation(extent={{10,-82},{30,-62}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.SpecificEnthalpySensor hSensor_a + "Specific enthalpy sensor at port a" + annotation (Placement(transformation(extent={{-10,58},{10,78}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.SpecificEnthalpySensor hSensor_b( + useTimeConstant=true, tau=10) "Specific enthalpy sensor at port b" + annotation (Placement(transformation(extent={{-10,-82},{10,-62}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.SpecificEntropySensor sSensor_a + "Specific entropy sensor at port a" + annotation (Placement(transformation(extent={{10,58},{30,78}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.SpecificEntropySensor sSensor_b( + useTimeConstant=true, tau=10) "Specific entropy sensor at port b" + annotation (Placement(transformation(extent={{-30,-82},{-10,-62}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.MassFractionsSensor xiSensor_a + "Mass fractions sensor at port a" + annotation (Placement(transformation(extent={{30,58},{50,78}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.MassFractionsSensor xiSensor_b( + useTimeConstant=true, tau=10) "Mass fractions sensor at port b" + annotation (Placement(transformation(extent={{-50,-82},{-30,-62}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.RelativeHumiditySensor phiSensor_a + "Relative humidity sensor at port a" + annotation (Placement(transformation(extent={{50,58},{70,78}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.RelativeHumiditySensor phiSensor_b( + useTimeConstant=true, tau=10) "Relative humidity sensor at port b" + annotation (Placement(transformation(extent={{-70,-82},{-50,-62}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.ThermodynamicStateSensor stateSensor_a + "Thermodynamic state sensor at port a" + annotation (Placement(transformation(extent={{70,58},{90,78}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.ThermodynamicStateSensor stateSensor_b + "Thermodynamic state sensor at port b" + annotation (Placement(transformation(extent={{-90,-82},{-70,-62}}))); + + SorpLib.Components.Sensors.GasVaporMixtureSenors.MassFlowRateSensor mFlowSensor + "Mass flow rate sensor" + annotation (Placement(transformation(extent={{-30,-2},{-10,18}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.VolumeFlowRateSensor VFlowSensor + "Volume flow rate sensor" + annotation (Placement(transformation(extent={{-10,-2},{10,18}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.PressureDifferenceSensor dpSensor + "Pressure difference sensor" + annotation (Placement(transformation(extent={{10,-2},{30,18}}))); + SorpLib.Components.Sensors.GasVaporMixtureSenors.TemperatureDifferenceSensor dTSensor + "Temperature difference sensor" + annotation (Placement(transformation(extent={{30,-2},{50,18}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Ramp input_mFlowVar( + height=60/60, + duration=2500, + offset=-30/60, + startTime=0) + "Ramp to simulate input signal of mass flow rate" + annotation (Placement(transformation(extent={{-100,10},{-80,30}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_TVar_a( + height=80, + duration=2500, + offset=293.15, + startTime=0) + "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{-100,-10},{-80,-30}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_pVar( + height=-(10e5 - 1e3), + duration=2500, + offset=10e5, + startTime=0) + "Ramp to simulate input signal of pressure" + annotation (Placement(transformation(extent={{100,10},{80,30}})), + HideResult=true); + Modelica.Blocks.Sources.Sine input_TVar_b( + amplitude=25, + f=1/250, + offset=273.15 + 50) + "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{100,-10},{80,-30}})), + HideResult=true); + +equation + // + // Connections + // + connect(input_mFlowVar.y, fs_a.m_flow_input) annotation (Line(points={{-79,20}, + {-70,20},{-70,2},{-61.2,2}}, color={0,0,127})); + connect(input_TVar_a.y, fs_a.T_input) annotation (Line(points={{-79,-20},{-70, + -20},{-70,-2},{-61.2,-2}}, color={0,0,127})); + connect(input_pVar.y, fs_b.p_input) annotation (Line(points={{79,20},{70,20},{ + 70,5},{61.2,5}}, color={0,0,127})); + connect(input_TVar_b.y, fs_b.T_input) annotation (Line(points={{79,-20},{70,-20}, + {70,-2},{61.2,-2}}, color={0,0,127})); + + connect(fs_a.port, TSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{-40,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, rhoSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{-20,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, hSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{0,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, sSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{20,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, xiSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{40,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, stateSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{80,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, TSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{40,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, rhoSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{20,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, hSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{0,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, sSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-20,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, xiSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-40,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, stateSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-80,-80}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, pSensor.port) annotation (Line( + points={{-60,0},{-40,0}}, + color={244,125,35}, + thickness=1)); + connect(pSensor.port, mFlowSensor.port_a) annotation (Line( + points={{-40,0},{-25,0}}, + color={244,125,35}, + thickness=1)); + connect(mFlowSensor.port_b, VFlowSensor.port_a) annotation (Line( + points={{-15,0},{-5,0}}, + color={244,125,35}, + thickness=1)); + connect(VFlowSensor.port_b, dpSensor.port_a) annotation (Line( + points={{5,0},{15,0}}, + color={244,125,35}, + thickness=1)); + connect(dpSensor.port_b, dTSensor.port_a) annotation (Line( + points={{25,0},{35,0}}, + color={244,125,35}, + thickness=1)); + connect(dTSensor.port_b, fs_b.port) annotation (Line( + points={{45,0},{60,0}}, + color={244,125,35}, + thickness=1)); + connect(fs_a.port, phiSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{60,60}}, + color={244,125,35}, + thickness=1)); + connect(fs_b.port, phiSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-60,-80}}, + color={244,125,35}, + thickness=1)); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks all gas-vapor mixture sensors. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_GasSensors; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/Tester/package.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..84ce374015a942bf69f77eb61a4330f8503f132e --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +package Tester "Models to test and varify models for gas / gas mixture sensors" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented gas / gas +mixture sensors. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/Tester/package.order b/SorpLib/Components/Sensors/GasVaporMixtureSenors/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..242ac2d1f8a7733c243a5de43f2c3c18ff8e0cb4 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/Tester/package.order @@ -0,0 +1 @@ +Test_GasSensors diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/ThermodynamicStateSensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/ThermodynamicStateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..ee9491bd7a0c07a953a9139397ab0a1e9cc9fe1b --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/ThermodynamicStateSensor.mo @@ -0,0 +1,43 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model ThermodynamicStateSensor "Thermodynamic state sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.ThermodynamicStateSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Definition of variables + // + Real phi(min=0, max=1) + "Relative humidity"; + +equation + // + // Calculate properties + // + phi = Medium.relativeHumidity(state=state) + "Relative humidity"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This thermodynamic state sensor reads all thermodynamic state variables. I.e., +pressure <i>p</i>, temperature <i>T</i>, specific volume <i>v</i>, specific +enthalpy <i>h</i>, specific internal energy <i>u</i>, specific entropy <i>s</i>, +specific free enthalpy (i.e., Gibbs free energy <i>g</i>, and specific free +energy (i.e., Helmholts free energy) <i>a</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ThermodynamicStateSensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/VolumeFlowRateSensor.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/VolumeFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..599a6afb6ea7e2f62bf32ed489cb91334b7864be --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/VolumeFlowRateSensor.mo @@ -0,0 +1,39 @@ +within SorpLib.Components.Sensors.GasVaporMixtureSenors; +model VolumeFlowRateSensor "Volume flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.VolumeFlowRateSensor( + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This volume flow rate sensor reads the volume flow rate in m<sup>3</sup>/s. It +is possible to select that the sensor value <i>value</i> is delayed by using a +time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={244,125,35}, + thickness=1)})); +end VolumeFlowRateSensor; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/package.mo b/SorpLib/Components/Sensors/GasVaporMixtureSenors/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2f06401edde38c3cab4efd84534128d5e884e160 --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Components.Sensors; +package GasVaporMixtureSenors "Gas-vapor mixture sensors" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains gas-vapor mixture sensors based on the open-source Modelica +Standard Library (MSL). It implements absolute sensors, which are only connected to +one fluid port, as well as relative and flow sensors, which are connected between +two fluid ports. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GasVaporMixtureSenors; diff --git a/SorpLib/Components/Sensors/GasVaporMixtureSenors/package.order b/SorpLib/Components/Sensors/GasVaporMixtureSenors/package.order new file mode 100644 index 0000000000000000000000000000000000000000..80ca3f313166d4051e02b93230dbee22fd24d1cf --- /dev/null +++ b/SorpLib/Components/Sensors/GasVaporMixtureSenors/package.order @@ -0,0 +1,14 @@ +PressureSensor +TemperatureSensor +DensitySensor +SpecificEnthalpySensor +SpecificEntropySensor +MassFractionSensor +MassFractionsSensor +RelativeHumiditySensor +ThermodynamicStateSensor +MassFlowRateSensor +VolumeFlowRateSensor +PressureDifferenceSensor +TemperatureDifferenceSensor +Tester diff --git a/SorpLib/Components/Sensors/LiquidSensors/DensitySensor.mo b/SorpLib/Components/Sensors/LiquidSensors/DensitySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..e444ef0f3fc9e3995d08553b8a14d45140d855cd --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/DensitySensor.mo @@ -0,0 +1,33 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model DensitySensor "Density sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.DensitySensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This density sensor reads the density in kg/m<sup>3</sup>. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DensitySensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/MassFlowRateSensor.mo b/SorpLib/Components/Sensors/LiquidSensors/MassFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..250bfb3488adaac371dbcaffba8946c722fb2082 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/MassFlowRateSensor.mo @@ -0,0 +1,41 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model MassFlowRateSensor "Mass flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFlowRateSensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass flow rate sensor reads the mass flow rate in kg/s. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + Added functionality and documentation. + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={28,108,200}, + thickness=1)})); +end MassFlowRateSensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/MassFractionSensor.mo b/SorpLib/Components/Sensors/LiquidSensors/MassFractionSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..b106a022bd6f6c0560e3aa24cf317db76e2e82ab --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/MassFractionSensor.mo @@ -0,0 +1,33 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model MassFractionSensor "Mass fraction sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFractionSensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass fraction sensor reads the mass fraction of the specified component in +kg/kg. It is possible to select that the sensor value <i>value</i> is delayed by +using a time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MassFractionSensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/MassFractionsSensor.mo b/SorpLib/Components/Sensors/LiquidSensors/MassFractionsSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..bd03ffb36174f719174e81790fbe74d697aca5d5 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/MassFractionsSensor.mo @@ -0,0 +1,33 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model MassFractionsSensor "Mass fractions sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFractionsSensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass fractions sensor reads all mass fractions in kg/kg. It is possible to +select that the sensor values <i>value</i> are delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces dynamic states variable, it can be used to break +algebraic loops. The non-delayed sensor values can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MassFractionsSensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/PressureDifferenceSensor.mo b/SorpLib/Components/Sensors/LiquidSensors/PressureDifferenceSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..fdd25db3ffce09c8d9b0099da9ca29941202d82f --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/PressureDifferenceSensor.mo @@ -0,0 +1,38 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model PressureDifferenceSensor "Pressure difference sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.PressureDifferenceSensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This pressure difference sensor reads the pressure difference in Pa. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={28,108,200}, + thickness=1)})); +end PressureDifferenceSensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/PressureSensor.mo b/SorpLib/Components/Sensors/LiquidSensors/PressureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..8fa41045173e519fd6ecb41895b4d4082d8cc01d --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/PressureSensor.mo @@ -0,0 +1,33 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model PressureSensor "Pressure sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.PressureSensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This pressure sensor reads the pressure temperature in Pa. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PressureSensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/SpecificEnthalpySensor.mo b/SorpLib/Components/Sensors/LiquidSensors/SpecificEnthalpySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..ff1a37e7f1c9fa626a3217c4463294a82d122bc1 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/SpecificEnthalpySensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model SpecificEnthalpySensor "Specific enthalpy sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.SpecificEnthalpySensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This specific enthalpy sensor reads the specific enthalpy in J/kg. It is possible +to select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SpecificEnthalpySensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/SpecificEntropySensor.mo b/SorpLib/Components/Sensors/LiquidSensors/SpecificEntropySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..a7852a73d683ba44d6a658615270576d777aa0a6 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/SpecificEntropySensor.mo @@ -0,0 +1,33 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model SpecificEntropySensor "Specific entropy sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.SpecificEntropySensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This specific entropy sensor reads the specific entropy in J/kg/K. It is possible +to select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SpecificEntropySensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/TemperatureDifferenceSensor.mo b/SorpLib/Components/Sensors/LiquidSensors/TemperatureDifferenceSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..1b3b3f3e559c810c6f48a5447622a33385f68657 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/TemperatureDifferenceSensor.mo @@ -0,0 +1,38 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model TemperatureDifferenceSensor "Temperature difference sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.TemperatureDifferenceSensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature difference sensor reads the temperature difference in K. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={28,108,200}, + thickness=1)})); +end TemperatureDifferenceSensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/TemperatureSensor.mo b/SorpLib/Components/Sensors/LiquidSensors/TemperatureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..4833edde29e30b836fe9e7af4b0180741d3b8b91 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/TemperatureSensor.mo @@ -0,0 +1,33 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model TemperatureSensor "Temperature sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.TemperatureSensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature sensor reads the absolute temperature in K. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end TemperatureSensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/Tester/Test_LiquidSensors.mo b/SorpLib/Components/Sensors/LiquidSensors/Tester/Test_LiquidSensors.mo new file mode 100644 index 0000000000000000000000000000000000000000..79b4479996cbdc7bba8109f4a88119a655686834 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/Tester/Test_LiquidSensors.mo @@ -0,0 +1,218 @@ +within SorpLib.Components.Sensors.LiquidSensors.Tester; +model Test_LiquidSensors "Tester for liquid sensors" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true) "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + use_TInput=true) "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of sensors + // + SorpLib.Components.Sensors.LiquidSensors.PressureSensor pSensor + "Pressure sensor" + annotation (Placement(transformation(extent={{-50,-2},{-30,18}}))); + SorpLib.Components.Sensors.LiquidSensors.TemperatureSensor TSensor_a + "Temperature sensor at port a" + annotation (Placement(transformation(extent={{-50,58},{-30,78}}))); + SorpLib.Components.Sensors.LiquidSensors.TemperatureSensor TSensor_b( + useTimeConstant=true, tau=10) "Temperature sensor at port b" + annotation (Placement(transformation(extent={{30,-82},{50,-62}}))); + SorpLib.Components.Sensors.LiquidSensors.DensitySensor rhoSensor_a + "Density sensor at port a" + annotation (Placement(transformation(extent={{-30,58},{-10,78}}))); + SorpLib.Components.Sensors.LiquidSensors.DensitySensor rhoSensor_b( + useTimeConstant=true, tau=10) "Density sensor at port b" + annotation (Placement(transformation(extent={{10,-82},{30,-62}}))); + SorpLib.Components.Sensors.LiquidSensors.SpecificEnthalpySensor hSensor_a + "Specific enthalpy sensor at port a" + annotation (Placement(transformation(extent={{-10,58},{10,78}}))); + SorpLib.Components.Sensors.LiquidSensors.SpecificEnthalpySensor hSensor_b( + useTimeConstant=true, tau=10) "Specific enthalpy sensor at port b" + annotation (Placement(transformation(extent={{-10,-82},{10,-62}}))); + SorpLib.Components.Sensors.LiquidSensors.SpecificEntropySensor sSensor_a + "Specific entropy sensor at port a" + annotation (Placement(transformation(extent={{10,58},{30,78}}))); + SorpLib.Components.Sensors.LiquidSensors.SpecificEntropySensor sSensor_b( + useTimeConstant=true, tau=10) "Specific entropy sensor at port b" + annotation (Placement(transformation(extent={{-30,-82},{-10,-62}}))); + SorpLib.Components.Sensors.LiquidSensors.MassFractionsSensor xiSensor_a + "Mass fractions sensor at port a" + annotation (Placement(transformation(extent={{30,58},{50,78}}))); + SorpLib.Components.Sensors.LiquidSensors.MassFractionsSensor xiSensor_b( + useTimeConstant=true, tau=10) "Mass fractions sensor at port b" + annotation (Placement(transformation(extent={{-50,-82},{-30,-62}}))); + SorpLib.Components.Sensors.LiquidSensors.ThermodynamicStateSensor stateSensor_a + "Thermodynamic state sensor at port a" + annotation (Placement(transformation(extent={{50,58},{70,78}}))); + SorpLib.Components.Sensors.LiquidSensors.ThermodynamicStateSensor stateSensor_b + "Thermodynamic state sensor at port b" + annotation (Placement(transformation(extent={{-70,-82},{-50,-62}}))); + + SorpLib.Components.Sensors.LiquidSensors.MassFlowRateSensor mFlowSensor + "Mass flow rate sensor" + annotation (Placement(transformation(extent={{-30,-2},{-10,18}}))); + SorpLib.Components.Sensors.LiquidSensors.VolumeFlowRateSensor VFlowSensor + "Volume flow rate sensor" + annotation (Placement(transformation(extent={{-10,-2},{10,18}}))); + SorpLib.Components.Sensors.LiquidSensors.PressureDifferenceSensor dpSensor + "Pressure difference sensor" + annotation (Placement(transformation(extent={{10,-2},{30,18}}))); + SorpLib.Components.Sensors.LiquidSensors.TemperatureDifferenceSensor dTSensor + "Temperature difference sensor" + annotation (Placement(transformation(extent={{30,-2},{50,18}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Ramp input_mFlowVar( + height=60/60, + duration=2500, + offset=-30/60, + startTime=0) + "Ramp to simulate input signal of mass flow rate" + annotation (Placement(transformation(extent={{-100,10},{-80,30}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_TVar_a( + height=80, + duration=2500, + offset=293.15, + startTime=0) + "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{-100,-10},{-80,-30}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_pVar( + height=9e5, + duration=2500, + offset=1e5, + startTime=0) + "Ramp to simulate input signal of pressure" + annotation (Placement(transformation(extent={{100,10},{80,30}})), + HideResult=true); + Modelica.Blocks.Sources.Sine input_TVar_b( + amplitude=25, + f=1/250, + offset=273.15 + 50) + "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{100,-10},{80,-30}})), + HideResult=true); + +equation + // + // Connections + // + connect(input_mFlowVar.y, fs_a.m_flow_input) annotation (Line(points={{-79,20}, + {-70,20},{-70,2},{-61.2,2}}, color={0,0,127})); + connect(input_TVar_a.y, fs_a.T_input) annotation (Line(points={{-79,-20},{-70, + -20},{-70,-2},{-61.2,-2}}, color={0,0,127})); + connect(input_pVar.y, fs_b.p_input) annotation (Line(points={{79,20},{70,20},{ + 70,5},{61.2,5}}, color={0,0,127})); + connect(input_TVar_b.y, fs_b.T_input) annotation (Line(points={{79,-20},{70,-20}, + {70,-2},{61.2,-2}}, color={0,0,127})); + + connect(fs_a.port, TSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{-40,60}}, + color={28,108,200}, + thickness=1)); + connect(fs_a.port, rhoSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{-20,60}}, + color={28,108,200}, + thickness=1)); + connect(fs_a.port, hSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{0,60}}, + color={28,108,200}, + thickness=1)); + connect(fs_a.port, sSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{20,60}}, + color={28,108,200}, + thickness=1)); + connect(fs_a.port, xiSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{40,60}}, + color={28,108,200}, + thickness=1)); + connect(fs_a.port, stateSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{60,60}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, TSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{40,-80}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, rhoSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{20,-80}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, hSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{0,-80}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, sSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-20,-80}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, xiSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-40,-80}}, + color={28,108,200}, + thickness=1)); + connect(fs_b.port, stateSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-60,-80}}, + color={28,108,200}, + thickness=1)); + connect(fs_a.port, pSensor.port) annotation (Line( + points={{-60,0},{-40,0}}, + color={28,108,200}, + thickness=1)); + connect(pSensor.port, mFlowSensor.port_a) annotation (Line( + points={{-40,0},{-25,0}}, + color={28,108,200}, + thickness=1)); + connect(mFlowSensor.port_b, VFlowSensor.port_a) annotation (Line( + points={{-15,0},{-5,0}}, + color={28,108,200}, + thickness=1)); + connect(VFlowSensor.port_b, dpSensor.port_a) annotation (Line( + points={{5,0},{15,0}}, + color={28,108,200}, + thickness=1)); + connect(dpSensor.port_b, dTSensor.port_a) annotation (Line( + points={{25,0},{35,0}}, + color={28,108,200}, + thickness=1)); + connect(dTSensor.port_b, fs_b.port) annotation (Line( + points={{45,0},{60,0}}, + color={28,108,200}, + thickness=1)); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks all liquid sensors. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_LiquidSensors; diff --git a/SorpLib/Components/Sensors/LiquidSensors/Tester/package.mo b/SorpLib/Components/Sensors/LiquidSensors/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..4d4d46fc241bd1b1cad3985a975182f70cdb8836 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Sensors.LiquidSensors; +package Tester "Models to test and varify models for liquid sensors" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented liquid +sensors. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Sensors/LiquidSensors/Tester/package.order b/SorpLib/Components/Sensors/LiquidSensors/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..06206939622d4f75c342c52b393185c73d1509b0 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/Tester/package.order @@ -0,0 +1 @@ +Test_LiquidSensors diff --git a/SorpLib/Components/Sensors/LiquidSensors/ThermodynamicStateSensor.mo b/SorpLib/Components/Sensors/LiquidSensors/ThermodynamicStateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..228c16991682df8a006aef2c14d6cba6f2ff8d35 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/ThermodynamicStateSensor.mo @@ -0,0 +1,28 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model ThermodynamicStateSensor "Thermodynamic state sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.ThermodynamicStateSensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This thermodynamic state sensor reads all thermodynamic state variables. I.e., +pressure <i>p</i>, temperature <i>T</i>, specific volume <i>v</i>, specific +enthalpy <i>h</i>, specific internal energy <i>u</i>, specific entropy <i>s</i>, +specific free enthalpy (i.e., Gibbs free energy <i>g</i>, and specific free +energy (i.e., Helmholts free energy) <i>a</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ThermodynamicStateSensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/VolumeFlowRateSensor.mo b/SorpLib/Components/Sensors/LiquidSensors/VolumeFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..c95475b85f4c14175ee594d43cd115de7482767e --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/VolumeFlowRateSensor.mo @@ -0,0 +1,37 @@ +within SorpLib.Components.Sensors.LiquidSensors; +model VolumeFlowRateSensor "Volume flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.VolumeFlowRateSensor( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare replaceable package Medium = + Modelica.Media.Water.WaterIF97_R1pT); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This volume flow rate sensor reads the volume flow rate in m<sup>3</sup>/s. It +is possible to select that the sensor value <i>value</i> is delayed by using a +time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={28,108,200}, + thickness=1)})); +end VolumeFlowRateSensor; diff --git a/SorpLib/Components/Sensors/LiquidSensors/package.mo b/SorpLib/Components/Sensors/LiquidSensors/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f3f590e46eb6fa5a322482e1a5096edc5561e3e8 --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Components.Sensors; +package LiquidSensors "Liquid sensors" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains liquid sensors based on the open-source Modelica Standard +Library (MSL). It implements absolute sensors, which are only connected to one +fluid port, as well as relative and flow sensors, which are connected between +two fluid ports. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end LiquidSensors; diff --git a/SorpLib/Components/Sensors/LiquidSensors/package.order b/SorpLib/Components/Sensors/LiquidSensors/package.order new file mode 100644 index 0000000000000000000000000000000000000000..675912cb1c4715f4e8fc7ad71162280999d8969c --- /dev/null +++ b/SorpLib/Components/Sensors/LiquidSensors/package.order @@ -0,0 +1,13 @@ +PressureSensor +TemperatureSensor +DensitySensor +SpecificEnthalpySensor +SpecificEntropySensor +MassFractionSensor +MassFractionsSensor +ThermodynamicStateSensor +MassFlowRateSensor +VolumeFlowRateSensor +PressureDifferenceSensor +TemperatureDifferenceSensor +Tester diff --git a/SorpLib/Components/Sensors/ThermalSensors/DifferenceTemperatureSensor.mo b/SorpLib/Components/Sensors/ThermalSensors/DifferenceTemperatureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..668a9f4f0dcacd9f023ffb0827077ab2aebfb936 --- /dev/null +++ b/SorpLib/Components/Sensors/ThermalSensors/DifferenceTemperatureSensor.mo @@ -0,0 +1,87 @@ +within SorpLib.Components.Sensors.ThermalSensors; +model DifferenceTemperatureSensor + "Difference temperature sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialSensor( + value_initial=0); + + // + // Definition of parameters + // + parameter Boolean flowDirectionAB = true + " = true, temperature difference is calculated between port a and b (i.e., + positive value); otherwise, temperature difference is claculated between port + b and a" + annotation (Dialog(tab="General", group="Sensor Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + + // + // Definition of ports + // + Basics.Interfaces.HeatPorts.HeatPort_in port_a + annotation (Placement(transformation(extent={{-60,-90},{-40,-70}}), + iconTransformation(extent={{-60,-90},{-40,-70}}))); + + Basics.Interfaces.HeatPorts.HeatPort_out port_b + annotation (Placement(transformation(extent={{40,-90},{60,-70}}), + iconTransformation(extent={{40,-90},{60,-70}}))); + +equation + // + // Set port values + // + valueNonDelayed = if flowDirectionAB then port_a.T-port_b.T else port_b.T-port_a.T + "Temperature"; + + port_a.Q_flow = 0 + "Heat flow rate"; + port_b.Q_flow = 0 + "Heat flow rate"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This difference temperature sensor reads the difference temperature between port +a and b or b and a in K. It is possible to select that the sensor value <i>value</i> +is delayed by using a time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-40,60},{40,-40}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="ΔT"), Line( + points={{-52,-80},{50,-80}}, + color={238,46,47}, + thickness=1), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value,significantDigits=3) + " K")})); +end DifferenceTemperatureSensor; diff --git a/SorpLib/Components/Sensors/ThermalSensors/HeatFlowRateSensor.mo b/SorpLib/Components/Sensors/ThermalSensors/HeatFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..f0e952407c90f82290f733e07283c2d92734e62a --- /dev/null +++ b/SorpLib/Components/Sensors/ThermalSensors/HeatFlowRateSensor.mo @@ -0,0 +1,88 @@ +within SorpLib.Components.Sensors.ThermalSensors; +model HeatFlowRateSensor "Heat flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialSensor( + value_initial=0); + + // + // Definition of parameters + // + parameter Boolean flowDirectionAB = true + " = true, if heat flows from port a to b (i.e., positive value); otherwise, + heat flows from port b to a" + annotation (Dialog(tab="General", group="Sensor Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + + // + // Definition of ports + // + Basics.Interfaces.HeatPorts.HeatPort_in port_a + annotation (Placement(transformation(extent={{-60,-90},{-40,-70}}), + iconTransformation(extent={{-60,-90},{-40,-70}}))); + + Basics.Interfaces.HeatPorts.HeatPort_out port_b + annotation (Placement(transformation(extent={{40,-90},{60,-70}}), + iconTransformation(extent={{40,-90},{60,-70}}))); + +equation + // + // Set port values + // + valueNonDelayed = if flowDirectionAB then port_a.Q_flow else port_b.Q_flow + "Heat flow rate"; + + // + // Connections + // + connect(port_a, port_b) annotation (Line( + points={{-50,-80},{50,-80}}, + color={238,46,47}, + thickness=1)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This heat flow rate sensor reads the heat flow rate at port a or b in W. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,50},{50,-30}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="Q̇"), Line( + points={{-52,-80},{50,-80}}, + color={238,46,47}, + thickness=1), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value,significantDigits=3) + " W")})); +end HeatFlowRateSensor; diff --git a/SorpLib/Components/Sensors/ThermalSensors/TemperatureSensor.mo b/SorpLib/Components/Sensors/ThermalSensors/TemperatureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..51e69dc876cbbe06687c7c4e8f7515ae523e1e6a --- /dev/null +++ b/SorpLib/Components/Sensors/ThermalSensors/TemperatureSensor.mo @@ -0,0 +1,65 @@ +within SorpLib.Components.Sensors.ThermalSensors; +model TemperatureSensor + "Temperature sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialSensor( + value_initial=298.15); + + // + // Definition of ports + // + Basics.Interfaces.HeatPorts.HeatPort_in port + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}), + iconTransformation(extent={{-10,-90},{10,-70}}))); + +equation + // + // Set port values + // + port.T = valueNonDelayed + "Temperature"; + port.Q_flow = 0 + "Heat flow rate"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature sensor reads the absolute temperature in K. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,60},{50,-40}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="T"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value-273.15,significantDigits=3) + " °C")})); +end TemperatureSensor; diff --git a/SorpLib/Components/Sensors/ThermalSensors/Tester/Test_ThermalSensors.mo b/SorpLib/Components/Sensors/ThermalSensors/Tester/Test_ThermalSensors.mo new file mode 100644 index 0000000000000000000000000000000000000000..5a5a0c02123755eb862feac4deee8beb1494a992 --- /dev/null +++ b/SorpLib/Components/Sensors/ThermalSensors/Tester/Test_ThermalSensors.mo @@ -0,0 +1,108 @@ +within SorpLib.Components.Sensors.ThermalSensors.Tester; +model Test_ThermalSensors "Tester for thermal sensors" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + Basics.Sources.Thermal.HeatSource hp_TVar( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=true) + "Heat source with variable temperature" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + Basics.Sources.Thermal.HeatSource hp_QVar( + boundaryType=SorpLib.Choices.BoundaryThermal.HeatFlowRate, + use_QFlowInput=true) + "Heat source with variable heat flow" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of sensors + // + TemperatureSensor TSensor_hp_TVar + "Temperatur sensor at thermal source 'hp_TVar'" + annotation (Placement(transformation(extent={{-50,-2},{-30,18}}))); + DifferenceTemperatureSensor DTSensor "Difference temperature sensor" + annotation (Placement(transformation(extent={{-10,18},{10,38}}))); + HeatFlowRateSensor QFlowSensor "Heat flow rate sensor" + annotation (Placement(transformation(extent={{-10,-2},{10,18}}))); + TemperatureSensor TSensor_hp_QVar(useTimeConstant=true, tau=25, + value_initial=293.15) + "Temperatur sensor at thermal source 'hp_QVar'" + annotation (Placement(transformation(extent={{30,-2},{50,18}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Ramp input_TVar( + height=80, + duration=2500, + offset=293.15, + startTime=0) + "Ramp to simulate input signal of temperrature" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_QVar( + height=2000, + duration=2500, + offset=-1000, + startTime=0) + "Ramp to simulate input signal of heat flow" + annotation (Placement(transformation(extent={{100,-10},{80,10}})), + HideResult=true); + +equation + // + // Connections + // + connect(hp_TVar.port, TSensor_hp_TVar.port) annotation (Line( + points={{-60,0},{-40,0}}, + color={238,46,47}, + thickness=1)); + connect(hp_QVar.port, TSensor_hp_QVar.port) annotation (Line( + points={{60,0},{40,0}}, + color={238,46,47}, + thickness=1)); + connect(hp_TVar.port, QFlowSensor.port_a) annotation (Line( + points={{-60,0},{-5,0}}, + color={238,46,47}, + thickness=1)); + connect(QFlowSensor.port_b, hp_QVar.port) annotation (Line( + points={{5,0},{60,0}}, + color={238,46,47}, + thickness=1)); + connect(hp_TVar.port, DTSensor.port_a) annotation (Line( + points={{-60,0},{-22,0},{-22,20},{-5,20}}, + color={238,46,47}, + thickness=1)); + connect(DTSensor.port_b, hp_QVar.port) annotation (Line( + points={{5,20},{20,20},{20,0},{60,0}}, + color={238,46,47}, + thickness=1)); + + connect(input_TVar.y, hp_TVar.T_input) annotation (Line(points={{-79,0},{-70,0},{ + -70,5.2},{-61,5.2}}, color={0,0,127})); + connect(input_QVar.y, hp_QVar.Q_flow_input) annotation (Line(points={{79,0},{70,0}, + {70,-6},{61,-6},{61,-5}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks all thermal sensors. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_ThermalSensors; diff --git a/SorpLib/Components/Sensors/ThermalSensors/Tester/package.mo b/SorpLib/Components/Sensors/ThermalSensors/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f8cbeb5cd7ebb8472cd261bacfb7d827df1fc9a8 --- /dev/null +++ b/SorpLib/Components/Sensors/ThermalSensors/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Sensors.ThermalSensors; +package Tester "Models to test and varify models for thermal sensors" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented thermal +sensors. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Sensors/ThermalSensors/Tester/package.order b/SorpLib/Components/Sensors/ThermalSensors/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c1325a9e9347bdf510dbc94764431893891c0837 --- /dev/null +++ b/SorpLib/Components/Sensors/ThermalSensors/Tester/package.order @@ -0,0 +1 @@ +Test_ThermalSensors diff --git a/SorpLib/Components/Sensors/ThermalSensors/package.mo b/SorpLib/Components/Sensors/ThermalSensors/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c05fb6d4c0255c9c93e86240576e061cfa5b4b3c --- /dev/null +++ b/SorpLib/Components/Sensors/ThermalSensors/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Sensors; +package ThermalSensors "Thermal sensors" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains thermal sensors. It implements absolute sensors, which +are only connected to one thermal port, as well as relative and flow sensors, +which are connected between two thermal ports. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ThermalSensors; diff --git a/SorpLib/Components/Sensors/ThermalSensors/package.order b/SorpLib/Components/Sensors/ThermalSensors/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bafaf60d4b7c4963dbc004502efc629a8b286ca5 --- /dev/null +++ b/SorpLib/Components/Sensors/ThermalSensors/package.order @@ -0,0 +1,4 @@ +TemperatureSensor +DifferenceTemperatureSensor +HeatFlowRateSensor +Tester diff --git a/SorpLib/Components/Sensors/VLESensors/DensitySensor.mo b/SorpLib/Components/Sensors/VLESensors/DensitySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..d639c42b4f139a92861a10c3087f0b352956a324 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/DensitySensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.VLESensors; +model DensitySensor "Density sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.DensitySensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This density sensor reads the density in kg/m<sup>3</sup>. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DensitySensor; diff --git a/SorpLib/Components/Sensors/VLESensors/MassFlowRateSensor.mo b/SorpLib/Components/Sensors/VLESensors/MassFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..7df52980301cac0c81618538f03c740610762f4d --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/MassFlowRateSensor.mo @@ -0,0 +1,42 @@ +within SorpLib.Components.Sensors.VLESensors; +model MassFlowRateSensor "Mass flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFlowRateSensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass flow rate sensor reads the mass flow rate in kg/s. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + Added functionality and documentation. + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={0,140,72}, + thickness=1)})); +end MassFlowRateSensor; diff --git a/SorpLib/Components/Sensors/VLESensors/MassFractionSensor.mo b/SorpLib/Components/Sensors/VLESensors/MassFractionSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..2396d4eab28f6c0e806fe4043fd1eefb8566f3d4 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/MassFractionSensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.VLESensors; +model MassFractionSensor "Mass fraction sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFractionSensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass fraction sensor reads the mass fraction of the specified component in +kg/kg. It is possible to select that the sensor value <i>value</i> is delayed by +using a time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MassFractionSensor; diff --git a/SorpLib/Components/Sensors/VLESensors/MassFractionsSensor.mo b/SorpLib/Components/Sensors/VLESensors/MassFractionsSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..95a1a6fad2417f50988966602386c719b5145908 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/MassFractionsSensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.VLESensors; +model MassFractionsSensor "Mass fractions sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.MassFractionsSensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This mass fractions sensor reads all mass fractions in kg/kg. It is possible to +select that the sensor values <i>value</i> are delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces dynamic states variable, it can be used to break +algebraic loops. The non-delayed sensor values can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MassFractionsSensor; diff --git a/SorpLib/Components/Sensors/VLESensors/PressureDifferenceSensor.mo b/SorpLib/Components/Sensors/VLESensors/PressureDifferenceSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..64ecafa8bef0250c2df59c4fb02f435f7aa8fb26 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/PressureDifferenceSensor.mo @@ -0,0 +1,39 @@ +within SorpLib.Components.Sensors.VLESensors; +model PressureDifferenceSensor "Pressure difference sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.PressureDifferenceSensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This pressure difference sensor reads the pressure difference in Pa. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={0,140,72}, + thickness=1)})); +end PressureDifferenceSensor; diff --git a/SorpLib/Components/Sensors/VLESensors/PressureSensor.mo b/SorpLib/Components/Sensors/VLESensors/PressureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..76ee4979b3eca8d7569a5337bf99d9c56c880df0 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/PressureSensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.VLESensors; +model PressureSensor "Pressure sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.PressureSensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This pressure sensor reads the pressure temperature in Pa. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PressureSensor; diff --git a/SorpLib/Components/Sensors/VLESensors/SpecificEnthalpySensor.mo b/SorpLib/Components/Sensors/VLESensors/SpecificEnthalpySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..d167a6fd49d158aa59366dffd5e9cf78a164da2f --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/SpecificEnthalpySensor.mo @@ -0,0 +1,35 @@ +within SorpLib.Components.Sensors.VLESensors; +model SpecificEnthalpySensor "Specific enthalpy sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.SpecificEnthalpySensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This specific enthalpy sensor reads the specific enthalpy in J/kg. It is possible +to select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SpecificEnthalpySensor; diff --git a/SorpLib/Components/Sensors/VLESensors/SpecificEntropySensor.mo b/SorpLib/Components/Sensors/VLESensors/SpecificEntropySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..3ffb57615fc07277245407a58b380a05de1ec3fe --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/SpecificEntropySensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.VLESensors; +model SpecificEntropySensor "Specific entropy sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.SpecificEntropySensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This specific entropy sensor reads the specific entropy in J/kg/K. It is possible +to select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SpecificEntropySensor; diff --git a/SorpLib/Components/Sensors/VLESensors/TemperatureDifferenceSensor.mo b/SorpLib/Components/Sensors/VLESensors/TemperatureDifferenceSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..760833b2b9fdddd3d577b3271dd51ab30a2cc6a7 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/TemperatureDifferenceSensor.mo @@ -0,0 +1,39 @@ +within SorpLib.Components.Sensors.VLESensors; +model TemperatureDifferenceSensor "Temperature difference sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.TemperatureDifferenceSensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature difference sensor reads the temperature difference in K. It is +possible to select that the sensor value <i>value</i> is delayed by using a time +constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={0,140,72}, + thickness=1)})); +end TemperatureDifferenceSensor; diff --git a/SorpLib/Components/Sensors/VLESensors/TemperatureSensor.mo b/SorpLib/Components/Sensors/VLESensors/TemperatureSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..39cff04591c52ec35138c7cde9784ccd9c7a689a --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/TemperatureSensor.mo @@ -0,0 +1,34 @@ +within SorpLib.Components.Sensors.VLESensors; +model TemperatureSensor "Temperature sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.TemperatureSensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This temperature sensor reads the absolute temperature in K. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end TemperatureSensor; diff --git a/SorpLib/Components/Sensors/VLESensors/Tester/Test_VLESensors.mo b/SorpLib/Components/Sensors/VLESensors/Tester/Test_VLESensors.mo new file mode 100644 index 0000000000000000000000000000000000000000..e3e9ed0e5d81399f92e83c4ac3bfad048dca6862 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/Tester/Test_VLESensors.mo @@ -0,0 +1,232 @@ +within SorpLib.Components.Sensors.VLESensors.Tester; +model Test_VLESensors "Tester for VLE sensors" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.MassFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=true, + use_TInput=true) "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource fs_b( + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + use_TInput=true) "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of sensors + // + SorpLib.Components.Sensors.VLESensors.PressureSensor pSensor + "Pressure sensor" + annotation (Placement(transformation(extent={{-50,-2},{-30,18}}))); + SorpLib.Components.Sensors.VLESensors.TemperatureSensor TSensor_a + "Temperature sensor at port a" + annotation (Placement(transformation(extent={{-50,58},{-30,78}}))); + SorpLib.Components.Sensors.VLESensors.TemperatureSensor TSensor_b( + useTimeConstant=true, tau=10) "Temperature sensor at port b" + annotation (Placement(transformation(extent={{30,-82},{50,-62}}))); + SorpLib.Components.Sensors.VLESensors.DensitySensor rhoSensor_a + "Density sensor at port a" + annotation (Placement(transformation(extent={{-30,58},{-10,78}}))); + SorpLib.Components.Sensors.VLESensors.DensitySensor rhoSensor_b( + useTimeConstant=true, tau=10) "Density sensor at port b" + annotation (Placement(transformation(extent={{10,-82},{30,-62}}))); + SorpLib.Components.Sensors.VLESensors.SpecificEnthalpySensor hSensor_a + "Specific enthalpy sensor at port a" + annotation (Placement(transformation(extent={{-10,58},{10,78}}))); + SorpLib.Components.Sensors.VLESensors.SpecificEnthalpySensor hSensor_b( + useTimeConstant=true, tau=10) "Specific enthalpy sensor at port b" + annotation (Placement(transformation(extent={{-10,-82},{10,-62}}))); + SorpLib.Components.Sensors.VLESensors.SpecificEntropySensor sSensor_a + "Specific entropy sensor at port a" + annotation (Placement(transformation(extent={{10,58},{30,78}}))); + SorpLib.Components.Sensors.VLESensors.SpecificEntropySensor sSensor_b( + useTimeConstant=true, tau=10) "Specific entropy sensor at port b" + annotation (Placement(transformation(extent={{-30,-82},{-10,-62}}))); + SorpLib.Components.Sensors.VLESensors.MassFractionsSensor xiSensor_a + "Mass fractions sensor at port a" + annotation (Placement(transformation(extent={{30,58},{50,78}}))); + SorpLib.Components.Sensors.VLESensors.MassFractionsSensor xiSensor_b( + useTimeConstant=true, tau=10) "Mass fractions sensor at port b" + annotation (Placement(transformation(extent={{-50,-82},{-30,-62}}))); + SorpLib.Components.Sensors.VLESensors.VaporQualitySensor vaporQuality_a + "Vapor quality sensor at port a" + annotation (Placement(transformation(extent={{50,58},{70,78}}))); + SorpLib.Components.Sensors.VLESensors.VaporQualitySensor vaporQuality_b( + useTimeConstant=true, tau=10) "Vapor quality sensor at port b" + annotation (Placement(transformation(extent={{-70,-82},{-50,-62}}))); + SorpLib.Components.Sensors.VLESensors.ThermodynamicStateSensor stateSensor_a + "Thermodynamic state sensor at port a" + annotation (Placement(transformation(extent={{70,58},{90,78}}))); + SorpLib.Components.Sensors.VLESensors.ThermodynamicStateSensor stateSensor_b + "Thermodynamic state sensor at port b" + annotation (Placement(transformation(extent={{-90,-82},{-70,-62}}))); + + SorpLib.Components.Sensors.VLESensors.MassFlowRateSensor mFlowSensor + "Mass flow rate sensor" + annotation (Placement(transformation(extent={{-30,-2},{-10,18}}))); + SorpLib.Components.Sensors.VLESensors.VolumeFlowRateSensor VFlowSensor + "Volume flow rate sensor" + annotation (Placement(transformation(extent={{-10,-2},{10,18}}))); + SorpLib.Components.Sensors.VLESensors.PressureDifferenceSensor dpSensor + "Pressure difference sensor" + annotation (Placement(transformation(extent={{10,-2},{30,18}}))); + SorpLib.Components.Sensors.VLESensors.TemperatureDifferenceSensor dTSensor + "Temperature difference sensor" + annotation (Placement(transformation(extent={{30,-2},{50,18}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Ramp input_mFlowVar( + height=60/60, + duration=2500, + offset=-30/60, + startTime=0) + "Ramp to simulate input signal of mass flow rate" + annotation (Placement(transformation(extent={{-100,10},{-80,30}})), + HideResult=true); + Modelica.Blocks.Sources.Ramp input_TVar_a( + height=80, + duration=2500, + offset=293.15, + startTime=0) + "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{-100,-10},{-80,-30}})), + HideResult=true); + + Modelica.Blocks.Sources.Ramp input_pVar( + height=-(10e5 - 1e3), + duration=2500, + offset=10e5, + startTime=0) + "Ramp to simulate input signal of pressure" + annotation (Placement(transformation(extent={{100,10},{80,30}})), + HideResult=true); + Modelica.Blocks.Sources.Sine input_TVar_b( + amplitude=25, + f=1/250, + offset=273.15 + 50) + "Ramp to simulate input signal of temperature" + annotation (Placement(transformation(extent={{100,-10},{80,-30}})), + HideResult=true); + +equation + // + // Connections + // + connect(input_mFlowVar.y, fs_a.m_flow_input) annotation (Line(points={{-79,20}, + {-70,20},{-70,2},{-61.2,2}}, color={0,0,127})); + connect(input_TVar_a.y, fs_a.T_input) annotation (Line(points={{-79,-20},{-70, + -20},{-70,-2},{-61.2,-2}}, color={0,0,127})); + connect(input_pVar.y, fs_b.p_input) annotation (Line(points={{79,20},{70,20},{ + 70,5},{61.2,5}}, color={0,0,127})); + connect(input_TVar_b.y, fs_b.T_input) annotation (Line(points={{79,-20},{70,-20}, + {70,-2},{61.2,-2}}, color={0,0,127})); + + connect(fs_a.port, TSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{-40,60}}, + color={0,140,72}, + thickness=1)); + connect(fs_a.port, rhoSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{-20,60}}, + color={0,140,72}, + thickness=1)); + connect(fs_a.port, hSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{0,60}}, + color={0,140,72}, + thickness=1)); + connect(fs_a.port, sSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{20,60}}, + color={0,140,72}, + thickness=1)); + connect(fs_a.port, xiSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{40,60}}, + color={0,140,72}, + thickness=1)); + connect(fs_a.port, stateSensor_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{80,60}}, + color={0,140,72}, + thickness=1)); + connect(fs_b.port, TSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{40,-80}}, + color={0,140,72}, + thickness=1)); + connect(fs_b.port, rhoSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{20,-80}}, + color={0,140,72}, + thickness=1)); + connect(fs_b.port, hSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{0,-80}}, + color={0,140,72}, + thickness=1)); + connect(fs_b.port, sSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-20,-80}}, + color={0,140,72}, + thickness=1)); + connect(fs_b.port, xiSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-40,-80}}, + color={0,140,72}, + thickness=1)); + connect(fs_b.port, stateSensor_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-80,-80}}, + color={0,140,72}, + thickness=1)); + connect(fs_a.port, pSensor.port) annotation (Line( + points={{-60,0},{-40,0}}, + color={0,140,72}, + thickness=1)); + connect(pSensor.port, mFlowSensor.port_a) annotation (Line( + points={{-40,0},{-25,0}}, + color={0,140,72}, + thickness=1)); + connect(mFlowSensor.port_b, VFlowSensor.port_a) annotation (Line( + points={{-15,0},{-5,0}}, + color={0,140,72}, + thickness=1)); + connect(VFlowSensor.port_b, dpSensor.port_a) annotation (Line( + points={{5,0},{15,0}}, + color={0,140,72}, + thickness=1)); + connect(dpSensor.port_b, dTSensor.port_a) annotation (Line( + points={{25,0},{35,0}}, + color={0,140,72}, + thickness=1)); + connect(dTSensor.port_b, fs_b.port) annotation (Line( + points={{45,0},{60,0}}, + color={0,140,72}, + thickness=1)); + + // + // Annotations + // + connect(fs_a.port, vaporQuality_a.port) annotation (Line( + points={{-60,0},{-50,0},{-50,60},{60,60}}, + color={0,140,72}, + thickness=1)); + connect(fs_b.port, vaporQuality_b.port) annotation (Line( + points={{60,0},{50,0},{50,-80},{-60,-80}}, + color={0,140,72}, + thickness=1)); + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks all VLE sensors. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_VLESensors; diff --git a/SorpLib/Components/Sensors/VLESensors/Tester/package.mo b/SorpLib/Components/Sensors/VLESensors/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..06b125aedff5051c48aaab37a9c8183f4e27e06f --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/Tester/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Components.Sensors.VLESensors; +package Tester "Models to test and varify models for VLE sensors" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented VLE sensors. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Sensors/VLESensors/Tester/package.order b/SorpLib/Components/Sensors/VLESensors/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..16d6c0bdcdbde9236eb2aaaf1a212547d00cf229 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/Tester/package.order @@ -0,0 +1 @@ +Test_VLESensors diff --git a/SorpLib/Components/Sensors/VLESensors/ThermodynamicStateSensor.mo b/SorpLib/Components/Sensors/VLESensors/ThermodynamicStateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..9c62726115416520e41189d40703a6f0992dd3f2 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/ThermodynamicStateSensor.mo @@ -0,0 +1,53 @@ +within SorpLib.Components.Sensors.VLESensors; +model ThermodynamicStateSensor "Thermodynamic state sensor" + extends + SorpLib.Components.Sensors.BaseClasses.FluidMSL.ThermodynamicStateSensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Definition of variables + // + Real q(unit="kg/kg") + "Vapor quality"; + +protected + Medium.SaturationProperties sat = Medium.setSat_p(p=p) + "Saturation state"; + + Modelica.Units.SI.SpecificEnthalpy h_sat_liq= + Medium.bubbleEnthalpy(sat=sat) + "Specific bubble point enthalpy"; + Modelica.Units.SI.SpecificEnthalpy h_sat_vap= + Medium.dewEnthalpy(sat=sat) + "Specific dew point enthalpy"; + +equation + // + // Calculate properties + // + q = max(0, min((h - h_sat_liq) / (h_sat_vap - h_sat_liq), 1)) + "Vapor quality"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This thermodynamic state sensor reads all thermodynamic state variables. I.e., +pressure <i>p</i>, temperature <i>T</i>, specific volume <i>v</i>, specific +enthalpy <i>h</i>, specific internal energy <i>u</i>, specific entropy <i>s</i>, +specific free enthalpy (i.e., Gibbs free energy <i>g</i>, and specific free +energy (i.e., Helmholts free energy) <i>a</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ThermodynamicStateSensor; diff --git a/SorpLib/Components/Sensors/VLESensors/VaporQualitySensor.mo b/SorpLib/Components/Sensors/VLESensors/VaporQualitySensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..7cdcea48b750f652e9c7e05da9fa933749535402 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/VaporQualitySensor.mo @@ -0,0 +1,84 @@ +within SorpLib.Components.Sensors.VLESensors; +model VaporQualitySensor + "Vapor quality (i.e., mass fraction) sensor" + extends SorpLib.Components.Sensors.BaseClasses.PartialAbsoluteFluidSensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port, + final no_components=Medium.nX, + value_initial=0.1); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Medium.SaturationProperties sat = Medium.setSat_p(p=port.p) + "Saturation state"; + + Modelica.Units.SI.SpecificEnthalpy h_sat_liq= + Medium.bubbleEnthalpy(sat=sat) + "Specific bubble point enthalpy"; + Modelica.Units.SI.SpecificEnthalpy h_sat_vap= + Medium.dewEnthalpy(sat=sat) + "Specific dew point enthalpy"; + +equation + // + // Set port values + // + valueNonDelayed = max(0, + min((inStream(port.h_outflow) - h_sat_liq) / (h_sat_vap - h_sat_liq), 1)) + "Vapor quality"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This vapor quality sensor reads the vapor quality in kg/kg. It is possible to +select that the sensor value <i>value</i> is delayed by using a time constant +<i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ Line( + points={{0,-40},{0,-80}}, + color={0,0,0}, + thickness=1), Text( + extent={{-50,74},{50,-26}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="q"), + Text( + extent={{10,80},{90,60}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString=String(value,significantDigits=3) + " kg/kg")})); +end VaporQualitySensor; diff --git a/SorpLib/Components/Sensors/VLESensors/VolumeFlowRateSensor.mo b/SorpLib/Components/Sensors/VLESensors/VolumeFlowRateSensor.mo new file mode 100644 index 0000000000000000000000000000000000000000..235e8e739c89574e790e7ff9d4c126c48e051f56 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/VolumeFlowRateSensor.mo @@ -0,0 +1,38 @@ +within SorpLib.Components.Sensors.VLESensors; +model VolumeFlowRateSensor "Volume flow rate sensor" + extends SorpLib.Components.Sensors.BaseClasses.FluidMSL.VolumeFlowRateSensor( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This volume flow rate sensor reads the volume flow rate in m<sup>3</sup>/s. It +is possible to select that the sensor value <i>value</i> is delayed by using a +time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={Line( + points={{-50,-80},{50,-80}}, + color={0,140,72}, + thickness=1)})); +end VolumeFlowRateSensor; diff --git a/SorpLib/Components/Sensors/VLESensors/package.mo b/SorpLib/Components/Sensors/VLESensors/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..44af2ff7bb2920be3144dd5f482fa9e6a97ed6ea --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Components.Sensors; +package VLESensors "VLE sensors" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains VLE sensors based on the open-source Modelica Standard +Library (MSL). It implements absolute sensors, which are only connected to one +fluid port, as well as relative and flow sensors, which are connected between +two fluid ports. +</p> +</html>", revisions="<html> +<ul> + <li> + December 18, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end VLESensors; diff --git a/SorpLib/Components/Sensors/VLESensors/package.order b/SorpLib/Components/Sensors/VLESensors/package.order new file mode 100644 index 0000000000000000000000000000000000000000..fcf07b95475e6754dfa26c0403b29e7b70e19cb8 --- /dev/null +++ b/SorpLib/Components/Sensors/VLESensors/package.order @@ -0,0 +1,14 @@ +PressureSensor +TemperatureSensor +DensitySensor +SpecificEnthalpySensor +SpecificEntropySensor +MassFractionSensor +MassFractionsSensor +VaporQualitySensor +ThermodynamicStateSensor +MassFlowRateSensor +VolumeFlowRateSensor +PressureDifferenceSensor +TemperatureDifferenceSensor +Tester diff --git a/SorpLib/Components/Sensors/package.mo b/SorpLib/Components/Sensors/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..433ee7afdfb57a37a8019a236905fd945ba44ba8 --- /dev/null +++ b/SorpLib/Components/Sensors/package.mo @@ -0,0 +1,203 @@ +within SorpLib.Components; +package Sensors "Ideal sensors to extract signals from interfaces" +extends Modelica.Icons.SensorsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains ideal sensors to measure thermal, thermo-physical, or +hydraulic values. The sensors are ideal, meaning that they do not influence the +model they are connected to. There are three types of sensors. Absolute sensors +are connected to one port and measure state variables. Relative sensors are +connected to two ports and measure the difference between two state variables. +Flow sensors are connected to two ports and measure flow variables. +</p> + +<h4>Main equations</h4> +<p> +It is possible to select that the sensor value <i>value</i> is delayed by using +a time constant <i>tau</i>: +</p> +<pre> + (dvalue/dt) = (valueNonDelayed - value) / tau; +</pre> +<p> +Although this introduces a dynamic state variable, it can be used to break +algebraic loops. The non-delayed sensor value can be accessed via the variable +<i>valueNonDelayed</i>. +</p> + +<h4>Implemented sensors</h4> +<p> +Three sensors are implemented for thermal ports: +</p> +<ul> + <li> + <i>Temperature</i>: Measures the temperature (absolute sensor). + </li> + <li> + <i>Difference temperatures</i>: Measures the difference temperature between two + pots (relative sensor). + </li> + <li> + <i>Heat flow rate</i>: Measures the heat flow rate (flow sensor). + </li> +</ul> +<p> +The following sensors are implemented for fluid ports: +<br/> +</p> +<table border=\"1\" cellspacing=\"0\" cellpadding=\"5\"> + <thead> + <tr> + <th><b>Sensor</b></th> + <th><b>Type</b></th> + <th><b>Liquid</b></th> + <th><b>Gas / Gas mixture</b></th> + <th><b>Gas-vapor mixture</b></th> + <th><b>VLE</b></th> + </tr> + </thead> + <tbody> + <tr> + <td>Pressure</td> + <td>Absolute</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Temperature</td> + <td>Absolute</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Density</td> + <td>Absolute</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Specific enthalpy</td> + <td>Absolute</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Specific entropy</td> + <td>Absolute</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Mass fraction</td> + <td>Absolute</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Mass fractions</td> + <td>Absolute</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Vapor quality</td> + <td>Absolute</td> + <td></td> + <td></td> + <td>X</td> + <td></td> + </tr> + <tr> + <td>Relative humidity</td> + <td>Absolute</td> + <td></td> + <td></td> + <td>X</td> + <td></td> + </tr> + <tr> + <td>Thermodynamic state</td> + <td>Absolute</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Mass flow rate</td> + <td>Flow</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Volume flow rate</td> + <td>Flow</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Pressure difference</td> + <td>Relative</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + <tr> + <td>Temperature difference</td> + <td>Relative</td> + <td>X</td> + <td>X</td> + <td>X</td> + <td>X</td> + </tr> + </tbody> +</table> + +<h4>Typical use</h4> +<p> +The sensors are typically used to measure quantities for controllers or +thermal/fluid boundaries. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useTimeConstant</i>: + The sensor value is returned with a delay by using a time constant. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +The sensors have a dynamic state (i.e., <i>value</i> ) when a time constant is +used. Otherwise, there is no dynamic state. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Sensors; diff --git a/SorpLib/Components/Sensors/package.order b/SorpLib/Components/Sensors/package.order new file mode 100644 index 0000000000000000000000000000000000000000..2af56978e24aacd0439f72e1a555dc66cae5c92b --- /dev/null +++ b/SorpLib/Components/Sensors/package.order @@ -0,0 +1,6 @@ +BaseClasses +ThermalSensors +LiquidSensors +GasSensors +GasVaporMixtureSenors +VLESensors diff --git a/SorpLib/Components/Tubes/BaseClasses/PartialTube.mo b/SorpLib/Components/Tubes/BaseClasses/PartialTube.mo new file mode 100644 index 0000000000000000000000000000000000000000..a4657881ddc2e4b53b30730463336ffe1c85f367 --- /dev/null +++ b/SorpLib/Components/Tubes/BaseClasses/PartialTube.mo @@ -0,0 +1,832 @@ +within SorpLib.Components.Tubes.BaseClasses; +partial model PartialTube "Base model for all tubes" + + // + // Definition of general parameters + // + parameter Integer no_fluidVolumes(min=2)=10 + "Discretization number of fluid volumes" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + parameter Integer no_wallVolumes(min=2)=no_fluidVolumes + "Discretization number of wall volumes (must be a factor of no_fluidVolumes)" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding the geometry + // + replaceable parameter SorpLib.Components.Tubes.Records.GeometryTube geometry + constrainedby SorpLib.Components.Tubes.Records.GeometryTube( + no_fluidVolumes=no_fluidVolumes, + no_wallVolumes=no_wallVolumes) + "Geometry of the tube" + annotation (Dialog(tab = "General", group = "Geoemetry"), + choicesAllMatching = true); + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of models describing transport phenomena + // + parameter Boolean useConductionPerpendicularFlowDirection = true + " = true, if thermal conduction perpendicular to the flow direction is + considered within the wall" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean useConductionFlowDirection = false + " = true, if thermal conduction in the flow direction is considered within + the wall" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcFluidTransportProperties = true + " = true, if any transport model needs fluid or transport properties" + annotation (Dialog(tab="Transport Phenomena", group="General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Integer fluidPropertyPosition = 1 + "Defines the position for fluid porperty calculation is discretization number + is different" + annotation (Dialog(tab="Transport Phenomena", group="General", + enable=no_fluidVolumes<>no_wallVolumes), + choices(choice=1 "First volume near port a", + choice=2 "First volume near port b", + choice=3 "Properties averaged over volumes"), + Evaluate=true, + HideResult=true); + + replaceable model InnerWallThermalConductionPerpendicularFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l/geometry.no_wallVolumes, + d_inner=geometry.d_hydInner, + d_outer=(geometry.d_hydInner + geometry.d_hydOuter)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction perpendicular to the + flow direction within the wall near the fluid" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionPerpendicularFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model OuterWallThermalConductionPerpendicularFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.CylindricalWall + ( l_wall=geometry.l/geometry.no_wallVolumes, + d_inner=(geometry.d_hydInner + geometry.d_hydOuter)/2, + d_outer=geometry.d_hydOuter) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction perpendicular to the + flow direction within the wall near the heat port" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionPerpendicularFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + replaceable model WallThermalConductionFlowDirection = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.Conduction.PlainWall + ( + A_cross=geometry.A_crossWall, + delta_wall=(geometry.l/geometry.no_wallVolumes)/2) + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialConductiveHeatTransferCoefficient + "Heat transfer correlation describing thermal conduction in the flow direction + within the wall" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Conduction", + enable = useConductionFlowDirection), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model FluidThermalConvectionTubeInside = + SorpLib.Components.HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.GnielinskiDittusBoelter + constrainedby + SorpLib.Components.HeatTransfer.BaseClasses.PartialTubeInsideHeatTransferCoefficient + "Heat transfer correlation describing thermal convection at the tube inside + (i.e., form the fluid to the wall)" + annotation (Dialog(tab="Transport Phenomena", group="Thermal Convection"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model PressureDrop = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Konakov + constrainedby + SorpLib.Components.Fittings.BaseClasses.PartialTubeInsidePressureLoss + "Pressure drop correlation describing the pressure drop of the fluid" + annotation (Dialog(tab="Transport Phenomena", group="Pressure Drop"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding start values + // + parameter Modelica.Units.SI.Pressure p_fluidAInitial = 1.25e5 + "Initial value of fluid pressure at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + parameter Modelica.Units.SI.Pressure p_fluidBInitial = 1e5 + "Initial value of fluid pressure at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + + parameter Modelica.Units.SI.Temperature T_fluidAInitial = 283.15 + "Initial value of fluid temperature at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + parameter Modelica.Units.SI.Temperature T_fluidBInitial = 303.15 + "Initial value of fluid temperature at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + + parameter Modelica.Units.SI.Temperature T_wallAInitial = T_fluidAInitial + "Initial value of wall temperature at port a" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + parameter Modelica.Units.SI.Temperature T_wallBInitial = T_fluidBInitial + "Initial value of wall temperature at port b" + annotation (Dialog(tab="Initialisation", group="Initial Values")); + + parameter Modelica.Units.SI.MassFlowRate m_flow_start = 1e-4 + "Start value for mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter SorpLib.Choices.BalanceEquations type_overallMassBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial + "Handling of the overall mass balance and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Choices.BalanceEquations type_independentMassBalances= + type_overallMassBalance + "Handling of independent mass balances and corresponding initialisations" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Choices.BalanceEquations type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial + "Handling of the energy balance and corresponding initialisation" + annotation (Dialog(tab = "Advanced", group = "Conservation Equations"), + Evaluate=true, + HideResult = true); + + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Modelica.Units.SI.MassFlowRate m_flow_small = 1e-4 + "Regularization mass flow rate" + annotation (Dialog(tab="Advanced", group="Numerics")); + parameter Integer noDiff = 2 + "Specification how often transition functions can be differentiated" + annotation(Dialog(tab = "Advanced", group = "Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of protected parameters + // +protected + final parameter Integer factorDiscretization= + integer(max(no_fluidVolumes,no_wallVolumes)/ + min(no_fluidVolumes,no_wallVolumes)) + "Discretization factor" + annotation (Dialog(tab = "General", group = "Discretization"), + Evaluate=true, + HideResult=true); + + final parameter Modelica.Units.SI.Pressure[no_fluidVolumes] p_fluidInitial= + linspace(p_fluidAInitial, p_fluidBInitial, no_fluidVolumes) + "Initial value of fluid pressures for each volume" + annotation (Dialog(tab="Initialisation", group="Initial Values"), + HideResult = true); + final parameter Modelica.Units.SI.Temperature[no_fluidVolumes] T_fluidInitial= + linspace(T_fluidAInitial, T_fluidBInitial, no_fluidVolumes) + "Initial value of fluid temperature for each fluid volume" + annotation (Dialog(tab="Initialisation", group="Initial Values"), + HideResult = true); + final parameter Modelica.Units.SI.Temperature[no_wallVolumes] T_wallInitial= + linspace(T_wallAInitial, T_wallBInitial, no_wallVolumes) + "Initial value of wall temperatures for each wall volume" + annotation (Dialog(tab="Initialisation", group="Initial Values"), + HideResult = true); + + // + // Definition of ports + // +public + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort fp_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=m_flow_start)) + "Fluid port a" + annotation (Placement(transformation(extent={{-110,-10},{-90,10}}), + iconTransformation(extent={{-110,-10},{-90,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort fp_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-m_flow_start)) + "Fluid port b" + annotation (Placement(transformation(extent={{90,-10},{110,10}}), + iconTransformation(extent={{90,-10},{110,10}})), + choicesAllMatching=true); + + SorpLib.Basics.Interfaces.HeatPorts.HeatPort_in[no_wallVolumes] hp_wall + "Heat ports at the wall" + annotation (Placement(transformation(extent={{-10,30},{10,50}}), + iconTransformation(extent={{-10,30},{10,50}}))); + + // + // Definition and instanziation of models + // + replaceable SorpLib.Basics.Volumes.BaseClasses.PartialFluidVolume[no_fluidVolumes] fluidVolumes( + each independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX, + each final calculateAdditionalProperties=calcFluidTransportProperties, + each final useHeatPorts=true, + each final useHeatPortsX=false, + each final useHeatPortsY=true, + each final useHeatPortsZ=false, + final p_initial=p_fluidInitial, + final T_initial=T_fluidInitial, + each final mc_flow_initialX=m_flow_start, + each final type_energyBalance=type_energyBalance, + each final avoid_events=avoid_events, + each final type_overallMassBalance=type_overallMassBalance, + each final nPorts_cfp_xMinus=1, + each final nPorts_cfp_xPlus=1) + "Fluid volumes" + annotation (Placement(transformation(extent={{-10,-74},{10,-54}}))); + + replaceable SorpLib.Basics.Volumes.BaseClasses.PartialVolume[no_wallVolumes] wallVolumes( + each final useHeatPortsX=useConductionFlowDirection, + each final useHeatPortsY=true, + each final useHeatPortsZ=false, + each final type_energyBalance=type_energyBalance, + each final avoid_events=avoid_events) + "Wall volumes" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + SorpLib.Components.HeatTransfer.TubeInsideHeatTransfer[min(no_fluidVolumes,no_wallVolumes)] thermalConvection_fluidToWall( + each final n_a=if no_wallVolumes > no_fluidVolumes then 1 elseif + no_wallVolumes < no_fluidVolumes then factorDiscretization else 1, + each final n_b=if useConductionPerpendicularFlowDirection then 1 elseif + no_wallVolumes > no_fluidVolumes then factorDiscretization elseif + no_wallVolumes < no_fluidVolumes then 1 else 1, + each final geometry=geometry, + each final calculateFluidProperties=calcFluidTransportProperties, + redeclare each final model HeatTransferCoefficient = + FluidThermalConvectionTubeInside, + final fluidProperties=propertiesFluid, + final m_hyd_xMinus=m_flow_hyd_xMinus/geometry.no_hydraulicParallelTubes, + final m_hyd_xPlus=m_flow_hyd_xPlus/geometry.no_hydraulicParallelTubes) + "Thermal convection from fluids to walls" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-42}))); + + SorpLib.Components.HeatTransfer.ConductionHeatTransfer[min(no_fluidVolumes,no_wallVolumes)] thermalConduction_fluidToWall( + each final n_a=1, + each final n_b=if no_wallVolumes < no_fluidVolumes then 1 elseif + no_wallVolumes > no_fluidVolumes then factorDiscretization else 1, + each final calculateFluidProperties=calcFluidTransportProperties, + redeclare each final model HeatTransferCoefficient = + InnerWallThermalConductionPerpendicularFlowDirection, + each final no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes, + final fluidProperties=propertiesWall) if + useConductionPerpendicularFlowDirection + "Thermal conduction from fluids to walls" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,-22}))); + + SorpLib.Components.HeatTransfer.ConductionHeatTransfer[no_wallVolumes] thermalConduction_wallToHeatPort( + each final n_a=1, + each final n_b=1, + each final calculateFluidProperties=calcFluidTransportProperties, + redeclare each final model HeatTransferCoefficient = + OuterWallThermalConductionPerpendicularFlowDirection, + each final no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes) if + useConductionPerpendicularFlowDirection + "Thermal conduction from wall to heat ports" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,24}))); + + SorpLib.Components.HeatTransfer.ConductionHeatTransfer[no_wallVolumes-1] thermalConduction_wall1( + each final n_a=1, + each final n_b=1, + each final calculateFluidProperties=calcFluidTransportProperties, + redeclare each final model HeatTransferCoefficient = + WallThermalConductionFlowDirection, + each final no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes) if + useConductionFlowDirection + "Thermal conduction of the first wall halfs" + annotation (Placement(transformation(extent={{18,-10},{38,10}}))); + + SorpLib.Components.HeatTransfer.ConductionHeatTransfer[no_wallVolumes-1] thermalConduction_wall2( + each final n_a=1, + each final n_b=1, + each final calculateFluidProperties=calcFluidTransportProperties, + redeclare each final model HeatTransferCoefficient = + WallThermalConductionFlowDirection, + each final no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes) if + useConductionFlowDirection + "Thermal conduction of the second wall halfs" + annotation (Placement(transformation(extent={{-38,-10},{-18,10}}))); + + replaceable SorpLib.Components.Fittings.BaseClasses.PartialResistance[no_fluidVolumes-1] pressureDrop( + each final instreamingPropertiesByInput=true, + each final dynamicPressureLoss=false, + each final geodeticPressureLoss=false, + each final frictionPressureLoss=true, + final p_a=fluidVolumes[1:no_fluidVolumes-1].fluidProperties.p, + final T_a=fluidVolumes[1:no_fluidVolumes-1].fluidProperties.T, + final rho_a=1 ./ fluidVolumes[1:no_fluidVolumes-1].fluidProperties.v, + final eta_a=fluidVolumes[1:no_fluidVolumes-1].fluidProperties.eta, + final p_b_ad=fluidVolumes[2:no_fluidVolumes].fluidProperties.p, + final T_b_ad=fluidVolumes[2:no_fluidVolumes].fluidProperties.T, + final rho_b_ad=1 ./ fluidVolumes[2:no_fluidVolumes].fluidProperties.v, + final eta_b_ad=fluidVolumes[2:no_fluidVolumes].fluidProperties.eta, + each final m_flow_start=m_flow_start, + each final avoid_events=avoid_events, + each final m_flow_small=m_flow_small, + each positionFluidProperties=SorpLib.Choices.ResistorFluidProperties.PortAInlet, + each fittingPressureLosss=false) + "Pressure drop between fluid volumes" + annotation (Placement(transformation(extent={{10,-100},{-10,-80}}))); + + // + // Definition of variables + // + Modelica.Units.SI.PressureDifference dp = fp_a.p - fp_b.p + "Pressure difference between port a and b"; + + Modelica.Units.SI.MassFlowRate m_flow_a = fp_a.m_flow + "Mass flow rate at port a"; + Modelica.Units.SI.MassFlowRate m_flow_b = fp_b.m_flow + "Mass flow rate at port b"; + + Modelica.Units.SI.HeatFlowRate DH_flow + "Difference enthalpy flow rate between port a and port b"; + Modelica.Units.SI.HeatFlowRate Q_flow_fluidWall= + sum(thermalConvection_fluidToWall.Q_flow) + "Heat flow rate transferred from the fluid to the eall"; + Modelica.Units.SI.HeatFlowRate Q_flow_wallHP= + -sum(hp_wall.Q_flow) + "Heat flow rate transferred from the wall to the heat port"; + + // + // Definition of protected variables + // +protected + Modelica.Units.SI.Pressure[no_wallVolumes] p_wall + "Pressures used to calculate properteis of the wall"; + + Modelica.Units.SI.MassFlowRate[min(no_fluidVolumes,no_wallVolumes)] m_flow_hyd_xMinus + "Mass flow rates at first volume near port a"; + Modelica.Units.SI.MassFlowRate[min(no_fluidVolumes,no_wallVolumes)] m_flow_hyd_xPlus + "Mass flow rates at first volume near port b"; + + SorpLib.Components.HeatTransfer.Records.FluidProperties[min(no_fluidVolumes,no_wallVolumes)] propertiesWall + "Media properties used to calcualte conductive heat transfer at fluid side"; + SorpLib.Components.HeatTransfer.Records.FluidProperties[min(no_fluidVolumes,no_wallVolumes)] propertiesFluid + "Media properties used to calcualte convective heat transfer at fluid side"; + +equation + // + // Assertations + // + if no_wallVolumes < no_fluidVolumes then + assert(rem(no_fluidVolumes, no_wallVolumes) == 0, + "Number of wall volumes must be a factor of the number of fluid volumes!"); + + elseif no_wallVolumes > no_fluidVolumes then + assert(rem(no_wallVolumes, no_fluidVolumes) == 0, + "Number of wall volumes must be a factor of the number of fluid volumes!"); + + end if; + + // + // Connection of fluid ports + // + connect(fp_a, fluidVolumes[1].cfp_xMinus[1]) annotation (Line(points={{-100,0}, + {-60,0},{-60,-62.2},{-4.2,-62.2}}, color={0,0,0})); + + for i in 1:no_fluidVolumes-1 loop + connect(pressureDrop[i].port_a, fluidVolumes[i].cfp_xPlus[1]) annotation (Line( + points={{8,-90},{20,-90},{20,-62.2},{7.8,-62.2}}, color={0,0,0})); + connect(pressureDrop[i].port_b, fluidVolumes[i+1].cfp_xMinus[1]) annotation (Line( + points={{-8,-90},{-20,-90},{-20,-62.2},{-4.2,-62.2}}, color={0,0,0})); + end for; + + connect(fp_b, fluidVolumes[no_fluidVolumes].cfp_xPlus[1]) annotation (Line(points={{100,0}, + {80,0},{80,-62.2},{7.8,-62.2}}, + color={0,0,0})); + + // + // Connection of heat ports + // + if no_fluidVolumes == no_wallVolumes then + // + // Identical discretization number + // + connect(fluidVolumes.hp_yPlus, thermalConvection_fluidToWall.hp_a[1]) + annotation (Line( + points={{0,-58},{0,-50}}, + color={238,46,47}, + thickness=1)); + + if useConductionPerpendicularFlowDirection then + connect(thermalConvection_fluidToWall.hp_b[1], + thermalConduction_fluidToWall.hp_a[1]) annotation (Line( + points={{0,-34},{0,-30}}, + color={238,46,47}, + thickness=1)); + connect(thermalConduction_fluidToWall.hp_b[1], wallVolumes.hp_yMinus) + annotation (Line( + points={{0,-14},{0,-6}}, + color={238,46,47}, + thickness=1)); + + else + connect(thermalConvection_fluidToWall.hp_b[1], wallVolumes.hp_yMinus); + + end if; + + elseif no_fluidVolumes > no_wallVolumes then + // + // More fluid volumes than wall volumes + // + for i in 1:no_wallVolumes loop + connect(fluidVolumes[1+(i-1)*factorDiscretization:i*factorDiscretization].hp_yPlus, + thermalConvection_fluidToWall[i].hp_a[1:factorDiscretization]) + annotation (Line( + points={{0,-58},{0,-50}}, + color={238,46,47}, + thickness=1)); + end for; + + if useConductionPerpendicularFlowDirection then + connect(thermalConvection_fluidToWall.hp_b[1], + thermalConduction_fluidToWall.hp_a[1]) annotation (Line( + points={{0,-34},{0,-30}}, + color={238,46,47}, + thickness=1)); + connect(thermalConduction_fluidToWall.hp_b[1], wallVolumes.hp_yMinus) + annotation (Line( + points={{0,-14},{0,-6}}, + color={238,46,47}, + thickness=1)); + + else + connect(thermalConvection_fluidToWall.hp_b[1], wallVolumes.hp_yMinus); + + end if; + + else + // + // More wall volumes than fluid volumes + // + connect(fluidVolumes.hp_yPlus, thermalConvection_fluidToWall.hp_a[1]) + annotation (Line( + points={{0,-58},{0,-50}}, + color={238,46,47}, + thickness=1)); + + if useConductionPerpendicularFlowDirection then + connect(thermalConvection_fluidToWall.hp_b[1], + thermalConduction_fluidToWall.hp_a[1]) annotation (Line( + points={{0,-34},{0,-30}}, + color={238,46,47}, + thickness=1)); + + for i in 1:no_fluidVolumes loop + connect(thermalConduction_fluidToWall[i].hp_b[1:factorDiscretization], + wallVolumes[1+(i-1)*factorDiscretization:i*factorDiscretization].hp_yMinus) + annotation (Line( + points={{0,-14},{0,-6}}, + color={238,46,47}, + thickness=1)); + end for; + + else + for i in 1:no_fluidVolumes loop + connect(thermalConvection_fluidToWall[i].hp_b[1:factorDiscretization], + wallVolumes[1+(i-1)*factorDiscretization:i*factorDiscretization].hp_yMinus) + annotation (Line( + points={{0,-34},{0,-6}}, + color={238,46,47}, + thickness=1)); + end for; + end if; + end if; + + if useConductionPerpendicularFlowDirection then + connect(wallVolumes.hp_yPlus, thermalConduction_wallToHeatPort.hp_a[1]) + annotation (Line( + points={{0,6},{0,16}}, + color={238,46,47}, + thickness=1)); + connect(thermalConduction_wallToHeatPort.hp_b[1], hp_wall) annotation (Line( + points={{0,32},{0,40}}, + color={238,46,47}, + thickness=1)); + + else + connect(wallVolumes.hp_yPlus, hp_wall) annotation (Line( + points={{0,6},{0,40}}, + color={238,46,47}, + thickness=1)); + + end if; + + if useConductionFlowDirection then + for i in 1:no_wallVolumes-1 loop + connect(wallVolumes[i].hp_xPlus, thermalConduction_wall1[i].hp_a[1]) + annotation (Line( + points={{6,0},{20,0}}, + color={238,46,47}, + thickness=1)); + connect(thermalConduction_wall1[i].hp_b[1], thermalConduction_wall2[i].hp_a[1]) + annotation (Line( + points={{36,0},{40,0},{40,14},{-40,14},{-40,0},{-36,0}}, + color={238,46,47}, + thickness=1)); + connect(thermalConduction_wall2[i].hp_b[1], wallVolumes[i+1].hp_xMinus) + annotation (Line( + points={{-20,0},{-6,0}}, + color={238,46,47}, + thickness=1)); + end for; + end if; + + // + // Calculate fluid properties + // + if no_fluidVolumes == no_wallVolumes then + // + // Identical discretization number + // + p_wall = fluidVolumes.fluidProperties.p + "Pressures used to calculate properteis of the wall"; + + m_flow_hyd_xMinus = fluidVolumes.fluidProperties.mc_flow_xMinus + "Mass flow rates at first volume near port a"; + m_flow_hyd_xPlus = fluidVolumes.fluidProperties.mc_flow_xPlus + "Mass flow rates at first volume near port b"; + + propertiesFluid.p = fluidVolumes.fluidProperties.p + "Pressures used to calcualte convective heat transfer at fluid side"; + propertiesFluid.T = fluidVolumes.fluidProperties.T + "Temperatures used to calcualte convective heat transfer at fluid side"; + propertiesFluid.rho = 1 ./ fluidVolumes.fluidProperties.v + "Densities used to calcualte convective heat transfer at fluid side"; + propertiesFluid.cp = fluidVolumes.fluidProperties.cp + "Specific heat capacities used to calcualte convective heat transfer at + fluid side"; + propertiesFluid.eta = fluidVolumes.fluidProperties.eta + "Dynamic viscosities used to calcualte convective heat transfer at + fluid side"; + propertiesFluid.lambda = fluidVolumes.fluidProperties.lambda + "Thermal conductivities used to calcualte convective heat transfer at + fluid side"; + + elseif no_fluidVolumes > no_wallVolumes then + // + // More fluid volumes than wall volumes + // + if fluidPropertyPosition == 1 then + for i in 1:no_wallVolumes loop + p_wall[i] = + fluidVolumes[1+(i-1)*factorDiscretization].fluidProperties.p + "Pressures used to calculate properteis of the wall"; + + m_flow_hyd_xMinus[i] = + fluidVolumes[1+(i-1)*factorDiscretization].fluidProperties.mc_flow_xMinus + "Mass flow rates at first volume near port a"; + m_flow_hyd_xMinus[i] = + fluidVolumes[1+(i-1)*factorDiscretization].fluidProperties.mc_flow_xPlus + "Mass flow rates at first volume near port b"; + + propertiesFluid[i].p = + fluidVolumes[1+(i-1)*factorDiscretization].fluidProperties.p + "Pressures used to calcualte convective heat transfer at fluid side"; + propertiesFluid[i].T = + fluidVolumes[1+(i-1)*factorDiscretization].fluidProperties.T + "Temperatures used to calcualte convective heat transfer at fluid side"; + propertiesFluid[i].rho = + 1 ./ fluidVolumes[1+(i-1)*factorDiscretization].fluidProperties.v + "Densities used to calcualte convective heat transfer at fluid side"; + propertiesFluid[i].cp = + fluidVolumes[1+(i-1)*factorDiscretization].fluidProperties.cp + "Specific heat capacities used to calcualte convective heat transfer at + fluid side"; + propertiesFluid[i].eta = + fluidVolumes[1+(i-1)*factorDiscretization].fluidProperties.eta + "Dynamic viscosities used to calcualte convective heat transfer at + fluid side"; + propertiesFluid[i].lambda = + fluidVolumes[1+(i-1)*factorDiscretization].fluidProperties.lambda + "Thermal conductivities used to calcualte convective heat transfer at + fluid side"; + end for; + + elseif fluidPropertyPosition == 2 then + for i in 1:no_wallVolumes loop + p_wall[i] = + fluidVolumes[i*factorDiscretization].fluidProperties.p + "Pressures used to calculate properteis of the wall"; + + m_flow_hyd_xMinus[i] = + fluidVolumes[i*factorDiscretization].fluidProperties.mc_flow_xMinus + "Mass flow rates at first volume near port a"; + m_flow_hyd_xMinus[i] = + fluidVolumes[i*factorDiscretization].fluidProperties.mc_flow_xPlus + "Mass flow rates at first volume near port b"; + + propertiesFluid[i].p = + fluidVolumes[i*factorDiscretization].fluidProperties.p + "Pressures used to calcualte convective heat transfer at fluid side"; + propertiesFluid[i].T = + fluidVolumes[i*factorDiscretization].fluidProperties.T + "Temperatures used to calcualte convective heat transfer at fluid side"; + propertiesFluid[i].rho = + 1 ./ fluidVolumes[i*factorDiscretization].fluidProperties.v + "Densities used to calcualte convective heat transfer at fluid side"; + propertiesFluid[i].cp = + fluidVolumes[i*factorDiscretization].fluidProperties.cp + "Specific heat capacities used to calcualte convective heat transfer at + fluid side"; + propertiesFluid[i].eta = + fluidVolumes[i*factorDiscretization].fluidProperties.eta + "Dynamic viscosities used to calcualte convective heat transfer at + fluid side"; + propertiesFluid[i].lambda = + fluidVolumes[i*factorDiscretization].fluidProperties.lambda + "Thermal conductivities used to calcualte convective heat transfer at + fluid side"; + end for; + + else + for i in 1:no_wallVolumes loop + p_wall[i] = 1/factorDiscretization * + sum(fluidVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].fluidProperties.p) + "Pressures used to calculate properteis of the wall"; + + m_flow_hyd_xMinus[i] = 1/factorDiscretization * + sum(fluidVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].fluidProperties.mc_flow_xMinus) + "Mass flow rates at first volume near port a"; + m_flow_hyd_xMinus[i] = 1/factorDiscretization * + sum(fluidVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].fluidProperties.mc_flow_xPlus) + "Mass flow rates at first volume near port b"; + + propertiesFluid[i].p = 1/factorDiscretization * + sum(fluidVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].fluidProperties.p) + "Pressures used to calcualte convective heat transfer at fluid side"; + propertiesFluid[i].T = 1/factorDiscretization * + sum(fluidVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].fluidProperties.T) + "Temperatures used to calcualte convective heat transfer at fluid side"; + propertiesFluid[i].rho = 1/factorDiscretization * + sum(1 ./ fluidVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].fluidProperties.v) + "Densities used to calcualte convective heat transfer at fluid side"; + propertiesFluid[i].cp = 1/factorDiscretization * + sum(fluidVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].fluidProperties.cp) + "Specific heat capacities used to calcualte convective heat transfer at + fluid side"; + propertiesFluid[i].eta = 1/factorDiscretization * + sum(fluidVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].fluidProperties.eta) + "Dynamic viscosities used to calcualte convective heat transfer at + fluid side"; + propertiesFluid[i].lambda = 1/factorDiscretization * + sum(fluidVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].fluidProperties.lambda) + "Thermal conductivities used to calcualte convective heat transfer at + fluid side"; + end for; + end if; + + else + // + // More wall volumes than fluid volumes + // + for i in 1:no_fluidVolumes loop + p_wall[1+(i-1)*factorDiscretization:i*factorDiscretization] = + fill(fluidVolumes[i].fluidProperties.p, factorDiscretization) + "Pressures used to calculate properteis of the wall"; + end for; + + m_flow_hyd_xMinus = fluidVolumes.fluidProperties.mc_flow_xMinus + "Mass flow rates at first volume near port a"; + m_flow_hyd_xPlus = fluidVolumes.fluidProperties.mc_flow_xPlus + "Mass flow rates at first volume near port b"; + + propertiesFluid.p = fluidVolumes.fluidProperties.p + "Pressures used to calcualte convective heat transfer at fluid side"; + propertiesFluid.T = fluidVolumes.fluidProperties.T + "Temperatures used to calcualte convective heat transfer at fluid side"; + propertiesFluid.rho = 1 ./ fluidVolumes.fluidProperties.v + "Densities used to calcualte convective heat transfer at fluid side"; + propertiesFluid.cp = fluidVolumes.fluidProperties.cp + "Specific heat capacities used to calcualte convective heat transfer at + fluid side"; + propertiesFluid.eta = fluidVolumes.fluidProperties.eta + "Dynamic viscosities used to calcualte convective heat transfer at + fluid side"; + propertiesFluid.lambda = fluidVolumes.fluidProperties.lambda + "Thermal conductivities used to calcualte convective heat transfer at + fluid side"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for all tubes. It defines fundamental parameters, +models, and variables required by all tubes. Models that inherit properties from this +partial model have to redeclare all partial models (i.e., fluid ports, wall volumes, +fluid volumes, and resistors). Morover, the geometry of the redeclared models except +the fluid ports must be correctly set using the geometry record. In addition, the +pressure drop model must be passed to the resistor model, and the inputs 'fluidProperties' +of the conductive heat transfer models must be correctly set using properties of the +wall volumes. +<br/><br/> +The following variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + Difference enthalpy flow rate between port a and port b <i>DH_flow</i>. + </li> + <li> + The fluid property records <i>propertiesWall</i> considering the disretization and + fluid property position. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + January 29, 2024, by Mirko Engelpracht:<br/> + Major adaptations due to restructering of the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle( + extent={{-100,40},{100,-40}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-60,10},{-40,-10}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.None, + fontSize=20, + textString="1"), + Text( + extent={{40,10},{60,-10}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.None, + fontSize=20, + textString="n"), + Line( + points={{0,40},{2,14},{-4,10},{2,-6},{-2,-16},{2,-32},{0,-40}}, + color={0,0,0}, + smooth=Smooth.Bezier)})); +end PartialTube; diff --git a/SorpLib/Components/Tubes/BaseClasses/package.mo b/SorpLib/Components/Tubes/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..df3bc716d4c519037ca7395ad44f9704574144f4 --- /dev/null +++ b/SorpLib/Components/Tubes/BaseClasses/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Tubes; +package BaseClasses "Base models and functions for all tubes" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial tubbes, containing fundamental definitions for tubes. +The content of this package is only of interest when adding new tubes to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Components/Tubes/BaseClasses/package.order b/SorpLib/Components/Tubes/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..f7b4dc6223fad4fac657983d97398c98b3e04dcc --- /dev/null +++ b/SorpLib/Components/Tubes/BaseClasses/package.order @@ -0,0 +1 @@ +PartialTube diff --git a/SorpLib/Components/Tubes/LiquidTube.mo b/SorpLib/Components/Tubes/LiquidTube.mo new file mode 100644 index 0000000000000000000000000000000000000000..28242986524a70a68c77ff1f11ce9798432e4e40 --- /dev/null +++ b/SorpLib/Components/Tubes/LiquidTube.mo @@ -0,0 +1,356 @@ +within SorpLib.Components.Tubes; +model LiquidTube + "Tube model that is one 1D discretized in the flow direction" + extends BaseClasses.PartialTube( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in fp_a, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out fp_b, + final no_components=Medium.nX, + final type_energyBalance= + SorpLib.Choices.BalanceEquations.TransientFixedInitial, + redeclare Basics.Volumes.FluidVolumes.LiquidVolume fluidVolumes( + redeclare each final package Medium = Medium, + redeclare each final Basics.Volumes.Records.VolumeGeometry geometry( + dx=geometry.l/geometry.no_fluidVolumes, + dy=geometry.d_hydInner, + dz=geometry.d_hydInner, + A_xy=-1, + A_xz=geometry.A_heatTransferInner/geometry.no_fluidVolumes, + A_yz=geometry.A_hydCrossInner, + V=geometry.V_inner/geometry.no_fluidVolumes*geometry.no_hydraulicParallelTubes)), + redeclare Basics.Volumes.SolidVolumes.SolidVolume wallVolumes( + redeclare each final WallMaterial solidMedium, + redeclare each final Basics.Volumes.Records.VolumeGeometry geometry( + dx=geometry.l/geometry.no_wallVolumes, + dy=geometry.t_wall/2, + dz=Modelica.Constants.pi*(geometry.d_hydInner + geometry.d_hydOuter)/2, + A_xy=geometry.t_wall*geometry.l/geometry.no_wallVolumes, + A_xz=Modelica.Constants.pi*(geometry.d_hydInner + geometry.d_hydOuter)/2 + *geometry.l/geometry.no_wallVolumes, + A_yz=geometry.A_hydCrossWall/geometry.no_wallVolumes, + V=geometry.V_wall/geometry.no_wallVolumes*geometry.no_hydraulicParallelTubes), + final T_initial=T_wallInitial, + final p = p_wall, + each independentStateVariables=SorpLib.Choices.IndependentVariablesVolume.pTX), + redeclare Fittings.Resistors.LiquidTubeResistance pressureDrop( + redeclare each final model PressureLossModel = PressureDrop, + redeclare each final package Medium = Medium, + redeclare each final SorpLib.Components.Fittings.Records.GeometryTube geometry( + l=geometry.l/(geometry.no_fluidVolumes-1), + d_hyd_a=geometry.d_hydInner, + d_hyd_b=geometry.d_hydInner, + roughness=geometry.roughness, + no_hydraulicParallelFlows=geometry.no_hydraulicParallelTubes)), + thermalConduction_wall1(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wallVolumes[1:no_wallVolumes-1].solidProperties.p, + T=wallVolumes[1:no_wallVolumes-1].solidProperties.T, + rho={1/wallVolumes[i].solidProperties.v for i in 1:no_wallVolumes-1}, + cp=wallVolumes[1:no_wallVolumes-1].solidProperties.c, + eta=0, + lambda=wallVolumes[1:no_wallVolumes-1].solidProperties.lambda)), + thermalConduction_wall2(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wallVolumes[2:no_wallVolumes].solidProperties.p, + T=wallVolumes[2:no_wallVolumes].solidProperties.T, + rho={1/wallVolumes[i].solidProperties.v for i in 2:no_wallVolumes}, + cp=wallVolumes[2:no_wallVolumes].solidProperties.c, + eta=0, + lambda=wallVolumes[2:no_wallVolumes].solidProperties.lambda)), + thermalConduction_wallToHeatPort(final fluidProperties= + SorpLib.Components.HeatTransfer.Records.FluidProperties( + p=wallVolumes[:].solidProperties.p, + T=wallVolumes[:].solidProperties.T, + rho={1/wallVolumes[i].solidProperties.v for i in 1:no_wallVolumes}, + cp=wallVolumes[:].solidProperties.c, + eta=0, + lambda=wallVolumes[:].solidProperties.lambda))); + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + replaceable model WallMaterial = + SorpLib.Media.Solids.MetalsAndMetalAlloys.Copper + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Solid wall medium" + annotation (Dialog(tab="General", group="Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of state records + // + Medium.ThermodynamicState state_a = Medium.setState_phX( + p = fp_a.p, + h = if avoid_events then noEvent(actualStream(fp_a.h_outflow)) else + actualStream(fp_a.h_outflow), + X = if avoid_events then noEvent(actualStream(fp_a.Xi_outflow)) else + actualStream(fp_a.Xi_outflow)) + "Record describing current state properties at port a"; + Medium.ThermodynamicState state_b = Medium.setState_phX( + p = fp_b.p, + h = if avoid_events then noEvent(actualStream(fp_b.h_outflow)) else + actualStream(fp_b.h_outflow), + X = if avoid_events then noEvent(actualStream(fp_b.Xi_outflow)) else + actualStream(fp_b.Xi_outflow)) + "Record describing current state properties at port b"; + +equation + // + // Calculate difference enthalpy stream + // + DH_flow = m_flow_a * Medium.specificEnthalpy(state=state_a) + + m_flow_a * Medium.specificEnthalpy(state=state_b) + "Difference enthalpy flow rate between port a and port b"; + + // + // Calculate fluid properties + // + if no_fluidVolumes == no_wallVolumes then + // + // Identical discretization number + // + propertiesWall.p = wallVolumes.solidProperties.p + "Pressures used to calcualte conductive heat transfer at fluid side"; + propertiesWall.T = wallVolumes.solidProperties.T + "Temperatures used to calcualte conductive heat transfer at fluid side"; + propertiesWall.rho = 1 ./ wallVolumes.solidProperties.v + "Densities used to calcualte conductive heat transfer at fluid side"; + propertiesWall.cp = wallVolumes.solidProperties.c + "Specific heat capacities used to calcualte conductive heat transfer at + fluid side"; + propertiesWall.eta = zeros(no_wallVolumes) + "Dynamic viscosities used to calcualte conductive heat transfer at + fluid side"; + propertiesWall.lambda = wallVolumes.solidProperties.lambda + "Thermal conductivities used to calcualte conductive heat transfer at + fluid side"; + + elseif no_fluidVolumes > no_wallVolumes then + // + // More fluid volumes than wall volumes + // + propertiesWall.p = wallVolumes.solidProperties.p + "Pressures used to calcualte conductive heat transfer at fluid side"; + propertiesWall.T = wallVolumes.solidProperties.T + "Temperatures used to calcualte conductive heat transfer at fluid side"; + propertiesWall.rho = 1 ./ wallVolumes.solidProperties.v + "Densities used to calcualte conductive heat transfer at fluid side"; + propertiesWall.cp = wallVolumes.solidProperties.c + "Specific heat capacities used to calcualte conductive heat transfer at + fluid side"; + propertiesWall.eta = zeros(no_wallVolumes) + "Dynamic viscosities used to calcualte conductive heat transfer at + fluid side"; + propertiesWall.lambda = wallVolumes.solidProperties.lambda + "Thermal conductivities used to calcualte conductive heat transfer at + fluid side"; + + else + // + // More wall volumes than fluid volumes + // + if fluidPropertyPosition == 1 then + for i in 1:no_fluidVolumes loop + propertiesWall[i].p = + wallVolumes[1+(i-1)*factorDiscretization].solidProperties.p + "Pressures used to calcualte conductive heat transfer at fluid side"; + propertiesWall[i].T = + wallVolumes[1+(i-1)*factorDiscretization].solidProperties.T + "Temperatures used to calcualte conductive heat transfer at fluid side"; + propertiesWall[i].rho = + 1 ./ wallVolumes[1+(i-1)*factorDiscretization].solidProperties.v + "Densities used to calcualte conductive heat transfer at fluid side"; + propertiesWall[i].cp = + wallVolumes[1+(i-1)*factorDiscretization].solidProperties.c + "Specific heat capacities used to calcualte conductive heat transfer at + fluid side"; + propertiesWall[i].eta = 0 + "Dynamic viscosities used to calcualte conductive heat transfer at + fluid side"; + propertiesWall[i].lambda = + wallVolumes[1+(i-1)*factorDiscretization].solidProperties.lambda + "Thermal conductivities used to calcualte conductive heat transfer at + fluid side"; + end for; + + elseif fluidPropertyPosition == 2 then + for i in 1:no_fluidVolumes loop + propertiesWall[i].p = + wallVolumes[i*factorDiscretization].solidProperties.p + "Pressures used to calcualte conductive heat transfer at fluid side"; + propertiesWall[i].T = + wallVolumes[i*factorDiscretization].solidProperties.T + "Temperatures used to calcualte conductive heat transfer at fluid side"; + propertiesWall[i].rho = + 1 ./ wallVolumes[i*factorDiscretization].solidProperties.v + "Densities used to calcualte conductive heat transfer at fluid side"; + propertiesWall[i].cp = + wallVolumes[i*factorDiscretization].solidProperties.c + "Specific heat capacities used to calcualte conductive heat transfer at + fluid side"; + propertiesWall[i].eta = 0 + "Dynamic viscosities used to calcualte conductive heat transfer at + fluid side"; + propertiesWall[i].lambda = + wallVolumes[i*factorDiscretization].solidProperties.lambda + "Thermal conductivities used to calcualte conductive heat transfer at + fluid side"; + end for; + + else + for i in 1:no_fluidVolumes loop + propertiesWall[i].p = 1/factorDiscretization * + sum(wallVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].solidProperties.p) + "Pressures used to calcualte conductive heat transfer at fluid side"; + propertiesWall[i].T = 1/factorDiscretization * + sum(wallVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].solidProperties.T) + "Temperatures used to calcualte conductive heat transfer at fluid side"; + propertiesWall[i].rho = 1/factorDiscretization * + sum(1 ./ wallVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].solidProperties.v) + "Densities used to calcualte conductive heat transfer at fluid side"; + propertiesWall[i].cp = 1/factorDiscretization * + sum(wallVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].solidProperties.c) + "Specific heat capacities used to calcualte conductive heat transfer at + fluid side"; + propertiesWall[i].eta = 0 + "Dynamic viscosities used to calcualte conductive heat transfer at + fluid side"; + propertiesWall[i].lambda = 1/factorDiscretization * + sum(wallVolumes[1+(i-1)*factorDiscretization: + i*factorDiscretization].solidProperties.lambda) + "Thermal conductivities used to calcualte conductive heat transfer at + fluid side"; + end for; + end if; + end if; + + // + // Annotations + // + + annotation (Documentation(revisions="<html> +<ul> + <li> + January 29, 2024, by Mirko Engelpracht:<br/> + Major adaptations due to restructering of the library and documentation. + </li> + <li> + January 14, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +The tube model is 1D-discretized in axial direction via an upwing discretization +scheme. It models the liquid flow through a pipe or a bunch of parallel pipes, +considering the friction-based pressure drop and heat transfer between the fluid +and wall. By design, the tube uses circular cross-sectional areas, but non-circular +cross-sectional areas can be used via appropriate hydraulic geometry parameter. +</p> + +<h4>Main equations</h4> +<p> +The tube model has a steady-state/transient mass balance for the liquid, and +a transient energy balance for the liquid and wall. For a detailed documentation, +see +<a href=\"Modelica://SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume\">SorpLib.Basics.Volumes.FluidVolumes.LiquidVolume</a> +and +<a href=\"Modelica://SorpLib.Basics.Volumes.SolidVolumes.SolidVolume\">SorpLib.Basics.Volumes.SolidVolumes.SolidVolume</a>. +<br/<br/> +The fluid volumes are coupled to each other via a hydraulic resistor, which +allows to consider different pressure drop correlations. For a detailed documentation, +see +<a href=\"Modelica://SorpLib.Components.Fittings.Resistors.LiquidTubeResistance\">SorpLib.Components.Fittings.Resistors.LiquidTubeResistance</a>. +<br/<br/> +The fluid and wall volumes are coupled via a heat transfer model, describing the +convective heat transfer fluid at the tube side. For a detailed documentation, see +<a href=\"Modelica://SorpLib.Components.HeatTransfer.TubeInsideHeatTransfer\">SorpLib.Components.HeatTransfer.TubeInsideHeatTransfer</a>. +<br/<br/> +Moreover, +<a href=\"Modelica://SorpLib.Components.HeatTransfer.ConductionHeatTransfer\">conductive heat transfer</a> +can be considered within the wall. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Constant volumes within the control volumes + </li> + <li> + Homogenous properties within the control volumes + </li> +</ul> + +<h4>Typical use</h4> +<p> +The tube model is typically used to model tubes within heat exchangers, such as +evaporators, condensers, or adsorbers. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>useConductionPerpendicularFlowDirection</i>: + Defines if conductive heat transfer perpendicular to the flow direction + is considered within the wall. + </li> + <li> + <i>useConductionFlowDirection</i>: + Defines if conductive heat transfer in the flow direction is considered + within the wall. + </li> + <li> + <i>calcFluidTransportProperties</i>: + Defines if fluid and transport properties are required for transport + phenomena. + </li> + <br/> + <li> + <i>type_overallMassBalance</i>: + Defines the type of the overall mass balance. + </li> + <li> + <i>type_independentMassBalances</i>: + Defines the type of the independent mass balances. + </li> + <li> + <i>type_energyBalance</i>: + Defines the type of the energy balance. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +This model has three dynamic state when using default options: +</p> +<ul> + <li> + Fluid pressure <i>p<sub>liq</sub></i>, fluid temperature <i>T<sub>liq</sub></i>, and wall temperature <i>T<sub>wall</sub></i> + </li> +</ul> +<p> +Note that this model does not have the pressure <i>p</i> as dynamic state if the +fluid medium is a single state model. +</p> +</html>")); +end LiquidTube; diff --git a/SorpLib/Components/Tubes/Records/GeometryTube.mo b/SorpLib/Components/Tubes/Records/GeometryTube.mo new file mode 100644 index 0000000000000000000000000000000000000000..b9bf46171ff0250f822da65f82fdb65b263ae0f8 --- /dev/null +++ b/SorpLib/Components/Tubes/Records/GeometryTube.mo @@ -0,0 +1,127 @@ +within SorpLib.Components.Tubes.Records; +record GeometryTube + "This record contains the geometry of tubes" + extends Modelica.Icons.Record; + + // + // Definition of parameters regarding the disretization + // + parameter Integer no_fluidVolumes(min=1) = 1 + "Number of fluid volumes" + annotation (Dialog(tab="General", group="Discretization", enable=false)); + parameter Integer no_wallVolumes(min=1) = 1 + "Number of wall volumes" + annotation (Dialog(tab="General", group="Discretization", enable=false)); + + // + // Definition of parameters regarding the general geometry + // + parameter Integer no_hydraulicParallelTubes(min=1) = 1 + "Number of hydraulically parallel tubes" + annotation (Dialog(tab="General", group="Geometry")); + + parameter Modelica.Units.SI.Length l = 1 + "Length of the tube" + annotation (Dialog(tab="General", group="Geometry")); + + parameter Modelica.Units.SI.Length roughness = 7.5e-7 + "Absolute roughness of the tube" + annotation (Dialog(tab="General", group="Geometry")); + + // + // Definition of parameters regarding diameters + // + parameter Modelica.Units.SI.Diameter d_inner = 0.01 + "Inner diameter" + annotation (Dialog(tab="General", group="Geometry - Diameters")); + parameter Modelica.Units.SI.Diameter d_outer = 0.012 + "Outer diameter" + annotation (Dialog(tab="General", group="Geometry - Diameters")); + + parameter Modelica.Units.SI.Diameter d_hydInner = d_inner + "Hydraulic inner diameter" + annotation (Dialog(tab="General", group="Geometry - Diameters")); + parameter Modelica.Units.SI.Diameter d_hydOuter = d_outer + "Hydraulic outer diameter" + annotation (Dialog(tab="General", group="Geometry - Diameters")); + + parameter Modelica.Units.SI.Thickness t_wall = (d_outer - d_inner) / 2 + "Wall thickness" + annotation (Dialog(tab="General", group="Geometry - Diameters")); + + // + // Definition of parameters regarding areas + // + parameter Modelica.Units.SI.Area A_crossInner = Modelica.Constants.pi/4 * d_inner^2 + "Inner cross-sectional area" + annotation (Dialog(tab="General", group="Geometry - Areas")); + parameter Modelica.Units.SI.Area A_crossOuter = Modelica.Constants.pi/4 * d_outer^2 + "Outer cross-sectional area" + annotation (Dialog(tab="General", group="Geometry - Areas")); + parameter Modelica.Units.SI.Area A_crossWall = A_crossOuter - A_crossInner + "Wall cross-sectional area" + annotation (Dialog(tab="General", group="Geometry - Areas")); + + parameter Modelica.Units.SI.Area A_hydCrossInner = A_crossInner + "Hydraulic inner cross-sectional area" + annotation (Dialog(tab="General", group="Geometry - Areas")); + parameter Modelica.Units.SI.Area A_hydCrossOuter = A_crossOuter + "Hydraulic outer cross-sectional area" + annotation (Dialog(tab="General", group="Geometry - Areas")); + parameter Modelica.Units.SI.Area A_hydCrossWall = A_hydCrossOuter - A_hydCrossInner + "Hydraulic wall cross-sectional area" + annotation (Dialog(tab="General", group="Geometry - Areas")); + + parameter Modelica.Units.SI.Area A_heatTransferInner= + Modelica.Constants.pi * d_inner * l + "Total inner heat transfer area" + annotation (Dialog(tab="General", group="Geometry - Areas")); + parameter Modelica.Units.SI.Area A_heatTransferOuter= + Modelica.Constants.pi * d_outer * l + "Total outer heat transfer area" + annotation (Dialog(tab="General", group="Geometry - Areas")); + + parameter Real f_finAreaRatioInner(min=0, max=1) = 0 + "Ratio of total inner fin area to total inner heat transfer area" + annotation (Dialog(tab="General", group="Geometry - Areas")); + parameter Real f_finAreaRatioOuter(min=0, max=1) = 0 + "Ratio of total outer fin area to total outer heat transfer area" + annotation (Dialog(tab="General", group="Geometry - Areas")); + + // + // Definition of parameters regarding volumes + // + parameter Modelica.Units.SI.Volume V_inner = A_crossInner * l + "Total inner volume" + annotation (Dialog(tab="General", group="Geometry - Volumes")); + parameter Modelica.Units.SI.Volume V_outer = A_crossOuter * l + "Total outer volume" + annotation (Dialog(tab="General", group="Geometry - Volumes")); + parameter Modelica.Units.SI.Volume V_wall = V_outer - V_inner + "Total wall volume" + annotation (Dialog(tab="General", group="Geometry - Volumes")); + + parameter Real f_finVolumeRatioInner(min=0, max=1) = 0 + "Ratio of total inner fin volume to total wall volume" + annotation (Dialog(tab="General", group="Geometry - Volumes")); + parameter Real f_finVolumeRatioOuter(min=0, max=1) = 0 + "Ratio of total outer fin volume to total wall volume" + annotation (Dialog(tab="General", group="Geometry - Volumes")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains geometric parameters required by models calculating the heat +transfer coefficients at the inside or outside of tubes. +</p> +</html>", revisions="<html> +<ul> + <li> + January 29, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GeometryTube; diff --git a/SorpLib/Components/Tubes/Records/package.mo b/SorpLib/Components/Tubes/Records/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..552ba5e131043ef40a76ef23e539ef54a9188f0f --- /dev/null +++ b/SorpLib/Components/Tubes/Records/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Tubes; +package Records "Package containing records" + extends Modelica.Icons.RecordsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains definitions of records. These records are used to cluster +variables and tidy up the model output. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Records; diff --git a/SorpLib/Components/Tubes/Records/package.order b/SorpLib/Components/Tubes/Records/package.order new file mode 100644 index 0000000000000000000000000000000000000000..617b36e19c700b69289265d08f7e9a3d7319ce47 --- /dev/null +++ b/SorpLib/Components/Tubes/Records/package.order @@ -0,0 +1 @@ +GeometryTube diff --git a/SorpLib/Components/Tubes/Tester/Test_LiquidTube.mo b/SorpLib/Components/Tubes/Tester/Test_LiquidTube.mo new file mode 100644 index 0000000000000000000000000000000000000000..37b0a5212141c038a357212defc2fb8537989932 --- /dev/null +++ b/SorpLib/Components/Tubes/Tester/Test_LiquidTube.mo @@ -0,0 +1,152 @@ +within SorpLib.Components.Tubes.Tester; +model Test_LiquidTube "Tester for the liquid tube" + extends Modelica.Icons.Example; + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource fs_a( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_mFlowInput=false, + use_VFlowInput=true, + V_flow_fixed=-10/60/1000, + T_fixed=288.15, + redeclare final package Medium = Medium) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + SorpLib.Basics.Sources.Fluids.LiquidSource fs_b( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + use_pInput=true, + T_fixed=358.15, + redeclare final package Medium = Medium) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + SorpLib.Basics.Sources.Thermal.HeatSource hs( + boundaryType=SorpLib.Choices.BoundaryThermal.Temperature, + use_TInput=true) + "Heat source for walls" annotation (Placement( + transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={0,40}))); + + // + // Definition of models + // + SorpLib.Components.Tubes.LiquidTube tube( + redeclare Records.GeometryTube geometry(l=10), + fluidPropertyPosition=3, + redeclare model FluidThermalConvectionTubeInside = + HeatTransfer.HeatTransferCoefficientCorrelations.TubeInside.ConstantAlphaA + ( + constantAlphaA=100), + redeclare model PressureDrop = + SorpLib.Components.Fittings.PressureLossCorrelations.TubeInside.Konakov ( + showTotalPressures=true, + showVelocities=true, + showDarcyFrictionNumber=true, + showIndividualPressureLosses=true), + redeclare final package Medium = Medium, + redeclare model WallMaterial = Media.Solids.MetalsAndMetalAlloys.Copper ( + calcCaloricProperties=false, + approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.Constant, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.Constant)) + "Tube model" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + SorpLib.Components.HeatTransfer.GenericHeatTransfer heatTransfer_boundaryToWall( + n_a=tube.no_wallVolumes, + n_b=1, + redeclare model HeatTransferCoefficient = + HeatTransfer.HeatTransferCoefficientCorrelations.Generic.ConstantAlphaA + (constantAlphaA=100)) "Heat transfer from heat source to wall" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,20}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Sine input_V_flow( + amplitude=15/1000/60, + f=1/500, + offset=-10/1000/60) "Input signal for volume flow rate" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Modelica.Blocks.Sources.Ramp input_p( + height=1e5, + duration=2500, + offset=2e5) "Input signal for pressure" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + Modelica.Blocks.Sources.Sine input_TWall( + amplitude=25, + f=1/250, + offset=273.15 + 50) "Input signal for wall temperature boundary" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,60}))); + +equation + // + // Connections + // + connect(fs_a.port, tube.fp_a) annotation (Line( + points={{-60,0},{-10,0}}, + color={28,108,200}, + thickness=1)); + connect(tube.fp_b, fs_b.port) annotation (Line( + points={{10,0},{60,0}}, + color={28,108,200}, + thickness=1)); + connect(hs.port, heatTransfer_boundaryToWall.hp_b[1]) annotation (Line( + points={{0,40},{0,28}}, + color={238,46,47}, + thickness=1)); + connect(heatTransfer_boundaryToWall.hp_a, tube.hp_wall) annotation (Line( + points={{0,12},{0,4}}, + color={238,46,47}, + thickness=1)); + + connect(input_V_flow.y, fs_a.V_flow_input) annotation (Line(points={{-79,0},{-70, + 0},{-70,2},{-61.2,2}}, color={0,0,127})); + connect(input_p.y, fs_b.p_input) + annotation (Line(points={{79,0},{70,0},{70,5},{61.2,5}}, color={0,0,127})); + connect(input_TWall.y, hs.T_input) annotation (Line(points={{-2.22045e-15,49}, + {0,49},{0,44},{-5.2,44},{-5.2,41}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment( + StopTime=2500), Documentation(info="<html> +<p> +This model checks the liquid tube. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + January 29, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_LiquidTube; diff --git a/SorpLib/Components/Tubes/Tester/package.mo b/SorpLib/Components/Tubes/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..457595022dcbf995fe2f42f0e0adbee240cc4719 --- /dev/null +++ b/SorpLib/Components/Tubes/Tester/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Tubes; +package Tester "Models to test and varify tube models" + extends Modelica.Icons.ExamplesPackage; + + + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented tubes. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Tubes/Tester/package.order b/SorpLib/Components/Tubes/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..3cc9ee33c8e0909566a6894ad7a711b536df5cd9 --- /dev/null +++ b/SorpLib/Components/Tubes/Tester/package.order @@ -0,0 +1 @@ +Test_LiquidTube diff --git a/SorpLib/Components/Tubes/package.mo b/SorpLib/Components/Tubes/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..1c88b8506b3c11684abedb0166690b92494d0866 --- /dev/null +++ b/SorpLib/Components/Tubes/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components; +package Tubes "Tubes containing fluids" + extends SorpLib.Icons.TubesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains tubes. Ready-to-use models are based on the Modelica +Standard library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tubes; diff --git a/SorpLib/Components/Tubes/package.order b/SorpLib/Components/Tubes/package.order new file mode 100644 index 0000000000000000000000000000000000000000..386b78552ce3cc9a440bc698b3f798130cd5ce2d --- /dev/null +++ b/SorpLib/Components/Tubes/package.order @@ -0,0 +1,4 @@ +BaseClasses +Records +LiquidTube +Tester diff --git a/SorpLib/Components/Valves/BaseClasses/PartialCompressibleThreeWayValve.mo b/SorpLib/Components/Valves/BaseClasses/PartialCompressibleThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..96630a8dee31931766275fd7463c07aa53546a18 --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/PartialCompressibleThreeWayValve.mo @@ -0,0 +1,143 @@ +within SorpLib.Components.Valves.BaseClasses; +model PartialCompressibleThreeWayValve + "Base model for all three-way valves for compressible fluids" + extends SorpLib.Components.Valves.BaseClasses.PartialThreeWayValve; + + // + // Definition of variables + // +protected + Modelica.Units.SI.Density rho_a + "Instreaming density at port a"; + Modelica.Media.Common.IsentropicExponent gamma_a + "Instreaming isentropic exponent at port a"; + + Real radicand_ab + "Radicand if flowing from port a to b"; + Real radicand_ac + "Radicand if flowing from port a to c"; + + Real weightingFactor_ab + "Weighting factor used to distinguish between flow regimes if flowing from + port a to b"; + Real weightingFactor_ac + "Weighting factor used to distinguish between flow regimes if flowing from + port b to c"; + +equation + // + // Calculate radicands + // + if avoid_events then + weightingFactor_ab = + SorpLib.Numerics.smoothTransition_noEvent( + x=(port_b.p / port_a.p), + transitionPoint=(2 / (gamma_a + 1)) ^ (gamma_a / (gamma_a - 1)), + transitionLength=1e-4, + noDiff=2) + "Weighting factor used to distinguish between flow regimes if flowing from + port a to b"; + weightingFactor_ac = + SorpLib.Numerics.smoothTransition_noEvent( + x=(port_c.p / port_a.p), + transitionPoint=(2 / (gamma_a + 1)) ^ (gamma_a / (gamma_a - 1)), + transitionLength=1e-4, + noDiff=2) + "Weighting factor used to distinguish between flow regimes if flowing from + port a to c"; + + else + weightingFactor_ab = + SorpLib.Numerics.smoothTransition( + x=(port_b.p / port_a.p), + transitionPoint=(2 / (gamma_a + 1)) ^ (gamma_a / (gamma_a - 1)), + transitionLength=1e-4, + noDiff=2) + "Weighting factor used to distinguish between flow regimes if flowing from + port a to b"; + weightingFactor_ac = + SorpLib.Numerics.smoothTransition( + x=(port_c.p / port_a.p), + transitionPoint=(2 / (gamma_a + 1)) ^ (gamma_a / (gamma_a - 1)), + transitionLength=1e-4, + noDiff=2) + "Weighting factor used to distinguish between flow regimes if flowing from + port a to c"; + + end if; + + radicand_ab = (2 * rho_a * port_a.p) * + (weightingFactor_ab * (2 ^ (2 / (gamma_a - 1)) * gamma_a / + (gamma_a + 1) ^ ((gamma_a + 1) / (gamma_a - 1))) + + (1-weightingFactor_ab) * (gamma_a / (gamma_a - 1) * + ((port_b.p / port_a.p) ^ (2 / gamma_a) - + (port_b.p / port_a.p) ^ ((gamma_a + 1) / gamma_a)))) + "Radicand if flowing from port a to b"; + radicand_ac = (2 * rho_a * port_a.p) * + (weightingFactor_ac * (2 ^ (2 / (gamma_a - 1)) * gamma_a / + (gamma_a + 1) ^ ((gamma_a + 1) / (gamma_a - 1))) + + (1-weightingFactor_ac) * (gamma_a / (gamma_a - 1) * + ((port_c.p / port_a.p) ^ (2 / gamma_a) - + (port_c.p / port_a.p) ^ ((gamma_a + 1) / gamma_a)))) + "Radicand if flowing from port a to c"; + + // + // Calculate the mass flow rates + // + port_b.m_flow = -A_eff_b * (if avoid_events then + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_ab, + delta_x=sqrt(dpRegularization), + f_positive=radicand_ab, + f_negative=0) else + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_ab, + delta_x=sqrt(dpRegularization), + f_positive=radicand_ab, + f_negative=0)) + "Mass flow rate at port b: Design flow direction from port a to b and no + other flow direction is allowed"; + port_c.m_flow = -A_eff_c * (if avoid_events then + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_ac, + delta_x=sqrt(dpRegularization), + f_positive=radicand_ac, + f_negative=0) else + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_ac, + delta_x=sqrt(dpRegularization), + f_positive=radicand_ac, + f_negative=0)) + "Mass flow rate at port c: Design flow direction from port a to c and no + other flow direction is allowed"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model of all three-way valves for compressible +fluids. It defines fundamental parameters and variables required by all three-way +valves for compressible fluids. +<br/><br/> +Models that inherit properties from this partial model have to redeclare the fluid +ports and to add a medium model. The following variables must be specified in the +model that inherit properties: +</p> +<ul> + <li> + <i>rho_a</i>: Instreaming density at port a. + </li> + <li> + <i>gamma_a</i>: Instreaming isentropic exponent at port a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PartialCompressibleThreeWayValve; diff --git a/SorpLib/Components/Valves/BaseClasses/PartialCompressibleValve.mo b/SorpLib/Components/Valves/BaseClasses/PartialCompressibleValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..7391fdf886d686ce8e461d41c71d311c63829be7 --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/PartialCompressibleValve.mo @@ -0,0 +1,177 @@ +within SorpLib.Components.Valves.BaseClasses; +partial model PartialCompressibleValve + "Base model for all valves for compressible fluids" + extends SorpLib.Components.Valves.BaseClasses.PartialOrificeValve( + final strictCheckValve=true, + final accountHydraulicHead=false, + final p_hydraulicHead=1000*9.81*0.25); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Density rho_a + "Instreaming density at port a"; + Modelica.Units.SI.Density rho_b + "Instreaming density at port b"; + + Modelica.Media.Common.IsentropicExponent gamma_a + "Instreaming isentropic exponent at port a"; + Modelica.Media.Common.IsentropicExponent gamma_b + "Instreaming isentropic exponent at port b"; + + Real radicand_a + "Radicand if flowing from port a to b"; + Real radicand_b + "Radicand if flowing from port b to a"; + + Real weightingFactor_a + "Weighting factor used to distinguish between flow regimes if flowing from + port a to b"; + Real weightingFactor_b + "Weighting factor used to distinguish between flow regimes if flowing from + port b to a"; + +equation + // + // Calculate radicands + // + if avoid_events then + weightingFactor_a = + SorpLib.Numerics.smoothTransition_noEvent( + x=(port_b.p / port_a.p), + transitionPoint=(2 / (gamma_a + 1)) ^ (gamma_a / (gamma_a - 1)), + transitionLength=1e-4, + noDiff=2) + "Weighting factor used to distinguish between flow regimes if flowing from + port a to b"; + weightingFactor_b = + SorpLib.Numerics.smoothTransition_noEvent( + x=(port_a.p / port_b.p), + transitionPoint=(2 / (gamma_b + 1)) ^ (gamma_b / (gamma_b - 1)), + transitionLength=1e-4, + noDiff=2) + "Weighting factor used to distinguish between flow regimes if flowing from + port a to b"; + + else + weightingFactor_a = + SorpLib.Numerics.smoothTransition( + x=(port_b.p / port_a.p), + transitionPoint=(2 / (gamma_a + 1)) ^ (gamma_a / (gamma_a - 1)), + transitionLength=1e-4, + noDiff=2) + "Weighting factor used to distinguish between flow regimes if flowing from + port a to b"; + weightingFactor_b = + SorpLib.Numerics.smoothTransition( + x=(port_a.p / port_b.p), + transitionPoint=(2 / (gamma_b + 1)) ^ (gamma_b / (gamma_b - 1)), + transitionLength=1e-4, + noDiff=2) + "Weighting factor used to distinguish between flow regimes if flowing from + port a to b"; + + end if; + + radicand_a = (2 * rho_a * port_a.p) * + (weightingFactor_a * (2 ^ (2 / (gamma_a - 1)) * gamma_a / + (gamma_a + 1) ^ ((gamma_a + 1) / (gamma_a - 1))) + + (1-weightingFactor_a) * (gamma_a / (gamma_a - 1) * + ((port_b.p / port_a.p) ^ (2 / gamma_a) - + (port_b.p / port_a.p) ^ ((gamma_a + 1) / gamma_a)))) + "Radicand if flowing from port a to b"; + radicand_b = (2 * rho_b * port_b.p) * + (weightingFactor_b * (2 ^ (2 / (gamma_b - 1)) * gamma_b / + (gamma_b + 1) ^ ((gamma_b + 1) / (gamma_b - 1))) + + (1-weightingFactor_b) * (gamma_b / (gamma_b - 1) * + ((port_a.p / port_b.p) ^ (2 / gamma_b) - + (port_a.p / port_b.p) ^ ((gamma_b + 1) / gamma_b)))) + "Radicand if flowing from port b to a"; + + // + // Calculate the mass flow rate + // + if checkValve and strictCheckValve then + port_a.m_flow = A_eff * (if avoid_events then + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=radicand_a, + f_negative=0) else + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=radicand_a, + f_negative=0)) + "Mass flow rate at port a: Design flow direction from port a to b and no + other flow direction is allowed"; + + elseif checkValve and not strictCheckValve then + port_a.m_flow = A_eff * (if avoid_events then + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=radicand_a, + f_negative=0) else + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=radicand_a, + f_negative=0)) + "Mass flow rate at port a: Design flow direction from port a to b and a + minimal flow from port b to a is allowed"; + + else + port_a.m_flow = A_eff * (if avoid_events then + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=radicand_a, + f_negative=radicand_b) else + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=radicand_a, + f_negative=radicand_b)) + "Mass flow rate at port a: Design flow direction from port a to b but + both flow directions are allowed"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model of all valves for compressible fluids. It +defines fundamental parameters and variables required by all valves for compressible +fluids. +<br/><br/> +Models that inherit properties from this partial model have to redeclare the fluid +ports and to add a medium model. The following variables must be specified in the +model that inherit properties: +</p> +<ul> + <li> + <i>rho_a</i>: Instreaming density at port a. + </li> + <li> + <i>rho_b</i>: Instreaming density at port b. + </li> + <li> + <i>gamma_a</i>: Instreaming isentropic exponent at port a. + </li> + <li> + <i>gamma_b</i>: Instreaming isentropic exponent at port b. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PartialCompressibleValve; diff --git a/SorpLib/Components/Valves/BaseClasses/PartialCondensateRefluxValve.mo b/SorpLib/Components/Valves/BaseClasses/PartialCondensateRefluxValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..dc46378d7179edd25c77bca6f78373c1177623b9 --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/PartialCondensateRefluxValve.mo @@ -0,0 +1,207 @@ +within SorpLib.Components.Valves.BaseClasses; +partial model PartialCondensateRefluxValve + "Base model for all condensate reflux valves" + + // + // Definition setup parameters + // + parameter Real setPoint = 0.25 + "Set point of process variable that is controlled (e.g., relative filling + level of a phase separator volume) at port a (i.e., mass flows from port a to + b)" + annotation (Dialog(tab="General", group="Valve Setup")); + + // + // Definition of parameters regarding the valve characteristic + // + parameter Integer controlType(min=1, max=3) = 2 + "Control type: Constant, linear, or quadratic" + annotation (Dialog(tab="Valve Characteristic", group="Type"), + choices( + choice=1 "Constant", + choice=2 "Linear", + choice=3 "Quadratic")); + + parameter Modelica.Units.SI.MassFlowRate m_flow_constant = 10/60 + "Constant mass flow rate used if controlType = 'Constant'" + annotation (Dialog(tab="Valve Characteristic", group="Constant Controler", + enable=controlType==1)); + parameter Real kp_linear(final unit="kg/s") = 0.15 + "Linear valve coefficient if controlType = 'Linear'" + annotation (Dialog(tab="Valve Characteristic", group="Linear Controler", + enable=controlType==2)); + parameter Real kp_quadratic(final unit="kg/s") = 0.15 + "Quadratic valve coefficient if controlType = 'Quadratic'" + annotation (Dialog(tab="Valve Characteristic", group="Quadratic Controler", + enable=controlType==3)); + + extends SorpLib.Components.Valves.BaseClasses.PartialValve( + final controllableOpening=false, + final fixedOpening=1, + final useTimeConstant=false, + final tau=1, + final leackage=false, + final leackageOpening=0, + final accountHydraulicHead=false, + final p_hydraulicHead = 1000 * 9.81 * 0.25, + final opening_initial=0); + + // + // Definition of advanced parameters + // + parameter Real setPointRegularization = 1e-2 + "Regularization around set point required for smooth transition to zero mass + flow rate if valve is a check valve or controlType = 'Constant'" + annotation (Dialog(tab="Advanced", group="Numerics", + enable=checkValve or controlType==1), + Evaluate=true, + HideResult=true); + parameter Integer noDiff(min=1,max=3) = 3 + "Specification how often smoothTransition-function can be differentiated + (i.e., 1, 2 or 3) if valve is a check valve" + annotation (Dialog(tab="Advanced", group="Numerics", + enable=checkValve), + Evaluate=true, + HideResult=true); + + // + // Definition of inputs + // + Modelica.Blocks.Interfaces.RealInput processVariable + "Process variable that is controlled to reach a set point" + annotation (Placement(transformation(extent={{-36,32},{-16,52}}), + iconTransformation(extent={{-36,32},{-16,52}}))); + + // + // Definition of variables + // +protected + Real weightingFactor = if checkValve then (if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent( + x=processVariable, + transitionPoint=setPoint, + transitionLength=setPointRegularization, + noDiff=noDiff) else + SorpLib.Numerics.smoothTransition( + x=processVariable, + transitionPoint=setPoint, + transitionLength=setPointRegularization, + noDiff=noDiff)) else 0 + "Weighting factor used for smooth transition to zero mass flow rate if valve + is a check valve: 1 at 'setPoint-setPointRegularization/2' and 0 at + 'setPoint+setPointRegularization/2"; + +equation + // + // Calculate flow characteristic depending on the control type + // + if controlType == 1 then + if checkValve and strictCheckValve then + port_a.m_flow = (1 - (if avoid_events then + SorpLib.Numerics.smoothTransition_noEvent( + x=processVariable, + transitionPoint=setPoint+setPointRegularization/2, + transitionLength=setPointRegularization, + noDiff=noDiff) else + SorpLib.Numerics.smoothTransition( + x=processVariable, + transitionPoint=setPoint+setPointRegularization/2, + transitionLength=setPointRegularization, + noDiff=noDiff))) * m_flow_constant + "Mass flow rate at port a: Design flow direction from port a to b and no + other flow direction is allowed"; + + elseif checkValve and not strictCheckValve then + port_a.m_flow = (1-weightingFactor) * m_flow_constant + "Mass flow rate at port a: Design flow direction from port a to b and a + minimal flow from port b to a is allowed"; + + else + port_a.m_flow = if avoid_events then + SorpLib.Numerics.regStep_noEvent( + x=processVariable-setPoint, + y1=m_flow_constant, + y2=-m_flow_constant, + x_small=setPointRegularization) else + SorpLib.Numerics.regStep( + x=processVariable-setPoint, + y1=m_flow_constant, + y2=-m_flow_constant, + x_small=setPointRegularization) + "Mass flow rate at port a: Design flow direction from port a to b but + both flow directions are allowed"; + + end if; + + elseif controlType == 2 then + if checkValve and strictCheckValve then + port_a.m_flow = smooth(0, max(processVariable - setPoint, 0)) * kp_linear + "Mass flow rate at port a: Design flow direction from port a to b and no + other flow direction is allowed"; + + elseif checkValve and not strictCheckValve then + port_a.m_flow = (1-weightingFactor) * (processVariable - setPoint) * kp_linear + "Mass flow rate at port a: Design flow direction from port a to b and a + minimal flow from port b to a is allowed"; + + else + port_a.m_flow = (processVariable - setPoint) * kp_linear + "Mass flow rate at port a: Design flow direction from port a to b but + both flow directions are allowed"; + + end if; + + else + if checkValve and strictCheckValve then + port_a.m_flow = smooth(0, max(sign(processVariable - setPoint) * + (processVariable - setPoint)^2, 0)) * kp_quadratic + "Mass flow rate at port a: Design flow direction from port a to b and no + other flow direction is allowed"; + + elseif checkValve and not strictCheckValve then + port_a.m_flow = (1-weightingFactor) * sign(processVariable - setPoint) * + (processVariable - setPoint)^2 * kp_quadratic + "Mass flow rate at port a: Design flow direction from port a to b and a + minimal flow from port b to a is allowed"; + + else + port_a.m_flow = sign(processVariable - setPoint) * + (processVariable - setPoint)^2 * kp_quadratic + "Mass flow rate at port a: Design flow direction from port a to b but + both flow directions are allowed"; + + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model of all condensate reflux valves. It defines fundamental +parameters and variables required by all condensate reflux valves. These valves act as control +valves: I.e., a process variable (e.g., the relative filling level in a phase separator volume) +is regulated to its setpoint via the mass flow through the valve. Three characteristics are +available for the control behavior: A constant mass flow, a mass flow that is linear to the +deviation from the setpoint, and a mass flow that is quadratic to the deviation from the setpoint. +<br/><br/> +Models that inherit properties from this partial model have to redeclare the fluid ports and to +add a medium model. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + Major revisions (new functionalities, documentation). + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + Smaller revisions after restructuring of the library. + </li> + <li> + December 11, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end PartialCondensateRefluxValve; diff --git a/SorpLib/Components/Valves/BaseClasses/PartialIncompressibleThreeWayValve.mo b/SorpLib/Components/Valves/BaseClasses/PartialIncompressibleThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..c5b0b1df3f9a79468d9db42dec1b35b9ae783861 --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/PartialIncompressibleThreeWayValve.mo @@ -0,0 +1,70 @@ +within SorpLib.Components.Valves.BaseClasses; +model PartialIncompressibleThreeWayValve + "Base model for all three-way valves for incompressible fluids" + extends SorpLib.Components.Valves.BaseClasses.PartialThreeWayValve; + + // + // Definition of variables + // +protected + Modelica.Units.SI.Density rho_a + "Instreaming density at port a"; + +equation + // + // Calculate the mass flow rates + // + port_b.m_flow = -A_eff_b * (if avoid_events then + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_ab, + delta_x=sqrt(dpRegularization), + f_positive=2*rho_a, + f_negative=0) else + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_ab, + delta_x=sqrt(dpRegularization), + f_positive=2*rho_a, + f_negative=0)) + "Mass flow rate at port b: Design flow direction from port a to b and no + other flow direction is allowed"; + port_c.m_flow = -A_eff_c * (if avoid_events then + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_ac, + delta_x=sqrt(dpRegularization), + f_positive=2*rho_a, + f_negative=0) else + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_ac, + delta_x=sqrt(dpRegularization), + f_positive=2*rho_a, + f_negative=0)) + "Mass flow rate at port c: Design flow direction from port a to c and no + other flow direction is allowed"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model of all three-way valves for incompresible +fluids. It defines fundamental parameters and variables required by all three-way +valves for incompresible fluids. +<br/><br/> +Models that inherit properties from this partial model have to redeclare the fluid +ports and to add a medium model. The following variables must be specified in the +model that inherit properties: +</p> +<ul> + <li> + <i>rho_a</i>: Instreaming density at port a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PartialIncompressibleThreeWayValve; diff --git a/SorpLib/Components/Valves/BaseClasses/PartialIncompressibleValve.mo b/SorpLib/Components/Valves/BaseClasses/PartialIncompressibleValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..b1b57ae08fe99ecec7673435caad263039265366 --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/PartialIncompressibleValve.mo @@ -0,0 +1,96 @@ +within SorpLib.Components.Valves.BaseClasses; +partial model PartialIncompressibleValve + "Base model for all valves for incompressible fluids" + extends SorpLib.Components.Valves.BaseClasses.PartialOrificeValve( + final strictCheckValve=true); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Density rho_a + "Instreaming density at port a"; + Modelica.Units.SI.Density rho_b + "Instreaming density at port b"; + +equation + // + // Calculate the mass flow rate + // + if checkValve and strictCheckValve then + port_a.m_flow = A_eff * (if avoid_events then + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=2*rho_a, + f_negative=0) else + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=2*rho_a, + f_negative=0)) + "Mass flow rate at port a: Design flow direction from port a to b and no + other flow direction is allowed"; + + elseif checkValve and not strictCheckValve then + port_a.m_flow = A_eff * (if avoid_events then + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=2*rho_a, + f_negative=0) else + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=2*rho_a, + f_negative=0)) + "Mass flow rate at port a: Design flow direction from port a to b and a + minimal flow from port b to a is allowed"; + + else + port_a.m_flow = A_eff * (if avoid_events then + SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=2*rho_a, + f_negative=2*rho_b) else + SorpLib.Numerics.regSquareWFactors_inv( + y=dp_, + delta_x=sqrt(dpRegularization), + f_positive=2*rho_a, + f_negative=2*rho_b)) + "Mass flow rate at port a: Design flow direction from port a to b but + both flow directions are allowed"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model of all valves for incompresible fluids. It +defines fundamental parameters and variables required by all valves for incompresible +fluids. +<br/><br/> +Models that inherit properties from this partial model have to redeclare the fluid +ports and to add a medium model. The following variables must be specified in the +model that inherit properties: +</p> +<ul> + <li> + <i>rho_a</i>: Instreaming density at port a. + </li> + <li> + <i>rho_b</i>: Instreaming density at port b. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PartialIncompressibleValve; diff --git a/SorpLib/Components/Valves/BaseClasses/PartialOrificeValve.mo b/SorpLib/Components/Valves/BaseClasses/PartialOrificeValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..0fb63e641f14e82995777028d58385d94503dc81 --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/PartialOrificeValve.mo @@ -0,0 +1,163 @@ +within SorpLib.Components.Valves.BaseClasses; +partial model PartialOrificeValve + "Base model for all orifice valves" + + // + // Definition of parameters regarding the valve characteristic + // + parameter Boolean useKvsValue = true + " = true, if Kvs-value is used to determine mass flow rate; otherwise, A_eff + is used to determine mass flow rate" + annotation (Dialog(tab="Valve Characteristic", group="Type"), + Evaluate=true); + parameter Integer valveCharacteristic = 1 + "Valve characteristic used to calculate the flow coefficient or effective area + depending on the actual opening: Linear, quadratic, or equal percentage" + annotation (Dialog(tab="Valve Characteristic", group="Type"), + choices( + choice=1 "Linear", + choice=2 "Quadratic", + choice=3 "Equal percentage")); + + parameter Real opening_A_eff_min = 1e-2 + "Minimal valve opening (i.e., position) that corresponds to minimal effective + flow area" + annotation (Dialog(tab="Valve Characteristic", group="Effective Flow Area", + enable=not useKvsValue and valveCharacteristic==3)); + parameter Modelica.Units.SI.Area A_eff_min = 0.1e-6 + "Minimal effective flow area if valve is almost closed" + annotation (Dialog(tab="Valve Characteristic", group="Effective Flow Area", + enable=not useKvsValue and valveCharacteristic==3)); + parameter Modelica.Units.SI.Area A_eff_max = 0.3e-6 + "Maximal effective flow area if valve is completly open" + annotation (Dialog(tab="Valve Characteristic", group="Effective Flow Area", + enable=not useKvsValue)); + + parameter Modelica.Units.SI.PressureDifference dp_ref = 1e5 + "Reference pressure difference that corresponds to the Kvs-value" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue)); + parameter Modelica.Units.SI.Density rho_ref = 1e3 + "Reference density that corresponds to the Kvs-value" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue)); + parameter Real opening_Kv_min = 1e-2 + "Minimal valve opening (i.e., position) that corresponds to minimal flow + coefficient" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue and valveCharacteristic==3)); + parameter Real Kv_min(unit="m3/h") = 0.5 + "Minimal flow coefficient if valve is almost closed" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue and valveCharacteristic==3)); + parameter Real Kvs(unit="m3/h") = 1.5 + "Maximal flow coefficient if valve is completly open" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue)); + + extends SorpLib.Components.Valves.BaseClasses.PartialValve( + controllableOpening=true); + + // + // Definition of advanced parameters + // + parameter Modelica.Units.SI.PressureDifference dpRegularization = 10 + "Regularization around zero pressure drop for continous flow reversal or + check valve implementation" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.Area A_eff + "Effective flow area used to calculate the mass flow rate: This area considers + the actual opening and the calculation approach (i.e., Kvs-value or effective + flow area"; + +equation + // + // Calculate the effective flow area + // + if useKvsValue then + if valveCharacteristic == 1 then + A_eff = + SorpLib.Components.Valves.ValveCharacteristics.linearCharacteristic( + opening=opening_internal, + fc_max=Kvs) * sqrt(rho_ref / (2 * dp_ref)) / 3600 + "Effective flow area used to calculate the mass flow rate"; + + elseif valveCharacteristic == 2 then + A_eff = + SorpLib.Components.Valves.ValveCharacteristics.quadraticCharacteristic( + opening=opening_internal, + fc_max=Kvs) * sqrt(rho_ref / (2 * dp_ref)) / 3600 + "Effective flow area used to calculate the mass flow rate"; + + else + A_eff = + SorpLib.Components.Valves.ValveCharacteristics.equalPercentageCharacteristic( + opening=opening_internal, + fc_max=Kvs, + fc_min=Kv_min, + opening_min=opening_Kv_min) * sqrt(rho_ref / (2 * dp_ref)) / 3600 + "Effective flow area used to calculate the mass flow rate"; + + end if; + + else + if valveCharacteristic == 1 then + A_eff = + SorpLib.Components.Valves.ValveCharacteristics.linearCharacteristic( + opening=opening_internal, + fc_max=A_eff_max) + "Effective flow area used to calculate the mass flow rate"; + + elseif valveCharacteristic == 2 then + A_eff = + SorpLib.Components.Valves.ValveCharacteristics.quadraticCharacteristic( + opening=opening_internal, + fc_max=A_eff_max) + "Effective flow area used to calculate the mass flow rate"; + + else + A_eff = + SorpLib.Components.Valves.ValveCharacteristics.equalPercentageCharacteristic( + opening=opening_internal, + fc_max=A_eff_max, + fc_min=A_eff_min, + opening_min=opening_A_eff_min) + "Effective flow area used to calculate the mass flow rate"; + + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model of all orifice valves. It defines fundamental parameters +and variables required by all orifice valves. +<br/><br/> +Models that inherit properties from this partial model have to redeclare the fluid ports and to +add a medium model. The following variables must be specified in the model that inherit +properties: +</p> +<ul> + <li> + The flow variable <i>port_a.m_flow</i> that defines the mass flow rate at port a. The + mass flow rate depends on the pressure difference <i>dp_</i> between the two ports. Further, + the mass flow rate depends on the valve type (i.e., (strict) check valve or normal valve). + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PartialOrificeValve; diff --git a/SorpLib/Components/Valves/BaseClasses/PartialThreeWayValve.mo b/SorpLib/Components/Valves/BaseClasses/PartialThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..04b8f7cb4d57e075fe9042a204a4073bbb6d3bea --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/PartialThreeWayValve.mo @@ -0,0 +1,440 @@ +within SorpLib.Components.Valves.BaseClasses; +partial model PartialThreeWayValve + "Base model for all three-way valves" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of setup parameters + // + parameter Boolean controllablePosition = false + " = true, if valve position is contrallable via an input signal" + annotation (Dialog(tab="General", group="Valve Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + parameter Real fixedPosition(min=0, max=1) = 0 + "Fixed valve position if the valve is not controllable: If 0, mass flows from + port a to b; if 1, mass flows from port a to c" + annotation (Dialog(tab="General", group="Valve Setup", + enable=not controllablePosition)); + + parameter Boolean useTimeConstant = false + " = true, if time constant is used to delay valve position" + annotation (Dialog(tab="General", group="Valve Setup", + enable=controllablePosition), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + parameter Modelica.Units.SI.Time tau = 1 + "Time constant for valve position" + annotation (Dialog(tab="General", group="Valve Setup", + enable=controllablePosition and useTimeConstant)); + + parameter Boolean leackage = false + " = true, if valve has a leackage mass flow rate (i.e., cannot be fully + switched to position 0 or 1) to avoid singularities" + annotation (Dialog(tab="General", group="Valve Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + parameter Real leackagePosition(min=0, max=1) = 1e-3 + "Leackage valve position to avoid singularities" + annotation (Dialog(tab="General", group="Valve Setup", + enable=leackage)); + + // + // Definition of parameters regarding the valve characteristic + // + parameter Boolean useKvsValue = true + " = true, if Kvs-value is used to determine mass flow rate; otherwise, A_eff + is used to determine mass flow rate" + annotation (Dialog(tab="Valve Characteristic", group="Type"), + Evaluate=true); + + parameter Modelica.Units.SI.Area A_eff_max_b = 0.3e-6 + "Maximal effective flow area at port b if valve is completly open" + annotation (Dialog(tab="Valve Characteristic", group="Effective Flow Area", + enable=not useKvsValue)); + parameter Modelica.Units.SI.Area A_eff_max_c = A_eff_max_b + "Maximal effective flow area at port c if valve is completly open" + annotation (Dialog(tab="Valve Characteristic", group="Effective Flow Area", + enable=not useKvsValue)); + + parameter Modelica.Units.SI.PressureDifference dp_ref_b = 1e5 + "Reference pressure difference that corresponds to the Kvs-value at port b" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue)); + parameter Modelica.Units.SI.PressureDifference dp_ref_c = dp_ref_b + "Reference pressure difference that corresponds to the Kvs-value at port c" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue)); + parameter Modelica.Units.SI.Density rho_ref_b = 1e3 + "Reference density that corresponds to the Kvs-value at port b" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue)); + parameter Modelica.Units.SI.Density rho_ref_c = rho_ref_b + "Reference density that corresponds to the Kvs-value at port c" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue)); + parameter Real Kvs_b(unit="m3/h") = 1.5 + "Maximal flow coefficient at port b if valve is completly open" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue)); + parameter Real Kvs_c(unit="m3/h") = Kvs_b + "Maximal flow coefficient at port c if valve is completly open" + annotation (Dialog(tab="Valve Characteristic", group="Flow coefficient", + enable=useKvsValue)); + + // + // Definition or initialisation parameters + // + parameter Real position_initial = 1 + "Initial value of valve position if valve position is delayed" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=controllablePosition and useTimeConstant)); + + parameter Modelica.Units.SI.MassFlowRate m_flow_start = 1e-4 + "Start value for mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + parameter Modelica.Units.SI.PressureDifference dpRegularization = 10 + "Regularization around zero pressure drop for check valve implementation" + annotation (Dialog(tab="Advanced", group="Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of inputs + // + Modelica.Blocks.Interfaces.RealInput position(min=0, max=1) if + controllablePosition + "Valve position input signal" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,70}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,70}))); + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=m_flow_start)) + "Fluid port a" + annotation (Placement(transformation(extent={{-10,-88},{10,-68}}), + iconTransformation(extent={{-10,-88},{10,-68}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-m_flow_start)) + "Fluid port b" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}), + iconTransformation(extent={{-90,-10},{-70,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_c + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-m_flow_start)) + "Fluid port c" + annotation (Placement(transformation(extent={{70,-10},{90,10}}), + iconTransformation(extent={{70,-10},{90,10}})), + choicesAllMatching=true); + + // + // Definition of variables + // + Modelica.Units.SI.PressureDifference dp_ab + "Pressure difference between port a and b"; + Modelica.Units.SI.PressureDifference dp_ac + "Pressure difference between port a and c"; + + Modelica.Units.SI.Area A_eff_b + "Effective flow area used to calculate the mass flow rate at port b: This area + considers the actual position and the calculation approach (i.e., Kvs-value + or effective flow area"; + Modelica.Units.SI.Area A_eff_c + "Effective flow area used to calculate the mass flow rate at port c: This area + considers the actual position and the calculation approach (i.e., Kvs-value + or effective flow area"; + + // + // Definition of blocks + // + Modelica.Blocks.Continuous.CriticalDamping filter( + n=2, + f=5 / (2 * Modelica.Constants.pi * tau), + normalized=true, + initType=Modelica.Blocks.Types.Init.InitialOutput, + y_start=position_initial) if controllablePosition and useTimeConstant + "Critical damping filter to filter position signal" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,40})), + HideResult=true); + + SorpLib.Components.Valves.Utilities.Limiter limiter( + lowerLimit=if leackage then leackagePosition else 0, + upperLimit=if leackage then 1-leackagePosition else 1) if + controllablePosition + "Limits the input signal" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,10})), + HideResult=true); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput position_internal(min=0, max=1) + "Needed for connecting to conditional components"; + +equation + // + // Assertations + // + if not controllablePosition then + assert(fixedPosition >= 0 and fixedPosition <= 1, + "Fixed position (" + String(fixedPosition) + ") must between 0 and 1!", + level = AssertionLevel.error); + end if; + + // + // Momentum balance + // + dp_ab = port_a.p - port_b.p + "Pressure difference between port a and b"; + dp_ac = port_a.p - port_c.p + "Pressure difference between port a and c"; + + // + // Mass balance + // + 0 = port_a.m_flow + port_b.m_flow + port_c.m_flow + "Steady-state mass balance"; + + port_a.Xi_outflow = SorpLib.Components.Valves.Utilities.mixStreamVariables( + m_flow_1=port_b.m_flow, + m_flow_2=port_c.m_flow, + streamVariable_1=inStream(port_b.Xi_outflow), + streamVariable_2=inStream(port_c.Xi_outflow)) + "Mixed stream variables accounting for flow directions of the three-way + valve"; + port_b.Xi_outflow = SorpLib.Components.Valves.Utilities.mixStreamVariables( + m_flow_1=port_a.m_flow, + m_flow_2=port_c.m_flow, + streamVariable_1=inStream(port_a.Xi_outflow), + streamVariable_2=inStream(port_c.Xi_outflow)) + "Mixed stream variables accounting for flow directions of the three-way + valve"; + port_c.Xi_outflow = SorpLib.Components.Valves.Utilities.mixStreamVariables( + m_flow_1=port_a.m_flow, + m_flow_2=port_b.m_flow, + streamVariable_1=inStream(port_a.Xi_outflow), + streamVariable_2=inStream(port_b.Xi_outflow)) + "Mixed stream variables accounting for flow directions of the three-way + valve"; + + // + // Energy balance + // + port_a.h_outflow = SorpLib.Components.Valves.Utilities.mixStreamVariables( + m_flow_1=port_b.m_flow, + m_flow_2=port_c.m_flow, + streamVariable_1=inStream(port_b.h_outflow), + streamVariable_2=inStream(port_c.h_outflow)) + "Mixed stream variables accounting for flow directions of the three-way + valve"; + port_b.h_outflow = SorpLib.Components.Valves.Utilities.mixStreamVariables( + m_flow_1=port_a.m_flow, + m_flow_2=port_c.m_flow, + streamVariable_1=inStream(port_a.h_outflow), + streamVariable_2=inStream(port_c.h_outflow)) + "Mixed stream variables accounting for flow directions of the three-way + valve"; + port_c.h_outflow = SorpLib.Components.Valves.Utilities.mixStreamVariables( + m_flow_1=port_a.m_flow, + m_flow_2=port_b.m_flow, + streamVariable_1=inStream(port_a.h_outflow), + streamVariable_2=inStream(port_b.h_outflow)) + "Mixed stream variables accounting for flow directions of the three-way + valve"; + + // + // Calculate actual opening + // + if not controllablePosition then + position_internal = if leackage then + min(max(fixedPosition,leackagePosition),1-leackagePosition) else + fixedPosition + "Needed for connecting to conditional components"; + else + if useTimeConstant then + connect(position, filter.u) + annotation (Line(points={{0,70},{0,52}}, color={0,0,127})); + connect(filter.y, limiter.u) + annotation (Line(points={{0,29},{0,22}}, color={0,0,127})); + + else + connect(position, limiter.u) + annotation (Line(points={{0,70},{0,22}}, color={0,0,127})); + + end if; + + connect(position_internal, limiter.y) + "Needed for connecting to conditional components"; + + end if; + + // + // Calculate the effective flow area + // + if useKvsValue then + A_eff_b = Kvs_b * sqrt(rho_ref_b / (2 * dp_ref_b)) / 3600 * + (1 - position_internal) + "Effective flow area used to calculate the mass flow rate at port b"; + A_eff_c = Kvs_c * sqrt(rho_ref_c / (2 * dp_ref_c)) / 3600 * + position_internal + "Effective flow area used to calculate the mass flow rate at port c"; + + else + A_eff_b = A_eff_max_b * (1 - position_internal) + "Effective flow area used to calculate the mass flow rate at port b"; + A_eff_c = A_eff_max_c * position_internal + "Effective flow area used to calculate the mass flow rate at port c"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model of all three-way valves. It defines fundamental +parameters and variables required by all valves. +<br/><br/> +Models that inherit properties from this partial model have to redeclare the fluid +ports. Furthermore, inherting models may have to add a medium model. The following +variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + The flow variable <i>port_b.m_flow</i> that defines the mass flow rate at port b + in dependance of the pressure drop between port a and b <i>dp_ab</i>. + </li> + <li> + The flow variable <i>port_c.m_flow</i> that defines the mass flow rate at port c + in dependance of the pressure drop between port a and c <i>dp_ac</i>. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>"), Icon(coordinateSystem(extent={{-100,-100},{100,100}}), + graphics={ Line( + points={{0,40},{0,0}}, + color={0,0,0}, + thickness=1), + Polygon( + points={{-80,62},{-80,62}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Polygon( + points={{-80,50},{-80,-50},{0,0},{-80,50}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Polygon( + points={{-40,50},{-40,-50},{40,0},{-40,50}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + origin={40,0}, + rotation=180), + Ellipse( + extent={{-16,60},{16,28}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-10,54},{10,34}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString="M", + textStyle={TextStyle.Bold}), + Polygon( + points={{-40,50},{-40,-50},{40,0},{-40,50}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + origin={0,-40}, + rotation=90), + Line( + points={{-40,0},{-40,-40}}, + color={0,0,0}, + arrow={Arrow.None,Arrow.Filled}, + origin={20,40}, + rotation=90), + Line( + points={{10,0},{-10,0}}, + color={238,46,47}, + thickness=1, + arrow={Arrow.None,Arrow.Filled}, + origin={0,-50}, + rotation=90), + Text( + extent={{-10,12},{10,-12}}, + lineColor={238,46,47}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="x", + origin={0,-46}, + rotation=180), + Line( + points={{-40,-80},{-40,-40}}, + color={0,0,0}, + arrow={Arrow.None,Arrow.Filled}, + origin={-100,40}, + rotation=90)}), + Diagram(coordinateSystem(extent={{-100,-100},{100,100}}))); +end PartialThreeWayValve; diff --git a/SorpLib/Components/Valves/BaseClasses/PartialValve.mo b/SorpLib/Components/Valves/BaseClasses/PartialValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..65eb7387cb94e44d5e805ffcae154777c3794b9e --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/PartialValve.mo @@ -0,0 +1,357 @@ +within SorpLib.Components.Valves.BaseClasses; +partial model PartialValve + "Base model for all valves" + + // + // Definition of parameters regarding the medium + // + parameter Integer no_components = 1 + "Number of components" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true); + + // + // Definition of setup parameters + // + parameter Boolean controllableOpening = false + " = true, if valve opening (i.e., position) is contrallable via an input + signal" + annotation (Dialog(tab="General", group="Valve Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + parameter Real fixedOpening(min=0, max=1) = 0 + "Fixed valve opening (i.e., position) if the valve is not controllable" + annotation (Dialog(tab="General", group="Valve Setup", + enable=not controllableOpening)); + + parameter Boolean useTimeConstant = false + " = true, if time constant is used to delay valve opening (i.e., position)" + annotation (Dialog(tab="General", group="Valve Setup", + enable=controllableOpening), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + parameter Modelica.Units.SI.Time tau = 1 + "Time constant for valve opening (i.e., position)" + annotation (Dialog(tab="General", group="Valve Setup", + enable=controllableOpening and useTimeConstant)); + + parameter Boolean leackage = false + " = true, if valve has a leackage mass flow rate (i.e., minimal opening) to + avoid singularities" + annotation (Dialog(tab="General", group="Valve Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + parameter Real leackageOpening(min=0, max=1) = 1e-3 + "Leackage valve opening (i.e., minimal valve position) to avoid singularities" + annotation (Dialog(tab="General", group="Valve Setup", + enable=leackage)); + + parameter Boolean checkValve = false + " = true, if valve is a check valve (i.e., mass flow direction from port a + to port b)" + annotation (Dialog(tab="General", group="Valve Setup"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + parameter Boolean strictCheckValve = false + " = true, if check valve is strict: Mass can only flow from port a to b; + otherwise, a smoothTransition-function is used that allows minimal mass flow + from port b around the transition point of the check valve (e.g., pressure + difference) but increases numerical stability" + annotation (Dialog(tab="General", group="Valve Setup", + enable=checkValve), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + + // + // Definition of parameters regarding the valve characteristic + // + parameter Boolean accountHydraulicHead = false + " = true, if additional hydraulic head shall be considered to calculate the + driving potential (i.e., pressure difference) for the mass flow rate" + annotation (Dialog(tab="Valve Characteristic", group="Driving Potential"), + choices(checkBox=true), + HideResult=true, + Evaluate=true); + + parameter Modelica.Units.SI.Pressure p_hydraulicHead = 1000 * 9.81 * 0.25 + "Additional hydraulic head (i.e., rho * g * h) used to increase the pressure + at port a (i.e., positive if port a is located higher than port b)" + annotation (Dialog(tab="Valve Characteristic", group="Driving Potential", + enable=accountHydraulicHead)); + + // + // Definition or initialisation parameters + // + parameter Real opening_initial = 1 + "Initial value of valve opening (i.e., position) if valve opening is delayed" + annotation (Dialog(tab="Initialisation", group="Initial Values", + enable=controllableOpening and useTimeConstant)); + + parameter Modelica.Units.SI.MassFlowRate m_flow_start = 1e-4 + "Start value for mass flow rate" + annotation (Dialog(tab="Initialisation", group="Start Values")); + + // + // Definition of advanced parameters + // + parameter Boolean avoid_events = false + "= true, if events are avoid by using noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "Numerics"), + choices(checkBox=true), + Evaluate=true, + HideResult = true); + + // + // Definition of inputs + // + Modelica.Blocks.Interfaces.RealInput opening(min=0, max=1) if + controllableOpening + "Valve opening (i.e., position) input signal" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,70}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,70}))); + + // + // Definition of ports + // + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_a + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=m_flow_start)) + "Fluid port a" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}), + iconTransformation(extent={{-90,-10},{-70,10}})), + choicesAllMatching=true); + + replaceable SorpLib.Basics.Interfaces.BaseClasses.PartialFluidPort port_b + constrainedby Basics.Interfaces.BaseClasses.PartialFluidPort( + final no_components=no_components, + m_flow(start=-m_flow_start)) + "Fluid port b" + annotation (Placement(transformation(extent={{70,-10},{90,10}}), + iconTransformation(extent={{70,-10},{90,10}})), + choicesAllMatching=true); + + // + // Definition of variables + // + Modelica.Units.SI.PressureDifference dp + "Pressure difference between ports"; + Modelica.Units.SI.PressureDifference dp_wHydraulicHead + "Pressure difference between ports when accounting the hydraulic"; + + // + // Definition of blocks + // + Modelica.Blocks.Continuous.CriticalDamping filter( + n=2, + f=5 / (2 * Modelica.Constants.pi * tau), + normalized=true, + initType=Modelica.Blocks.Types.Init.InitialOutput, + y_start=opening_initial) if controllableOpening and useTimeConstant + "Critical damping filter to filter opening signal" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,40})), + HideResult=true); + + SorpLib.Components.Valves.Utilities.Limiter limiter( + lowerLimit=if leackage then leackageOpening else 0, + upperLimit=1) if controllableOpening + "Limits the input signal" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,10})), + HideResult=true); + + // + // Definition of protected connectors + // +protected + Modelica.Blocks.Interfaces.RealInput opening_internal(min=0, max=1) + "Needed for connecting to conditional components"; + + // + // Definition of variables + // + Modelica.Units.SI.PressureDifference dp_ + "Pressure difference used as driving potential to calculate mass flow rate"; + +equation + // + // Assertations + // + if not controllableOpening then + assert(fixedOpening >= 0 and fixedOpening <= 1, + "Fixed opening (" + String(fixedOpening) + ") must between 0 and 1!", + level = AssertionLevel.error); + end if; + + if leackage then + assert(leackageOpening >= 0 and leackageOpening <= 1, + "Leackage opening (" + String(leackageOpening) + ") must between 0 " + + "and 1!", + level = AssertionLevel.error); + end if; + + // + // Momentum balance + // + dp = port_a.p - port_b.p + "Pressure difference between ports"; + dp_wHydraulicHead = (port_a.p + p_hydraulicHead) - port_b.p + "Pressure difference between ports when accounting the hydraulic"; + + dp_ = if accountHydraulicHead then dp_wHydraulicHead else dp + "Pressure difference used as driving potential to calculate mass flow rate"; + + // + // Mass balance + // + 0 = port_a.m_flow + port_b.m_flow + "Steady-state mass balance"; + + port_a.Xi_outflow = inStream(port_b.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + port_b.Xi_outflow = inStream(port_a.Xi_outflow) + "Stream variable: Trivial equation since no change of mass fractions"; + + // + // Energy balance + // + port_a.h_outflow = inStream(port_b.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + port_b.h_outflow = inStream(port_a.h_outflow) + "Stream variable: Trivial equation since no change of energy"; + + // + // Calculate actual opening + // + if not controllableOpening then + opening_internal = if leackage then max(fixedOpening, leackageOpening) else + fixedOpening + "Needed for connecting to conditional components"; + else + if useTimeConstant then + connect(opening, filter.u) + annotation (Line(points={{0,70},{0,52}}, color={0,0,127})); + connect(filter.y, limiter.u) + annotation (Line(points={{0,29},{0,22}}, color={0,0,127})); + + else + connect(opening, limiter.u) + annotation (Line(points={{0,70},{0,22}}, color={0,0,127})); + + end if; + + connect(opening_internal, limiter.y) + "Needed for connecting to conditional components"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model of all valves. It defines fundamental parameters +and variables required by all valves. +<br/><br/> +Models that inherit properties from this partial model have to redeclare the fluid ports. +Furthermore, inherting models may have to add further inputs and a medium model. The following +variables must be specified in the model that inherit properties: +</p> +<ul> + <li> + The flow variable <i>port_a.m_flow</i> that defines the mass flow rate at port a. The + mass flow rate often depends on the pressure difference <i>dp</i> between the two ports + but alternative calculation approaches can also be implemented. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + Major revisions (new functionalities, documentation). + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + Smaller revisions after restructuring of the library. + </li> + <li> + December 11, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>"), Icon(coordinateSystem(extent={{-100,-100},{100,100}}), + graphics={ Line( + points={{0,40},{0,0}}, + color={0,0,0}, + thickness=1), + Polygon( + points={{-80,62},{-80,62}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Polygon( + points={{-80,50},{-80,-50},{0,0},{-80,50}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Polygon( + points={{-40,50},{-40,-50},{40,0},{-40,50}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + origin={40,0}, + rotation=180), + Ellipse( + extent={{-16,60},{16,28}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-10,54},{10,34}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textString="M", + textStyle={TextStyle.Bold}), + Line( + points={{-40,-40},{40,-40}}, + color={0,0,0}, + arrow={Arrow.None,Arrow.Filled}), + Line( + points={{8,-20},{-12,-20}}, + color={238,46,47}, + thickness=1, + arrow={Arrow.None,Arrow.Filled}, + visible=checkValve), + Text( + extent={{-10,-6},{10,-30}}, + lineColor={238,46,47}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + textStyle={TextStyle.Bold}, + textString="x", + visible=checkValve)}), + Diagram(coordinateSystem(extent={{-100,-100},{100,100}}))); +end PartialValve; diff --git a/SorpLib/Components/Valves/BaseClasses/PartialValveCharacteristic.mo b/SorpLib/Components/Valves/BaseClasses/PartialValveCharacteristic.mo new file mode 100644 index 0000000000000000000000000000000000000000..57133aff90523b85292902094408e51e59690e51 --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/PartialValveCharacteristic.mo @@ -0,0 +1,44 @@ +within SorpLib.Components.Valves.BaseClasses; +partial function PartialValveCharacteristic + "Base function for all valve characteristics" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real opening(min=0, max=1) + "Valve opening (i.e., position)" + annotation (Dialog(tab="General", group="Inputs")); + input Real fc_max = 1.6 + "Maximal flow coefficient if valve is completly open" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real fc + "Flow coefficient" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the base function for all valve characteristics. It +definies common inputs and outputs. This partial functions is based on the function +<a href=\"Modelica://Modelica.Fluid.Valves.BaseClasses.ValveCharacteristics.baseFun\">Modelica.Fluid.Valves.BaseClasses.ValveCharacteristics.baseFun</a>. +<br/><br/> +Functions that inherit properties from this partial function may have to add +further inputs and the calculation approach for the valve characteristic +(i.e., <i>fc(opening)</i>). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end PartialValveCharacteristic; diff --git a/SorpLib/Components/Valves/BaseClasses/package.mo b/SorpLib/Components/Valves/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..99492649d3c4806a692eef593728d1ae1f420e68 --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Components.Valves; +package BaseClasses "Base models and functions for all valves" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial valve models and valve characteristic functions, +containing fundamental definitions for valves and their charecteristics. The +content of this package is only of interest when adding new valves to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Components/Valves/BaseClasses/package.order b/SorpLib/Components/Valves/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..7be8b8c08be12509a2d074a121e42ad25af8ea67 --- /dev/null +++ b/SorpLib/Components/Valves/BaseClasses/package.order @@ -0,0 +1,9 @@ +PartialValve +PartialCondensateRefluxValve +PartialOrificeValve +PartialIncompressibleValve +PartialCompressibleValve +PartialThreeWayValve +PartialIncompressibleThreeWayValve +PartialCompressibleThreeWayValve +PartialValveCharacteristic diff --git a/SorpLib/Components/Valves/GasValves/CompressibleThreeWayValve.mo b/SorpLib/Components/Valves/GasValves/CompressibleThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..9ce7b8b1138260480c93d870b877ed71f3310d03 --- /dev/null +++ b/SorpLib/Components/Valves/GasValves/CompressibleThreeWayValve.mo @@ -0,0 +1,163 @@ +within SorpLib.Components.Valves.GasValves; +model CompressibleThreeWayValve + "Three-way valve for compressible fluids" + extends + SorpLib.Components.Valves.BaseClasses.PartialCompressibleThreeWayValve( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_c, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variabbles + // +protected + Medium.ThermodynamicState state_a_in + "Thermodynamic state record with instreaming properties at port a"; + +equation + // + // Calculate fluid properties + // + state_a_in = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1,inStream(port_a.Xi_outflow),{1-sum(inStream(port_a.Xi_outflow))})) + "Thermodynamic state record with instreaming properties at port a"; + + rho_a = Medium.density(state=state_a_in) + "Instreaming density at port a"; + gamma_a = Medium.isentropicExponent( state=state_a_in) + "Instreaming isentropic exponent at port a"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This three-way valve can be applied for compressible fluids, such as air. +The valve splits a mass flow entering port a into two mass flows leaving port b +and c. For thus purpose, the valve position defines the division of the instreaming +mass flow at port a: I.e., for <i>position = 0</i>, the mass flows to port b; +for <i>position = 1</i>, the mass flows to port c. The position can be set by an +input signal. +</p> + +<h4>Main equations</h4> +<p> +The mass flow rates <i>port_b.m_flow</i> and <i>port_c.m_flow</i> are calculated +in dependance of the instreaming pressure <i>p</i>, instreaming density <i>ρ</i>, +and discharge function <i>Ψ<sub>i</sub></i>, following the equation of Bernoulli +for compressible fluids (i.e., equation of Saint-Venant & Wantzel): +</p> +<pre> + port_b.m_flow = -A<sub>eff,b</sub> * <strong>sqrt</strong>(2 * ρ * p) * Ψ<sub>a</sub>; +</pre> +<pre> + port_c.m_flow = -A<sub>eff,c</sub> * <strong>sqrt</strong>(2 * ρ * p) * Ψ<sub>c</sub>; +</pre> +<p> +The effective areas <i>A<sub>eff,i</sub></i> depends on the actual valve position +and are calculated via a linear valve characteristic. For this purpose, the maximal +effective areas <i>A<sub>eff,max,i</sub></i> are required. The maximal effective +areas <i>A<sub>eff,max,i</sub></i> are present if the valve is fully opened and +can directly be specified. Alternatively, they can be calculated using the maximal +flow coefficients <i>Kvs<sub>i</sub></i>, reference densities <i>ρ<sub>ref,i</sub></i>, +and reference pressure drops <i>Δp<sub>ref,i</sub></i>: +</p> +<pre> + <i>A<sub>eff,max,i</sub></i> = Kvs<sub>i</sub> * <strong>sqrt</strong>(ρ<sub>ref,i</sub> / (2 * Δp<sub>ref,i</sub>)); +</pre> +<p> +The discharge functions <i>Ψ<sub>i</sub></i> depend on the pressure ratios between the +outstreaming and instreaming pressures <i>p<sub>out,i</sub>/p<sub>in</sub></i> as long as +the velocity is below the speed of sound. Once the speed of sound is reached, the discharge +functions do not change anymore: +</p> +<pre> + Ψ<sub>i</sub> = <strong>if</strong> p<sub>out,i</sub>/p<sub>in</sub> > (2 / (γ + 1)) ^ (γ / (γ - 1)) <strong>then</strong> + <strong>sqrt</strong>(γ / (γ - 1) * ((p<sub>out,i</sub>/p<sub>in</sub>) ^ (2 / γ) - (p<sub>out,i</sub>/p<sub>in</sub>) ^ ((γ + 1) / γ))) <strong>else</strong> + <strong>sqrt</strong>(2 ^ (2 / (γ - 1)) * γ / (γ + 1) ^ ((γ + 1) / (γ - 1))); +</pre> +<p> +Not that the valve is a check valve, thus mass can only flow from port a to port b and c. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Compressible fluid + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + Isentropic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks of open sorption systems to +split a mass flow rate. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>controllablePosition</i>: + Defines if the valve position can be set via an input signal. + </li> + <li> + <i>useTimeConstant</i>: + Defines if the valve position input signal is delayed by a time constant. + </li> + <li> + <i>leackage</i>: + Defines if the valve has a small leackage flow. + </li> + <br/> + <li> + <i>useKvsValue</i>: + Defines if the mass flow rates at port b and c are calculated using the + Kvs-approach or A_eff-approach. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +The model has two dynamic states if the input signal describing the valve position +is delayed by a time constant. Otherwise, the model has no dynamic states. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CompressibleThreeWayValve; diff --git a/SorpLib/Components/Valves/GasValves/CompressibleValve.mo b/SorpLib/Components/Valves/GasValves/CompressibleValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..736f334f633419ed8ad19fcb182755c90bb38a0a --- /dev/null +++ b/SorpLib/Components/Valves/GasValves/CompressibleValve.mo @@ -0,0 +1,179 @@ +within SorpLib.Components.Valves.GasValves; +model CompressibleValve "Valve for compressible fluids" + extends SorpLib.Components.Valves.BaseClasses.PartialCompressibleValve( + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.GasPort_out port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the ideal gas, ideal gas mixture, or ideal gas-vapor mixture" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variabbles + // +protected + Medium.ThermodynamicState state_a_in + "Thermodynamic state record with instreaming properties at port a"; + Medium.ThermodynamicState state_b_in + "Thermodynamic state record with instreaming properties at port b"; + +equation + // + // Calculate fluid properties + // + state_a_in = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1,inStream(port_a.Xi_outflow),{1-sum(inStream(port_a.Xi_outflow))})) + "Thermodynamic state record with instreaming properties at port a"; + state_b_in = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=cat(1,inStream(port_b.Xi_outflow),{1-sum(inStream(port_b.Xi_outflow))})) + "Thermodynamic state record with instreaming properties at port b"; + + rho_a = Medium.density(state=state_a_in) + "Instreaming density at port a"; + rho_b = Medium.density(state=state_b_in) + "Instreaming density at port b"; + + gamma_a = Medium.isentropicExponent( state=state_a_in) + "Instreaming isentropic exponent at port a"; + gamma_b = Medium.isentropicExponent( state=state_b_in) + "Instreaming isentropic exponent at port b"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This valve can be applied for compressible fluids, such as air. The valve opening +(i.e., position) can be set via an input signal. The valve can be used as a simple +on/off valve (i.e., opening = 0/1) or as a control valve by setting the valve opening +betwenn 0 and 1. +</p> + +<h4>Main equations</h4> +<p> +The mass flow rate <i>port_a.m_flow</i> is calculated in dependance of the instreaming +pressure <i>p</i>, instreaming density <i>ρ</i>, and discharge function <i>Ψ</i>, +following the equation of Bernoulli for compressible fluids (i.e., equation of Saint-Venant +& Wantzel): +</p> +<pre> + port_a.m_flow = A<sub>eff</sub> * <strong>sqrt</strong>(2 * ρ * p) * Ψ; +</pre> +<p> +The effective area <i>A<sub>eff</sub></i> depends on the actual valve opening (i.e., +position) and is calculated via the selected +<a href=\"Modelica://SorpLib.Components.Valves.ValveCharacteristics\">valve characteristic</a>). +For this purpose, the maximal effective area <i>A<sub>eff,max</sub></i> is required. +The maximal effective area <i>A<sub>eff,max</sub></i> is present if the valve is fully +opened and can directly be specified. Alternatively, it can be calculated using the maximal +flow coefficient <i>Kvs</i>, reference density <i>ρ<sub>ref</sub></i>, and reference +pressure drop <i>Δp<sub>ref</sub></i>: +</p> +<pre> + <i>A<sub>eff,max</sub></i> = Kvs * <strong>sqrt</strong>(ρ<sub>ref</sub> / (2 * Δp<sub>ref</sub>)); +</pre> +<p> +The discharge function <i>Ψ</i> depends on the pressure ratio between the outstreaming and +instreaming pressure <i>p<sub>out</sub>/p<sub>in</sub></i> as long as the velocity is below the +speed of sound. Once the speed of sound is reached, the discharge function does not change anymore: +</p> +<pre> + Ψ = <strong>if</strong> p<sub>out</sub>/p<sub>in</sub> > (2 / (γ + 1)) ^ (γ / (γ - 1)) <strong>then</strong> + <strong>sqrt</strong>(γ / (γ - 1) * ((p<sub>out</sub>/p<sub>in</sub>) ^ (2 / γ) - (p<sub>out</sub>/p<sub>in</sub>) ^ ((γ + 1) / γ))) <strong>else</strong> + <strong>sqrt</strong>(2 ^ (2 / (γ - 1)) * γ / (γ + 1) ^ ((γ + 1) / (γ - 1))); +</pre> +<p> +To account for the flow direction, the root expression is calculated using the anti-symmetric +root approximation +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +Furthermore, the valve can be a check valve (see options). If the valve is a check valve, mass +can only flow from port a to port b. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Compressible fluid + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + Isentropic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks of open sorption systems. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>controllableOpening</i>: + Defines if the valve opening can be set via an input signal. + </li> + <li> + <i>useTimeConstant</i>: + Defines if the valve opening input signal is delayed by a time constant. + </li> + <li> + <i>leackage</i>: + Defines if the valve has a small leackage flow. + </li> + <li> + <i>checkValve</i>: + Defines if the valve is a strict check valve, thus only allowing a mass flow from + port a to port b. + </li> + <br/> + <li> + <i>useKvsValue</i>: + Defines if the mass flow rate is calculated using the Kvs-approach or A_eff-approach. + </li> + <li> + <i>valveCharacteristic</i>: + Defines the valve characteristic (see + <a href=\"Modelica://SorpLib.Components.Valves.ValveCharacteristics\">SorpLib.Components.Valves.ValveCharacteristics</a>). + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +The model has two dynamic states if the input signal describing the valve opening is +delayed by a time constant. Otherwise, the model has no dynamic states. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CompressibleValve; diff --git a/SorpLib/Components/Valves/GasValves/Tester/Test_CompressibleThreeWayValve.mo b/SorpLib/Components/Valves/GasValves/Tester/Test_CompressibleThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..8019765466278d1a1b81b243c324e3388a3d42b2 --- /dev/null +++ b/SorpLib/Components/Valves/GasValves/Tester/Test_CompressibleThreeWayValve.mo @@ -0,0 +1,178 @@ +within SorpLib.Components.Valves.GasValves.Tester; +model Test_CompressibleThreeWayValve + "Tester for the three-way valve for compressible fluids" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource[3] fs_a( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each p_fixed(displayUnit="bar") = 100000, + each T_fixed=373.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource[3] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source b" + annotation (Placement(transformation(extent={{70,40},{50,60}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource[3] fs_c( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source c" + annotation (Placement(transformation(extent={{70,-40},{50,-60}}))); + + // + // Definition of valves + // + SorpLib.Components.Valves.GasValves.CompressibleThreeWayValve threeWayValve( + controllablePosition=true) + "Three-way valve: Controllable, no time constant, no leackage" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,40}))); + + SorpLib.Components.Valves.GasValves.CompressibleThreeWayValve threeWayValve_delay( + controllablePosition=true, + useTimeConstant=true, + tau=10, + position_initial=0) + "Three-way valve: Controllable, time constant, no leackage" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,0}))); + + SorpLib.Components.Valves.GasValves.CompressibleThreeWayValve threeWayValve_delay_leackage( + controllablePosition=true, + useTimeConstant=true, + leackage=true, + position_initial=0) + "Three-way valve: Controllable, time constant, leackage" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,-40}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Trapezoid input_lRel( + amplitude=1, + rising=150, + width=50, + falling=0, + period=250, + offset=0) + "Input signal for relative filling level" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, + rotation=270, + origin={10,90}))); + + Modelica.Blocks.Sources.Sine input_p_b( + amplitude=-0.4e5, + f=1/100, + offset=1e5) "Input signal for pressure at port b" + annotation (Placement(transformation(extent={{100,40},{80,60}}))); + Modelica.Blocks.Sources.Sine input_T( + amplitude=25, + f=1/100, + offset=273.15 + 150) + "Input signal for temperature" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + Modelica.Blocks.Sources.Sine input_p_c( + amplitude=-0.4e5, + f=1/100, + offset=1e5) "Input signal for pressure at port c" + annotation (Placement(transformation(extent={{100,-60},{80,-40}}))); + +equation + // + // Connections + // + connect(fs_a[1].port, threeWayValve.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,40},{-7.8,40}}, + color={244,125,35}, + thickness=1)); + connect(fs_a[2].port, threeWayValve_delay.port_a) annotation (Line( + points={{-60,0},{-7.8,0}}, + color={244,125,35}, + thickness=1)); + connect(fs_a[3].port, threeWayValve_delay_leackage.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,-40},{-7.8,-40}}, + color={244,125,35}, + thickness=1)); + connect(threeWayValve.port_b, fs_b[1].port) annotation (Line( + points={{0,48},{0,50},{60,50}}, + color={244,125,35}, + thickness=1)); + connect(threeWayValve_delay.port_b, fs_b[2].port) annotation (Line( + points={{0,8},{0,10},{20,10},{20,50},{60,50}}, + color={244,125,35}, + thickness=1)); + connect(threeWayValve_delay_leackage.port_b, fs_b[3].port) annotation (Line( + points={{0,-32},{0,-30},{20,-30},{20,50},{60,50}}, + color={244,125,35}, + thickness=1)); + connect(threeWayValve.port_c, fs_c[1].port) annotation (Line( + points={{0,32},{0,30},{40,30},{40,-50},{60,-50}}, + color={244,125,35}, + thickness=1)); + connect(threeWayValve_delay.port_c, fs_c[2].port) annotation (Line( + points={{0,-8},{0,-10},{40,-10},{40,-50},{60,-50}}, + color={244,125,35}, + thickness=1)); + connect(threeWayValve_delay_leackage.port_c, fs_c[3].port) annotation (Line( + points={{0,-48},{0,-50},{60,-50}}, + color={244,125,35}, + thickness=1)); + + for ind in 1:3 loop + connect(input_T.y, fs_b[ind].T_input) annotation (Line(points={{79,0},{70,0}, + {70,48},{61.2,48}}, + color={0,0,127})); + connect(input_T.y, fs_c[ind].T_input) annotation (Line(points={{79,0},{70,0},{70, + -48},{61.2,-48}}, color={0,0,127})); + + connect(input_p_b.y, fs_b[ind].p_input) annotation (Line(points={{79,50},{70, + 50},{70,55},{61.2,55}}, color={0,0,127})); + connect(input_p_c.y, fs_c[ind].p_input) annotation (Line(points={{79,-50},{70,-50}, + {70,-55},{61.2,-55}}, color={0,0,127})); + end for; + + connect(input_lRel.y, threeWayValve.position) + annotation (Line(points={{10,79},{10,40},{7,40}}, color={0,0,127})); + connect(input_lRel.y, threeWayValve_delay.position) + annotation (Line(points={{10,79},{10,0},{7,0}}, color={0,0,127})); + connect(input_lRel.y, threeWayValve_delay_leackage.position) + annotation (Line(points={{10,79},{10,-40},{7,-40}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the compressible three-way valve. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_CompressibleThreeWayValve; diff --git a/SorpLib/Components/Valves/GasValves/Tester/Test_CompressibleValve.mo b/SorpLib/Components/Valves/GasValves/Tester/Test_CompressibleValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..8e287c9f8e519d43f0da4c074861a373eace4fe1 --- /dev/null +++ b/SorpLib/Components/Valves/GasValves/Tester/Test_CompressibleValve.mo @@ -0,0 +1,286 @@ +within SorpLib.Components.Valves.GasValves.Tester; +model Test_CompressibleValve + "Tester for the valve for compressible fluids" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource[9] fs_a( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each p_fixed(displayUnit="bar") = 100000, + each T_fixed=373.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.GasVaporMixtureSource[9] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of valves + // + SorpLib.Components.Valves.GasValves.CompressibleValve valve_controllable_Kvs_cType1( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=1) "Compressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,80},{10,100}}))); + SorpLib.Components.Valves.GasValves.CompressibleValve valve_controllable_Kvs_cType2( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=2) "Compressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,60},{10,80}}))); + SorpLib.Components.Valves.GasValves.CompressibleValve valve_controllable_Kvs_cType3( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=3) "Compressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,40},{10,60}}))); + + SorpLib.Components.Valves.GasValves.CompressibleValve valve_controllable_delay_Kvs_cType1( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=1, + opening_initial=0) "Compressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + SorpLib.Components.Valves.GasValves.CompressibleValve valve_controllable_delay_Kvs_cType2( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=2, + opening_initial=0) "Compressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + SorpLib.Components.Valves.GasValves.CompressibleValve valve_controllable_delay_Kvs_cType3( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=3, + opening_initial=0) "Compressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + + SorpLib.Components.Valves.GasValves.CompressibleValve valve_controllable_delay_leackage_check_Kvs_cType1( + controllableOpening=true, + useTimeConstant=true, + tau=1, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=1, + opening_initial=0) "Compressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,-60},{10,-40}}))); + SorpLib.Components.Valves.GasValves.CompressibleValve valve_controllable_delay_leackage_check_Kvs_cType2( + controllableOpening=true, + useTimeConstant=true, + tau=1, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=2, + opening_initial=0) "Compressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,-80},{10,-60}}))); + SorpLib.Components.Valves.GasValves.CompressibleValve valve_controllable_delay_leackage_check_Kvs_cType3( + controllableOpening=true, + useTimeConstant=true, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=3, + opening_initial=0) "Compressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,-100},{10,-80}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Trapezoid input_lRel( + amplitude=1, + rising=150, + width=50, + falling=0, + period=250, + offset=0) + "Input signal for relative filling level" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + + Modelica.Blocks.Sources.Sine input_p( + amplitude=-0.4e5, + f=1/100, + offset=1e5) + "Input signal for pressure" + annotation (Placement(transformation(extent={{100,10},{80,30}}))); + Modelica.Blocks.Sources.Sine input_T( + amplitude=25, + f=1/100, + offset=273.15 + 150) + "Input signal for temperature" + annotation (Placement(transformation(extent={{100,-30},{80,-10}}))); + +equation + // + // Connections + // + connect(fs_a[1].port, valve_controllable_Kvs_cType1.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,90},{-8,90}}, + color={244,125,35}, + thickness=1)); + connect(fs_a[2].port, valve_controllable_Kvs_cType2.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,70},{-8,70}}, + color={244,125,35}, + thickness=1)); + connect(fs_a[3].port, valve_controllable_Kvs_cType3.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,50},{-8,50}}, + color={244,125,35}, + thickness=1)); + connect(fs_a[4].port, valve_controllable_delay_Kvs_cType1.port_a) annotation ( + Line( + points={{-60,0},{-20,0},{-20,20},{-8,20}}, + color={244,125,35}, + thickness=1)); + connect(fs_a[5].port, valve_controllable_delay_Kvs_cType2.port_a) annotation ( + Line( + points={{-60,0},{-8,0}}, + color={244,125,35}, + thickness=1)); + connect(fs_a[6].port, valve_controllable_delay_Kvs_cType3.port_a) annotation ( + Line( + points={{-60,0},{-20,0},{-20,-20},{-8,-20}}, + color={244,125,35}, + thickness=1)); + connect(fs_a[7].port, valve_controllable_delay_leackage_check_Kvs_cType1.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-50},{-8,-50}}, + color={244,125,35}, + thickness=1)); + connect(fs_a[8].port, valve_controllable_delay_leackage_check_Kvs_cType2.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-70},{-8,-70}}, + color={244,125,35}, + thickness=1)); + connect(fs_a[9].port, valve_controllable_delay_leackage_check_Kvs_cType3.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-90},{-8,-90}}, + color={244,125,35}, + thickness=1)); + + connect(fs_b[1].port, valve_controllable_Kvs_cType1.port_b) annotation (Line( + points={{60,0},{20,0},{20,90},{8,90}}, + color={244,125,35}, + thickness=1)); + connect(fs_b[2].port, valve_controllable_Kvs_cType2.port_b) annotation (Line( + points={{60,0},{20,0},{20,70},{8,70}}, + color={244,125,35}, + thickness=1)); + connect(fs_b[3].port, valve_controllable_Kvs_cType3.port_b) annotation (Line( + points={{60,0},{20,0},{20,50},{8,50}}, + color={244,125,35}, + thickness=1)); + connect(fs_b[4].port, valve_controllable_delay_Kvs_cType1.port_b) annotation ( + Line( + points={{60,0},{20,0},{20,20},{8,20}}, + color={244,125,35}, + thickness=1)); + connect(fs_b[5].port, valve_controllable_delay_Kvs_cType2.port_b) annotation ( + Line( + points={{60,0},{8,0}}, + color={244,125,35}, + thickness=1)); + connect(fs_b[6].port, valve_controllable_delay_Kvs_cType3.port_b) annotation ( + Line( + points={{60,0},{20,0},{20,-20},{8,-20}}, + color={244,125,35}, + thickness=1)); + connect(fs_b[7].port, valve_controllable_delay_leackage_check_Kvs_cType1.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-50},{8,-50}}, + color={244,125,35}, + thickness=1)); + connect(fs_b[8].port, valve_controllable_delay_leackage_check_Kvs_cType2.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-70},{8,-70}}, + color={244,125,35}, + thickness=1)); + connect(fs_b[9].port, valve_controllable_delay_leackage_check_Kvs_cType3.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-90},{8,-90}}, + color={244,125,35}, + thickness=1)); + + for ind in 1:9 loop + connect(input_T.y, fs_b[ind].T_input) annotation (Line(points={{79,-20},{70, + -20},{70,-2},{61.2,-2}}, + color={0,0,127})); + connect(input_p.y, fs_b[ind].p_input) + annotation (Line(points={{79,20},{70,20},{70,5},{61.2,5}}, + color={0,0,127})); + end for; + + connect(input_lRel.y, valve_controllable_Kvs_cType1.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,97},{0,97}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_Kvs_cType2.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,77},{0,77}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_Kvs_cType3.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,57},{0,57}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType1.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,27},{0,27}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType2.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,7},{0,7}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType3.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-13},{0,-13}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType1.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-43},{0,-43}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType2.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-63},{0,-63}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType3.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-83},{0,-83}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the compressible valve. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_CompressibleValve; diff --git a/SorpLib/Components/Valves/GasValves/Tester/package.mo b/SorpLib/Components/Valves/GasValves/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b1f0bdf4b1f6bfc8b0990d9ff17e34a5b1e34c7b --- /dev/null +++ b/SorpLib/Components/Valves/GasValves/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Valves.GasValves; +package Tester "Models to test and varify models for gas valves" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented gas, gas mixture, +and gas-vapor mixture valves. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Valves/GasValves/Tester/package.order b/SorpLib/Components/Valves/GasValves/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..042bf5b6265ad491a0284320e42a179f201bcad0 --- /dev/null +++ b/SorpLib/Components/Valves/GasValves/Tester/package.order @@ -0,0 +1,2 @@ +Test_CompressibleValve +Test_CompressibleThreeWayValve diff --git a/SorpLib/Components/Valves/GasValves/package.mo b/SorpLib/Components/Valves/GasValves/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b7084979ac8aba2ea73ea411165d710223ccb03a --- /dev/null +++ b/SorpLib/Components/Valves/GasValves/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Valves; +package GasValves "Gas, gas mixture, and gas-vapor mixture valves" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains gas, gas mixture, and gas-vapor mixture valves based on +the open-source Modelica Standard Library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end GasValves; diff --git a/SorpLib/Components/Valves/GasValves/package.order b/SorpLib/Components/Valves/GasValves/package.order new file mode 100644 index 0000000000000000000000000000000000000000..d872a20c405e05a505b7fd6613f4a63f18d4e777 --- /dev/null +++ b/SorpLib/Components/Valves/GasValves/package.order @@ -0,0 +1,3 @@ +CompressibleValve +CompressibleThreeWayValve +Tester diff --git a/SorpLib/Components/Valves/LiquidValves/IncompressibleThreeWayValve.mo b/SorpLib/Components/Valves/LiquidValves/IncompressibleThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..078d7e9335442863de714cabda55946a7dd42ecd --- /dev/null +++ b/SorpLib/Components/Valves/LiquidValves/IncompressibleThreeWayValve.mo @@ -0,0 +1,138 @@ +within SorpLib.Components.Valves.LiquidValves; +model IncompressibleThreeWayValve + "Three-way valve for incompressible fluids" + extends + SorpLib.Components.Valves.BaseClasses.PartialIncompressibleThreeWayValve( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_c, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculate fluid properties + // + rho_a = Medium.density_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1,inStream(port_a.Xi_outflow),{1-sum(inStream(port_a.Xi_outflow))})) + "Instreaming density at port a"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This three-way valve can be applied for incompressible fluids, such as liquid water. +The valve splits a mass flow entering port a into two mass flows leaving port b +and c. For thus purpose, the valve position defines the division of the instreaming +mass flow at port a: I.e., for <i>position = 0</i>, the mass flows to port b; +for <i>position = 1</i>, the mass flows to port c. The position can be set by an +input signal. +</p> + +<h4>Main equations</h4> +<p> +The mass flow rates <i>port_b.m_flow</i> and <i>port_c.m_flow</i> are calculated +in dependance of the pressure drops <i>Δp<sub>ab</sub> = port_a.p - port_b.p</i>, +and <i>Δp<sub>ac</sub> = port_a.p - port_c.p</i>, following the equation of +Bernoulli for incompressible fluids: +</p> +<pre> + port_b.m_flow = -A<sub>eff,b</sub> * <strong>sqrt</strong>(2 * ρ * Δp<sub>ab</sub>) *(1 - position); +</pre> +<pre> + port_c.m_flow = -A<sub>eff,c</sub> * <strong>sqrt</strong>(2 * ρ * Δp<sub>ac</sub>) * position; +</pre> +<p> +The effective areas <i>A<sub>eff,i</sub></i> depends on the actual valve position +and are calculated via a linear valve characteristic. For this purpose, the maximal +effective areas <i>A<sub>eff,max,i</sub></i> are required. The maximal effective +areas <i>A<sub>eff,max,i</sub></i> are present if the valve is fully opened and +can directly be specified. Alternatively, they can be calculated using the maximal +flow coefficients <i>Kvs<sub>i</sub></i>, reference densities <i>ρ<sub>ref,i</sub></i>, +and reference pressure drops <i>Δp<sub>ref,i</sub></i>: +</p> +<pre> + <i>A<sub>eff,max,i</sub></i> = Kvs<sub>i</sub> * <strong>sqrt</strong>(ρ<sub>ref,i</sub> / (2 * Δp<sub>ref,i</sub>)); +</pre> +<p> +The density <i>ρ</i> corresponds to the inlet density of the actual flow +direction. Note that the valve is a strict check valve, thus mass can only flow +from port a to port b and c. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Incompressible fluid + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks of closed sorption systems to +split a mass flow rate. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>controllablePosition</i>: + Defines if the valve position can be set via an input signal. + </li> + <li> + <i>useTimeConstant</i>: + Defines if the valve position input signal is delayed by a time constant. + </li> + <li> + <i>leackage</i>: + Defines if the valve has a small leackage flow. + </li> + <br/> + <li> + <i>useKvsValue</i>: + Defines if the mass flow rates at port b and c are calculated using the + Kvs-approach or A_eff-approach. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +The model has two dynamic states if the input signal describing the valve position +is delayed by a time constant. Otherwise, the model has no dynamic states. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end IncompressibleThreeWayValve; diff --git a/SorpLib/Components/Valves/LiquidValves/IncompressibleValve.mo b/SorpLib/Components/Valves/LiquidValves/IncompressibleValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..2d9391b289ef6ff94249bcac937b2f4235901548 --- /dev/null +++ b/SorpLib/Components/Valves/LiquidValves/IncompressibleValve.mo @@ -0,0 +1,151 @@ +within SorpLib.Components.Valves.LiquidValves; +model IncompressibleValve "Valve for incompressible fluids" + extends SorpLib.Components.Valves.BaseClasses.PartialIncompressibleValve( + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.LiquidPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_R1pT + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model of the (ideal) liquid" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculate fluid properties + // + rho_a = Medium.density_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1,inStream(port_a.Xi_outflow),{1-sum(inStream(port_a.Xi_outflow))})) + "Instreaming density at port a"; + rho_b = Medium.density_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=cat(1,inStream(port_b.Xi_outflow),{1-sum(inStream(port_b.Xi_outflow))})) + "Instreaming density at port b"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This valve can be applied for incompressible fluids, such as liquid water. The valve +opening (i.e., position) can be set via an input signal. The valve can be used as a +simple on/off valve (i.e., opening = 0/1) or as a control valve by setting the valve +opening betwenn 0 and 1. +</p> + +<h4>Main equations</h4> +<p> +The mass flow rate <i>port_a.m_flow</i> is calculated in dependance of the pressure +drop <i>Δp = (port_a.p + Δp<sub>hydraulic head</sub>) - port_b.p</i>, +which can be increased by accounting a hydaulic head (see options), following the +equation of Bernoulli for incompressible fluids: +</p> +<pre> + port_a.m_flow = A<sub>eff</sub> * <strong>sqrt</strong>(2 * ρ * Δp); +</pre> +<p> +The effective area <i>A<sub>eff</sub></i> depends on the actual valve opening (i.e., +position) and is calculated via the selected +<a href=\"Modelica://SorpLib.Components.Valves.ValveCharacteristics\">valve characteristic</a>). +For this purpose, the maximal effective area <i>A<sub>eff,max</sub></i> is required. +The maximal effective area <i>A<sub>eff,max</sub></i> is present if the valve is fully +opened and can directly be specified. Alternatively, it can be calculated using the maximal +flow coefficient <i>Kvs</i>, reference density <i>ρ<sub>ref</sub></i>, and reference +pressure drop <i>Δp<sub>ref</sub></i>: +</p> +<pre> + <i>A<sub>eff,max</sub></i> = Kvs * <strong>sqrt</strong>(ρ<sub>ref</sub> / (2 * Δp<sub>ref</sub>)); +</pre> +<p> +The density <i>ρ</i> corresponds to the inlet density of the actual flow direction. +To account for the flow direction, the root expression is calculated using the anti-symmetric +root approximation +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +Furthermore, the valve can be a check valve (see options). If the valve is a check valve, mass +can only flow from port a to port b. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Incompressible fluid + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks of closed sorption systems. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>controllableOpening</i>: + Defines if the valve opening can be set via an input signal. + </li> + <li> + <i>useTimeConstant</i>: + Defines if the valve opening input signal is delayed by a time constant. + </li> + <li> + <i>leackage</i>: + Defines if the valve has a small leackage flow. + </li> + <li> + <i>checkValve</i>: + Defines if the valve is a strict check valve, thus only allowing a mass flow from + port a to port b. + </li> + <br/> + <li> + <i>useKvsValue</i>: + Defines if the mass flow rate is calculated using the Kvs-approach or A_eff-approach. + </li> + <li> + <i>valveCharacteristic</i>: + Defines the valve characteristic (see + <a href=\"Modelica://SorpLib.Components.Valves.ValveCharacteristics\">SorpLib.Components.Valves.ValveCharacteristics</a>). + </li> + <li> + <i>accountHydraulicHead</i>: + Defines if a hydraulic head is used to increase the pressure at port a. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +The model has two dynamic states if the input signal describing the valve opening is +delayed by a time constant. Otherwise, the model has no dynamic states. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end IncompressibleValve; diff --git a/SorpLib/Components/Valves/LiquidValves/Tester/Test_IncompressibleThreeWayValve.mo b/SorpLib/Components/Valves/LiquidValves/Tester/Test_IncompressibleThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..8bc4185bed89a948e83ff6dbf2d21a68c78fe25c --- /dev/null +++ b/SorpLib/Components/Valves/LiquidValves/Tester/Test_IncompressibleThreeWayValve.mo @@ -0,0 +1,178 @@ +within SorpLib.Components.Valves.LiquidValves.Tester; +model Test_IncompressibleThreeWayValve + "Tester for the three-way valve for incompressible fluids" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource[3] fs_a( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each p_fixed(displayUnit="bar") = 1000000, + each T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource[3] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source b" + annotation (Placement(transformation(extent={{70,40},{50,60}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource[3] fs_c( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source c" + annotation (Placement(transformation(extent={{70,-40},{50,-60}}))); + + // + // Definition of valves + // + SorpLib.Components.Valves.LiquidValves.IncompressibleThreeWayValve threeWayValve( + controllablePosition=true) + "Three-way valve: Controllable, no time constant, no leackage" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,40}))); + + SorpLib.Components.Valves.LiquidValves.IncompressibleThreeWayValve threeWayValve_delay( + controllablePosition=true, + useTimeConstant=true, + tau=10, + position_initial=0) + "Three-way valve: Controllable, time constant, no leackage" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,0}))); + + SorpLib.Components.Valves.LiquidValves.IncompressibleThreeWayValve threeWayValve_delay_leackage( + controllablePosition=true, + useTimeConstant=true, + leackage=true, + position_initial=0) + "Three-way valve: Controllable, time constant, leackage" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,-40}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Trapezoid input_lRel( + amplitude=1, + rising=150, + width=50, + falling=0, + period=250, + offset=0) + "Input signal for relative filling level" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, + rotation=270, + origin={10,90}))); + + Modelica.Blocks.Sources.Sine input_p_b( + amplitude=-1e5, + f=1/100, + offset=10e5) "Input signal for pressure at port b" + annotation (Placement(transformation(extent={{100,40},{80,60}}))); + Modelica.Blocks.Sources.Sine input_T( + amplitude=25, + f=1/100, + offset=273.15 + 50) + "Input signal for temperature" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + Modelica.Blocks.Sources.Sine input_p_c( + amplitude=-1e5, + f=1/100, + offset=10e5) "Input signal for pressure at port c" + annotation (Placement(transformation(extent={{100,-60},{80,-40}}))); + +equation + // + // Connections + // + connect(fs_a[1].port, threeWayValve.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,40},{-7.8,40}}, + color={28,108,200}, + thickness=1)); + connect(fs_a[2].port, threeWayValve_delay.port_a) annotation (Line( + points={{-60,0},{-7.8,0}}, + color={28,108,200}, + thickness=1)); + connect(fs_a[3].port, threeWayValve_delay_leackage.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,-40},{-7.8,-40}}, + color={28,108,200}, + thickness=1)); + connect(threeWayValve.port_b, fs_b[1].port) annotation (Line( + points={{0,48},{0,50},{60,50}}, + color={28,108,200}, + thickness=1)); + connect(threeWayValve_delay.port_b, fs_b[2].port) annotation (Line( + points={{0,8},{0,10},{20,10},{20,50},{60,50}}, + color={28,108,200}, + thickness=1)); + connect(threeWayValve_delay_leackage.port_b, fs_b[3].port) annotation (Line( + points={{0,-32},{0,-30},{20,-30},{20,50},{60,50}}, + color={28,108,200}, + thickness=1)); + connect(threeWayValve.port_c, fs_c[1].port) annotation (Line( + points={{0,32},{0,30},{40,30},{40,-50},{60,-50}}, + color={28,108,200}, + thickness=1)); + connect(threeWayValve_delay.port_c, fs_c[2].port) annotation (Line( + points={{0,-8},{0,-10},{40,-10},{40,-50},{60,-50}}, + color={28,108,200}, + thickness=1)); + connect(threeWayValve_delay_leackage.port_c, fs_c[3].port) annotation (Line( + points={{0,-48},{0,-50},{60,-50}}, + color={28,108,200}, + thickness=1)); + + for ind in 1:3 loop + connect(input_T.y, fs_b[ind].T_input) annotation (Line(points={{79,0},{70,0}, + {70,48},{61.2,48}}, + color={0,0,127})); + connect(input_T.y, fs_c[ind].T_input) annotation (Line(points={{79,0},{70,0},{70, + -48},{61.2,-48}}, color={0,0,127})); + + connect(input_p_b.y, fs_b[ind].p_input) annotation (Line(points={{79,50},{70, + 50},{70,55},{61.2,55}}, color={0,0,127})); + connect(input_p_c.y, fs_c[ind].p_input) annotation (Line(points={{79,-50},{70,-50}, + {70,-55},{61.2,-55}}, color={0,0,127})); + end for; + + connect(input_lRel.y, threeWayValve.position) + annotation (Line(points={{10,79},{10,40},{7,40}}, color={0,0,127})); + connect(input_lRel.y, threeWayValve_delay.position) + annotation (Line(points={{10,79},{10,0},{7,0}}, color={0,0,127})); + connect(input_lRel.y, threeWayValve_delay_leackage.position) + annotation (Line(points={{10,79},{10,-40},{7,-40}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the incompressible three-way valve. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_IncompressibleThreeWayValve; diff --git a/SorpLib/Components/Valves/LiquidValves/Tester/Test_IncompressibleValve.mo b/SorpLib/Components/Valves/LiquidValves/Tester/Test_IncompressibleValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..aae46f2365e91da21dc3e3b154afa97a180761a3 --- /dev/null +++ b/SorpLib/Components/Valves/LiquidValves/Tester/Test_IncompressibleValve.mo @@ -0,0 +1,280 @@ +within SorpLib.Components.Valves.LiquidValves.Tester; +model Test_IncompressibleValve + "Tester for the valve for incompressible fluids" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.LiquidSource[9] fs_a( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each p_fixed(displayUnit="bar") = 1000000, + each T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.LiquidSource[9] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of valves + // + SorpLib.Components.Valves.LiquidValves.IncompressibleValve valve_controllable_Kvs_cType1( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=1) "Incompressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,80},{10,100}}))); + SorpLib.Components.Valves.LiquidValves.IncompressibleValve valve_controllable_Kvs_cType2( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=2) "Incompressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,60},{10,80}}))); + SorpLib.Components.Valves.LiquidValves.IncompressibleValve valve_controllable_Kvs_cType3( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=3) "Incompressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,40},{10,60}}))); + + SorpLib.Components.Valves.LiquidValves.IncompressibleValve valve_controllable_delay_Kvs_cType1( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=1, + opening_initial=0) "Incompressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + SorpLib.Components.Valves.LiquidValves.IncompressibleValve valve_controllable_delay_Kvs_cType2( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=2, + opening_initial=0) "Incompressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + SorpLib.Components.Valves.LiquidValves.IncompressibleValve valve_controllable_delay_Kvs_cType3( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=3, + opening_initial=0) "Incompressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + + SorpLib.Components.Valves.LiquidValves.IncompressibleValve valve_controllable_delay_leackage_check_Kvs_cType1( + controllableOpening=true, + useTimeConstant=true, + tau=1, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=1, + opening_initial=0) "Incompressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,-60},{10,-40}}))); + SorpLib.Components.Valves.LiquidValves.IncompressibleValve valve_controllable_delay_leackage_check_Kvs_cType2( + controllableOpening=true, + useTimeConstant=true, + tau=1, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=2, + opening_initial=0) "Incompressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,-80},{10,-60}}))); + SorpLib.Components.Valves.LiquidValves.IncompressibleValve valve_controllable_delay_leackage_check_Kvs_cType3( + controllableOpening=true, + useTimeConstant=true, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=3, + opening_initial=0) "Incompressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,-100},{10,-80}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Trapezoid input_lRel( + amplitude=1, + rising=150, + width=50, + falling=0, + period=250, + offset=0) + "Input signal for relative filling level" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + + Modelica.Blocks.Sources.Sine input_T( + amplitude=25, + f=1/100, + offset=273.15 + 50) + "Input signal for temperature" + annotation (Placement(transformation(extent={{100,-30},{80,-10}}))); + +equation + // + // Connections + // + connect(fs_a[1].port, valve_controllable_Kvs_cType1.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,90},{-8,90}}, + color={28,108,200}, + thickness=1)); + connect(fs_a[2].port, valve_controllable_Kvs_cType2.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,70},{-8,70}}, + color={28,108,200}, + thickness=1)); + connect(fs_a[3].port, valve_controllable_Kvs_cType3.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,50},{-8,50}}, + color={28,108,200}, + thickness=1)); + connect(fs_a[4].port, valve_controllable_delay_Kvs_cType1.port_a) annotation ( + Line( + points={{-60,0},{-20,0},{-20,20},{-8,20}}, + color={28,108,200}, + thickness=1)); + connect(fs_a[5].port, valve_controllable_delay_Kvs_cType2.port_a) annotation ( + Line( + points={{-60,0},{-8,0}}, + color={28,108,200}, + thickness=1)); + connect(fs_a[6].port, valve_controllable_delay_Kvs_cType3.port_a) annotation ( + Line( + points={{-60,0},{-20,0},{-20,-20},{-8,-20}}, + color={28,108,200}, + thickness=1)); + connect(fs_a[7].port, valve_controllable_delay_leackage_check_Kvs_cType1.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-50},{-8,-50}}, + color={28,108,200}, + thickness=1)); + connect(fs_a[8].port, valve_controllable_delay_leackage_check_Kvs_cType2.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-70},{-8,-70}}, + color={28,108,200}, + thickness=1)); + connect(fs_a[9].port, valve_controllable_delay_leackage_check_Kvs_cType3.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-90},{-8,-90}}, + color={28,108,200}, + thickness=1)); + + connect(fs_b[1].port, valve_controllable_Kvs_cType1.port_b) annotation (Line( + points={{60,0},{20,0},{20,90},{8,90}}, + color={28,108,200}, + thickness=1)); + connect(fs_b[2].port, valve_controllable_Kvs_cType2.port_b) annotation (Line( + points={{60,0},{20,0},{20,70},{8,70}}, + color={28,108,200}, + thickness=1)); + connect(fs_b[3].port, valve_controllable_Kvs_cType3.port_b) annotation (Line( + points={{60,0},{20,0},{20,50},{8,50}}, + color={28,108,200}, + thickness=1)); + connect(fs_b[4].port, valve_controllable_delay_Kvs_cType1.port_b) annotation ( + Line( + points={{60,0},{20,0},{20,20},{8,20}}, + color={28,108,200}, + thickness=1)); + connect(fs_b[5].port, valve_controllable_delay_Kvs_cType2.port_b) annotation ( + Line( + points={{60,0},{8,0}}, + color={28,108,200}, + thickness=1)); + connect(fs_b[6].port, valve_controllable_delay_Kvs_cType3.port_b) annotation ( + Line( + points={{60,0},{20,0},{20,-20},{8,-20}}, + color={28,108,200}, + thickness=1)); + connect(fs_b[7].port, valve_controllable_delay_leackage_check_Kvs_cType1.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-50},{8,-50}}, + color={28,108,200}, + thickness=1)); + connect(fs_b[8].port, valve_controllable_delay_leackage_check_Kvs_cType2.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-70},{8,-70}}, + color={28,108,200}, + thickness=1)); + connect(fs_b[9].port, valve_controllable_delay_leackage_check_Kvs_cType3.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-90},{8,-90}}, + color={28,108,200}, + thickness=1)); + + for ind in 1:9 loop + connect(input_T.y, fs_b[ind].T_input) annotation (Line(points={{79,-20},{70, + -20},{70,-2},{61.2,-2}}, + color={0,0,127})); + connect(input_p.y, fs_b[ind].p_input) + annotation (Line(points={{79,20},{70,20},{70,5},{61.2,5}}, + color={0,0,127})); + end for; + + connect(input_lRel.y, valve_controllable_Kvs_cType1.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,97},{0,97}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_Kvs_cType2.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,77},{0,77}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_Kvs_cType3.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,57},{0,57}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType1.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,27},{0,27}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType2.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,7},{0,7}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType3.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-13},{0,-13}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType1.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-43},{0,-43}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType2.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-63},{0,-63}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType3.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-83},{0,-83}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the incompressible valve. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_IncompressibleValve; diff --git a/SorpLib/Components/Valves/LiquidValves/Tester/package.mo b/SorpLib/Components/Valves/LiquidValves/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c71ffaad269a6973bca1a5c6d16f7626865ba7dc --- /dev/null +++ b/SorpLib/Components/Valves/LiquidValves/Tester/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Components.Valves.LiquidValves; +package Tester "Models to test and varify models for liquid valves" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented liquid valves. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Valves/LiquidValves/Tester/package.order b/SorpLib/Components/Valves/LiquidValves/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..dc575e297a10b36660661cd54cd2e6a81c3b3754 --- /dev/null +++ b/SorpLib/Components/Valves/LiquidValves/Tester/package.order @@ -0,0 +1,2 @@ +Test_IncompressibleValve +Test_IncompressibleThreeWayValve diff --git a/SorpLib/Components/Valves/LiquidValves/package.mo b/SorpLib/Components/Valves/LiquidValves/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b231388abf89177d33a078e71d6fd8866776321c --- /dev/null +++ b/SorpLib/Components/Valves/LiquidValves/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Valves; +package LiquidValves "Liquid valves" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains liquid valves based on the open-source Modelica Standard +Library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end LiquidValves; diff --git a/SorpLib/Components/Valves/LiquidValves/package.order b/SorpLib/Components/Valves/LiquidValves/package.order new file mode 100644 index 0000000000000000000000000000000000000000..163bd3d82d40f1cb6c7c41a637de4a8950cd3dca --- /dev/null +++ b/SorpLib/Components/Valves/LiquidValves/package.order @@ -0,0 +1,3 @@ +IncompressibleValve +IncompressibleThreeWayValve +Tester diff --git a/SorpLib/Components/Valves/Utilities/Limiter.mo b/SorpLib/Components/Valves/Utilities/Limiter.mo new file mode 100644 index 0000000000000000000000000000000000000000..90fc75130ddcb2c6264f167bb83583943c35e746 --- /dev/null +++ b/SorpLib/Components/Valves/Utilities/Limiter.mo @@ -0,0 +1,61 @@ +within SorpLib.Components.Valves.Utilities; +block Limiter + "Limiter that limits a signal to an upper and a lower bound" + extends Modelica.Blocks.Interfaces.SISO; + + // + // Definition of parameters + // + parameter Real lowerLimit = 0 + "Lower limit" + annotation (Dialog(tab="General", group="Limits")); + parameter Real upperLimit = 1 + "Upper limit" + annotation (Dialog(tab="General", group="Limits")); + +equation + // + // Assertations + // + assert(upperLimit >= lowerLimit, + "Limits must be consistent, but upper limit (" + String(upperLimit) + + ") is greater than lower limit (" + String(upperLimit) + ")!", + level = AssertionLevel.error); + + // + // Limit signal + // + y = smooth(0, max(min(u, upperLimit), lowerLimit)) + "Limited input signal"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This blocks limit the input signal <i>u</i> to the lower limit <i>lowerLimit</i> +and upper limit <i>upperLimit</i>. This block is a simplified version of +<a href=\"Modelica://Modelica.Blocks.Nonlinear.Limiter\">Modelica.Blocks.Nonlinear.Limiter</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), Icon(graphics={ + Polygon( + points={{0,90},{-8,68},{8,68},{0,90}}, + lineColor={192,192,192}, + fillColor={192,192,192}, + fillPattern=FillPattern.Solid), + Line(points={{0,-90},{0,68}}, color={192,192,192}), + Line(points={{-90,0},{68,0}}, color={192,192,192}), + Polygon( + points={{90,0},{68,-8},{68,8},{90,0}}, + lineColor={192,192,192}, + fillColor={192,192,192}, + fillPattern=FillPattern.Solid), + Line(points={{-80,-70},{-50,-70},{50,70},{80,70}})})); +end Limiter; diff --git a/SorpLib/Components/Valves/Utilities/mixStreamVariables.mo b/SorpLib/Components/Valves/Utilities/mixStreamVariables.mo new file mode 100644 index 0000000000000000000000000000000000000000..4556f3785e509698147573a6cec049b5461dc412 --- /dev/null +++ b/SorpLib/Components/Valves/Utilities/mixStreamVariables.mo @@ -0,0 +1,61 @@ +within SorpLib.Components.Valves.Utilities; +function mixStreamVariables + "Function mixing two stream variables of three-way valves" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MassFlowRate m_flow_1 + "Flow variable of first stream variable" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MassFlowRate m_flow_2 + "Flow variable of second stream variable" + annotation (Dialog(tab="General", group="Inputs")); + + input Real streamVariable_1 + "First stream variable" + annotation (Dialog(tab="General", group="Inputs")); + input Real streamVariable_2 + "Second stream variable" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real mixedStreamVariable + "Mixed stream variable" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of constants + // + + +algorithm + mixedStreamVariable := (streamVariable_1 * (max(m_flow_1,0) + + max(-m_flow_2,0) + 0.5*Modelica.Constants.eps) + streamVariable_2 * + (max(m_flow_2,0) + max(-m_flow_1,0) +0.5*Modelica.Constants.eps)) / + (abs(m_flow_1) + abs(m_flow_2) + Modelica.Constants.eps) + "Mixed stream variable"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function mixes two stream variables as required by three-way valves. The +function is based on the Modelica Standard library (MSL) +(<a href=\"Modelica://Modelica.Fluid.Fittings.MultiPort\">Modelica.Fluid.Fittings.MultiPort</a>) +and TIL library +(<a href=\"Modelica://TIL.Internals.joiningTwoStreams\">TIL.Internals.joiningTwoStreams</a>). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end mixStreamVariables; diff --git a/SorpLib/Components/Valves/Utilities/package.mo b/SorpLib/Components/Valves/Utilities/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..630a1ae4f57bd1009e7156613fd9b218ca23061f --- /dev/null +++ b/SorpLib/Components/Valves/Utilities/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Components.Valves; +package Utilities "Utility models and functions for all valves" + extends Modelica.Icons.UtilitiesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains utility models and functions used to create valve models. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Utilities; diff --git a/SorpLib/Components/Valves/Utilities/package.order b/SorpLib/Components/Valves/Utilities/package.order new file mode 100644 index 0000000000000000000000000000000000000000..632068b05c07e685db4f819bc63aa21873450478 --- /dev/null +++ b/SorpLib/Components/Valves/Utilities/package.order @@ -0,0 +1,2 @@ +Limiter +mixStreamVariables diff --git a/SorpLib/Components/Valves/VLEValves/CompressibleThreeWayValve.mo b/SorpLib/Components/Valves/VLEValves/CompressibleThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..007e6dfc0af20a6eea9de9b20ae3b073f3d8f636 --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/CompressibleThreeWayValve.mo @@ -0,0 +1,163 @@ +within SorpLib.Components.Valves.VLEValves; +model CompressibleThreeWayValve + "Three-way valve for compressible fluids" + extends + SorpLib.Components.Valves.BaseClasses.PartialCompressibleThreeWayValve( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_c, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variabbles + // +protected + Medium.ThermodynamicState state_a_in + "Thermodynamic state record with instreaming properties at port a"; + +equation + // + // Calculate fluid properties + // + state_a_in = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1,inStream(port_a.Xi_outflow),{1-sum(inStream(port_a.Xi_outflow))})) + "Thermodynamic state record with instreaming properties at port a"; + + rho_a = Medium.density(state=state_a_in) + "Instreaming density at port a"; + gamma_a = Medium.isentropicExponent( state=state_a_in) + "Instreaming isentropic exponent at port a"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This three-way valve can be applied for compressible fluids, such as air. +The valve splits a mass flow entering port a into two mass flows leaving port b +and c. For thus purpose, the valve position defines the division of the instreaming +mass flow at port a: I.e., for <i>position = 0</i>, the mass flows to port b; +for <i>position = 1</i>, the mass flows to port c. The position can be set by an +input signal. +</p> + +<h4>Main equations</h4> +<p> +The mass flow rates <i>port_b.m_flow</i> and <i>port_c.m_flow</i> are calculated +in dependance of the instreaming pressure <i>p</i>, instreaming density <i>ρ</i>, +and discharge function <i>Ψ<sub>i</sub></i>, following the equation of Bernoulli +for compressible fluids (i.e., equation of Saint-Venant & Wantzel): +</p> +<pre> + port_b.m_flow = -A<sub>eff,b</sub> * <strong>sqrt</strong>(2 * ρ * p) * Ψ<sub>a</sub>; +</pre> +<pre> + port_c.m_flow = -A<sub>eff,c</sub> * <strong>sqrt</strong>(2 * ρ * p) * Ψ<sub>c</sub>; +</pre> +<p> +The effective areas <i>A<sub>eff,i</sub></i> depends on the actual valve position +and are calculated via a linear valve characteristic. For this purpose, the maximal +effective areas <i>A<sub>eff,max,i</sub></i> are required. The maximal effective +areas <i>A<sub>eff,max,i</sub></i> are present if the valve is fully opened and +can directly be specified. Alternatively, they can be calculated using the maximal +flow coefficients <i>Kvs<sub>i</sub></i>, reference densities <i>ρ<sub>ref,i</sub></i>, +and reference pressure drops <i>Δp<sub>ref,i</sub></i>: +</p> +<pre> + <i>A<sub>eff,max,i</sub></i> = Kvs<sub>i</sub> * <strong>sqrt</strong>(ρ<sub>ref,i</sub> / (2 * Δp<sub>ref,i</sub>)); +</pre> +<p> +The discharge functions <i>Ψ<sub>i</sub></i> depend on the pressure ratios between the +outstreaming and instreaming pressures <i>p<sub>out,i</sub>/p<sub>in</sub></i> as long as +the velocity is below the speed of sound. Once the speed of sound is reached, the discharge +functions do not change anymore: +</p> +<pre> + Ψ<sub>i</sub> = <strong>if</strong> p<sub>out,i</sub>/p<sub>in</sub> > (2 / (γ + 1)) ^ (γ / (γ - 1)) <strong>then</strong> + <strong>sqrt</strong>(γ / (γ - 1) * ((p<sub>out,i</sub>/p<sub>in</sub>) ^ (2 / γ) - (p<sub>out,i</sub>/p<sub>in</sub>) ^ ((γ + 1) / γ))) <strong>else</strong> + <strong>sqrt</strong>(2 ^ (2 / (γ - 1)) * γ / (γ + 1) ^ ((γ + 1) / (γ - 1))); +</pre> +<p> +Not that the valve is a check valve, thus mass can only flow from port a to port b and c. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Compressible fluid + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + Isentropic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks of open sorption systems to +split a mass flow rate. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>controllablePosition</i>: + Defines if the valve position can be set via an input signal. + </li> + <li> + <i>useTimeConstant</i>: + Defines if the valve position input signal is delayed by a time constant. + </li> + <li> + <i>leackage</i>: + Defines if the valve has a small leackage flow. + </li> + <br/> + <li> + <i>useKvsValue</i>: + Defines if the mass flow rates at port b and c are calculated using the + Kvs-approach or A_eff-approach. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +The model has two dynamic states if the input signal describing the valve position +is delayed by a time constant. Otherwise, the model has no dynamic states. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CompressibleThreeWayValve; diff --git a/SorpLib/Components/Valves/VLEValves/CompressibleValve.mo b/SorpLib/Components/Valves/VLEValves/CompressibleValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..bc126ad786f4706bc4bb1438d1f97d371f91c56b --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/CompressibleValve.mo @@ -0,0 +1,179 @@ +within SorpLib.Components.Valves.VLEValves; +model CompressibleValve "Valve for compressible fluids" + extends SorpLib.Components.Valves.BaseClasses.PartialCompressibleValve( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Definition of variabbles + // +protected + Medium.ThermodynamicState state_a_in + "Thermodynamic state record with instreaming properties at port a"; + Medium.ThermodynamicState state_b_in + "Thermodynamic state record with instreaming properties at port b"; + +equation + // + // Calculate fluid properties + // + state_a_in = Medium.setState_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1,inStream(port_a.Xi_outflow),{1-sum(inStream(port_a.Xi_outflow))})) + "Thermodynamic state record with instreaming properties at port a"; + state_b_in = Medium.setState_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=cat(1,inStream(port_b.Xi_outflow),{1-sum(inStream(port_b.Xi_outflow))})) + "Thermodynamic state record with instreaming properties at port b"; + + rho_a = Medium.density(state=state_a_in) + "Instreaming density at port a"; + rho_b = Medium.density(state=state_b_in) + "Instreaming density at port b"; + + gamma_a = Medium.isentropicExponent( state=state_a_in) + "Instreaming isentropic exponent at port a"; + gamma_b = Medium.isentropicExponent( state=state_b_in) + "Instreaming isentropic exponent at port b"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This valve can be applied for compressible fluids, such as air. The valve opening +(i.e., position) can be set via an input signal. The valve can be used as a simple +on/off valve (i.e., opening = 0/1) or as a control valve by setting the valve opening +betwenn 0 and 1. +</p> + +<h4>Main equations</h4> +<p> +The mass flow rate <i>port_a.m_flow</i> is calculated in dependance of the instreaming +pressure <i>p</i>, instreaming density <i>ρ</i>, and discharge function <i>Ψ</i>, +following the equation of Bernoulli for compressible fluids (i.e., equation of Saint-Venant +& Wantzel): +</p> +<pre> + port_a.m_flow = A<sub>eff</sub> * <strong>sqrt</strong>(2 * ρ * p) * Ψ; +</pre> +<p> +The effective area <i>A<sub>eff</sub></i> depends on the actual valve opening (i.e., +position) and is calculated via the selected +<a href=\"Modelica://SorpLib.Components.Valves.ValveCharacteristics\">valve characteristic</a>). +For this purpose, the maximal effective area <i>A<sub>eff,max</sub></i> is required. +The maximal effective area <i>A<sub>eff,max</sub></i> is present if the valve is fully +opened and can directly be specified. Alternatively, it can be calculated using the maximal +flow coefficient <i>Kvs</i>, reference density <i>ρ<sub>ref</sub></i>, and reference +pressure drop <i>Δp<sub>ref</sub></i>: +</p> +<pre> + <i>A<sub>eff,max</sub></i> = Kvs * <strong>sqrt</strong>(ρ<sub>ref</sub> / (2 * Δp<sub>ref</sub>)); +</pre> +<p> +The discharge function <i>Ψ</i> depends on the pressure ratio between the outstreaming and +instreaming pressure <i>p<sub>out</sub>/p<sub>in</sub></i> as long as the velocity is below the +speed of sound. Once the speed of sound is reached, the discharge function does not change anymore: +</p> +<pre> + Ψ = <strong>if</strong> p<sub>out</sub>/p<sub>in</sub> > (2 / (γ + 1)) ^ (γ / (γ - 1)) <strong>then</strong> + <strong>sqrt</strong>(γ / (γ - 1) * ((p<sub>out</sub>/p<sub>in</sub>) ^ (2 / γ) - (p<sub>out</sub>/p<sub>in</sub>) ^ ((γ + 1) / γ))) <strong>else</strong> + <strong>sqrt</strong>(2 ^ (2 / (γ - 1)) * γ / (γ + 1) ^ ((γ + 1) / (γ - 1))); +</pre> +<p> +To account for the flow direction, the root expression is calculated using the anti-symmetric +root approximation +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +Furthermore, the valve can be a check valve (see options). If the valve is a check valve, mass +can only flow from port a to port b. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Compressible fluid + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + Isentropic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks of open sorption systems. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>controllableOpening</i>: + Defines if the valve opening can be set via an input signal. + </li> + <li> + <i>useTimeConstant</i>: + Defines if the valve opening input signal is delayed by a time constant. + </li> + <li> + <i>leackage</i>: + Defines if the valve has a small leackage flow. + </li> + <li> + <i>checkValve</i>: + Defines if the valve is a strict check valve, thus only allowing a mass flow from + port a to port b. + </li> + <br/> + <li> + <i>useKvsValue</i>: + Defines if the mass flow rate is calculated using the Kvs-approach or A_eff-approach. + </li> + <li> + <i>valveCharacteristic</i>: + Defines the valve characteristic (see + <a href=\"Modelica://SorpLib.Components.Valves.ValveCharacteristics\">SorpLib.Components.Valves.ValveCharacteristics</a>). + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +The model has two dynamic states if the input signal describing the valve opening is +delayed by a time constant. Otherwise, the model has no dynamic states. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CompressibleValve; diff --git a/SorpLib/Components/Valves/VLEValves/CondensateRefluxValve.mo b/SorpLib/Components/Valves/VLEValves/CondensateRefluxValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..94cbfe5ab7a46b3d0c407b7fca94e0dd5994f610 --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/CondensateRefluxValve.mo @@ -0,0 +1,122 @@ +within SorpLib.Components.Valves.VLEValves; +model CondensateRefluxValve + "Condensate reflux valve" + extends SorpLib.Components.Valves.BaseClasses.PartialCondensateRefluxValve( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The control valve acts as a simple P-like controler to regulate a process variable +(e.g., the relative filling level in a phase separator volume) to its setpoint via +the mass flow through the valve. +</p> + +<h4>Main equations</h4> +<p> +Three characteristics are available for the control behavior: A constant mass flow, +a mass flow that is linear to the deviation from the setpoint, and a mass flow that +is quadratic to the deviation from the setpoint: +</p> +<pre> + 'Constant': port_a.m_flow = <strong>if</strong> (processVariable - setPoint) > 0 <strong>then</strong> m_flow_constant <strong>else</strong> -m_flow_constant; +</pre> +<pre> + 'Linear': port_a.m_flow = (processVariable - setPoint) * kp<sub>linear</sub>; +</pre> +<pre> + 'Quadratic': port_a.m_flow = (processVariable - setPoint)<sup>2</sup> * kp<sub>quadratic</sub>; +</pre> + +<p> +If the valve is a check valve (see options), mass can only flow from port a to port +b. To achiev this, the valve can act a 'normal' check valve or a 'strict' check +valve. A 'normal' check valve regulates the mass flow rate to zero if the process +variables reaches its setpoint via the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition\">SorpLib.Numerics.smoothTransition</a>. +Thus, minimal mass flows from port b to port a are possible, which can increase +the numerical stability of the model. These mass flows are not necessarily possible +in reality, but they are usually so small that the error is negligible. In contract, +a 'strict' check valve strictly regulates the mass flow rate to zero if the process +variables reaches its setpoint, and now flow reversal is possible. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Incompressible fluid + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No change in kinetic and potential energy between inlet and outlet + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in closed sorption systems (e.g., adsorption chillers) +to return the condensate from the condenser into the evaporator. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>checkValve</i>: + Defines if the valve is a check valve, thus only allowing a mass flow from port + a to port b except for a minor mass flow rate from port b to port a to increase + numerical stability. + </li> + <li> + <i>strictCheckValve</i>: + Defines if the valve is a strict check valve, thus only allowing a mass flow + from port a to port b. + </li> + <br/> + <li> + <i>controlType</i>: + Defines the control type for determining the mass flow rate at port a (see main + equations). + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + Major revisions (new functionalities, documentation). + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CondensateRefluxValve; diff --git a/SorpLib/Components/Valves/VLEValves/IncompressibleThreeWayValve.mo b/SorpLib/Components/Valves/VLEValves/IncompressibleThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..ebb9772e83f1e2ea4fe4dd512ae191f0a5d5aee7 --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/IncompressibleThreeWayValve.mo @@ -0,0 +1,139 @@ +within SorpLib.Components.Valves.VLEValves; +model IncompressibleThreeWayValve + "Three-way valve for incompressible fluids" + extends + SorpLib.Components.Valves.BaseClasses.PartialIncompressibleThreeWayValve( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_c, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculate fluid properties + // + rho_a = Medium.density_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1,inStream(port_a.Xi_outflow),{1-sum(inStream(port_a.Xi_outflow))})) + "Instreaming density at port a"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This three-way valve can be applied for incompressible fluids, such as liquid water. +The valve splits a mass flow entering port a into two mass flows leaving port b +and c. For thus purpose, the valve position defines the division of the instreaming +mass flow at port a: I.e., for <i>position = 0</i>, the mass flows to port b; +for <i>position = 1</i>, the mass flows to port c. The position can be set by an +input signal. +</p> + +<h4>Main equations</h4> +<p> +The mass flow rates <i>port_b.m_flow</i> and <i>port_c.m_flow</i> are calculated +in dependance of the pressure drops <i>Δp<sub>ab</sub> = port_a.p - port_b.p</i>, +and <i>Δp<sub>ac</sub> = port_a.p - port_c.p</i>, following the equation of +Bernoulli for incompressible fluids: +</p> +<pre> + port_b.m_flow = -A<sub>eff,b</sub> * <strong>sqrt</strong>(2 * ρ * Δp<sub>ab</sub>) *(1 - position); +</pre> +<pre> + port_c.m_flow = -A<sub>eff,c</sub> * <strong>sqrt</strong>(2 * ρ * Δp<sub>ac</sub>) * position; +</pre> +<p> +The effective areas <i>A<sub>eff,i</sub></i> depends on the actual valve position +and are calculated via a linear valve characteristic. For this purpose, the maximal +effective areas <i>A<sub>eff,max,i</sub></i> are required. The maximal effective +areas <i>A<sub>eff,max,i</sub></i> are present if the valve is fully opened and +can directly be specified. Alternatively, they can be calculated using the maximal +flow coefficients <i>Kvs<sub>i</sub></i>, reference densities <i>ρ<sub>ref,i</sub></i>, +and reference pressure drops <i>Δp<sub>ref,i</sub></i>: +</p> +<pre> + <i>A<sub>eff,max,i</sub></i> = Kvs<sub>i</sub> * <strong>sqrt</strong>(ρ<sub>ref,i</sub> / (2 * Δp<sub>ref,i</sub>)); +</pre> +<p> +The density <i>ρ</i> corresponds to the inlet density of the actual flow +direction. Note that the valve is a strict check valve, thus mass can only flow +from port a to port b and c. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Incompressible fluid + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks of closed sorption systems to +split a mass flow rate. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>controllablePosition</i>: + Defines if the valve position can be set via an input signal. + </li> + <li> + <i>useTimeConstant</i>: + Defines if the valve position input signal is delayed by a time constant. + </li> + <li> + <i>leackage</i>: + Defines if the valve has a small leackage flow. + </li> + <br/> + <li> + <i>useKvsValue</i>: + Defines if the mass flow rates at port b and c are calculated using the + Kvs-approach or A_eff-approach. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +The model has two dynamic states if the input signal describing the valve position +is delayed by a time constant. Otherwise, the model has no dynamic states. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end IncompressibleThreeWayValve; diff --git a/SorpLib/Components/Valves/VLEValves/IncompressibleValve.mo b/SorpLib/Components/Valves/VLEValves/IncompressibleValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..187ff8a19720aaf1cbaf3617abffea3d10904766 --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/IncompressibleValve.mo @@ -0,0 +1,152 @@ +within SorpLib.Components.Valves.VLEValves; +model IncompressibleValve "Valve for incompressible fluids" + extends SorpLib.Components.Valves.BaseClasses.PartialIncompressibleValve( + redeclare final Basics.Interfaces.FluidPorts.VLEPort_out port_b, + redeclare final Basics.Interfaces.FluidPorts.VLEPort_in port_a, + final no_components=Medium.nX); + + // + // Definition of parameters regarding the medium + // + replaceable package Medium = + Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium model of the real fluid (i.e., with two-phase regime)" + annotation (Dialog(tab="General", group="Medium"), + Evaluate=true, + HideResult=true, + choicesAllMatching=true); + +equation + // + // Calculate fluid properties + // + rho_a = Medium.density_phX( + p=port_a.p, + h=inStream(port_a.h_outflow), + X=cat(1,inStream(port_a.Xi_outflow),{1-sum(inStream(port_a.Xi_outflow))})) + "Instreaming density at port a"; + rho_b = Medium.density_phX( + p=port_b.p, + h=inStream(port_b.h_outflow), + X=cat(1,inStream(port_b.Xi_outflow),{1-sum(inStream(port_b.Xi_outflow))})) + "Instreaming density at port b"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This valve can be applied for incompressible fluids, such as liquid water. The valve +opening (i.e., position) can be set via an input signal. The valve can be used as a +simple on/off valve (i.e., opening = 0/1) or as a control valve by setting the valve +opening betwenn 0 and 1. +</p> + +<h4>Main equations</h4> +<p> +The mass flow rate <i>port_a.m_flow</i> is calculated in dependance of the pressure +drop <i>Δp = (port_a.p + Δp<sub>hydraulic head</sub>) - port_b.p</i>, +which can be increased by accounting a hydaulic head (see options), following the +equation of Bernoulli for incompressible fluids: +</p> +<pre> + port_a.m_flow = A<sub>eff</sub> * <strong>sqrt</strong>(2 * ρ * Δp); +</pre> +<p> +The effective area <i>A<sub>eff</sub></i> depends on the actual valve opening (i.e., +position) and is calculated via the selected +<a href=\"Modelica://SorpLib.Components.Valves.ValveCharacteristics\">valve characteristic</a>). +For this purpose, the maximal effective area <i>A<sub>eff,max</sub></i> is required. +The maximal effective area <i>A<sub>eff,max</sub></i> is present if the valve is fully +opened and can directly be specified. Alternatively, it can be calculated using the maximal +flow coefficient <i>Kvs</i>, reference density <i>ρ<sub>ref</sub></i>, and reference +pressure drop <i>Δp<sub>ref</sub></i>: +</p> +<pre> + <i>A<sub>eff,max</sub></i> = Kvs * <strong>sqrt</strong>(ρ<sub>ref</sub> / (2 * Δp<sub>ref</sub>)); +</pre> +<p> +The density <i>ρ</i> corresponds to the inlet density of the actual flow direction. +To account for the flow direction, the root expression is calculated using the anti-symmetric +root approximation +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +Furthermore, the valve can be a check valve (see options). If the valve is a check valve, mass +can only flow from port a to port b. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Incompressible fluid + </li> + <li> + Adiabatic process + </li> + <li> + Isenthalpic process + </li> + <li> + No storage of mass or energy + </li> +</ul> + +<h4>Typical use</h4> +<p> +The valve is typically used in hydraulic networks of closed sorption systems. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + <i>controllableOpening</i>: + Defines if the valve opening can be set via an input signal. + </li> + <li> + <i>useTimeConstant</i>: + Defines if the valve opening input signal is delayed by a time constant. + </li> + <li> + <i>leackage</i>: + Defines if the valve has a small leackage flow. + </li> + <li> + <i>checkValve</i>: + Defines if the valve is a strict check valve, thus only allowing a mass flow from + port a to port b. + </li> + <br/> + <li> + <i>useKvsValue</i>: + Defines if the mass flow rate is calculated using the Kvs-approach or A_eff-approach. + </li> + <li> + <i>valveCharacteristic</i>: + Defines the valve characteristic (see + <a href=\"Modelica://SorpLib.Components.Valves.ValveCharacteristics\">SorpLib.Components.Valves.ValveCharacteristics</a>). + </li> + <li> + <i>accountHydraulicHead</i>: + Defines if a hydraulic head is used to increase the pressure at port a. + </li> + <br/> + <li> + <i>avoid_events</i>: + Defines if events shall be avoided via the noEvent()-operator. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +The model has two dynamic states if the input signal describing the valve opening is +delayed by a time constant. Otherwise, the model has no dynamic states. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end IncompressibleValve; diff --git a/SorpLib/Components/Valves/VLEValves/Tester/Test_CompressibleThreeWayValve.mo b/SorpLib/Components/Valves/VLEValves/Tester/Test_CompressibleThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..b9d7ea00c31afe9b36b73abbe90862f643d0e888 --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/Tester/Test_CompressibleThreeWayValve.mo @@ -0,0 +1,180 @@ +within SorpLib.Components.Valves.VLEValves.Tester; +model Test_CompressibleThreeWayValve + "Tester for the three-way valve for compressible fluids" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource[3] fs_a( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each p_fixed(displayUnit="bar") = 50000, + each T_fixed=373.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource[3] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source b" + annotation (Placement(transformation(extent={{70,40},{50,60}}))); + + SorpLib.Basics.Sources.Fluids.VLESource[3] fs_c( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source c" + annotation (Placement(transformation(extent={{70,-40},{50,-60}}))); + + // + // Definition of valves + // + SorpLib.Components.Valves.VLEValves.CompressibleThreeWayValve threeWayValve( + controllablePosition=true) + "Three-way valve: Controllable, no time constant, no leackage" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,40}))); + + SorpLib.Components.Valves.VLEValves.CompressibleThreeWayValve threeWayValve_delay( + controllablePosition=true, + useTimeConstant=true, + tau=10, + position_initial=0) + "Three-way valve: Controllable, time constant, no leackage" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,0}))); + + SorpLib.Components.Valves.VLEValves.CompressibleThreeWayValve threeWayValve_delay_leackage( + controllablePosition=true, + useTimeConstant=true, + leackage=true, + position_initial=0) + "Three-way valve: Controllable, time constant, leackage" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,-40}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Trapezoid input_lRel( + amplitude=1, + rising=150, + width=50, + falling=0, + period=250, + offset=0) + "Input signal for relative filling level" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, + rotation=270, + origin={10,90}))); + + Modelica.Blocks.Sources.Sine input_p_b( + amplitude=-0.4e5, + f=1/100, + offset=0.5e5) + "Input signal for pressure at port b" + annotation (Placement(transformation(extent={{100,40},{80,60}}))); + Modelica.Blocks.Sources.Sine input_T( + amplitude=25, + f=1/100, + offset=273.15 + 150) + "Input signal for temperature" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + Modelica.Blocks.Sources.Sine input_p_c( + amplitude=-0.4e5, + f=1/100, + offset=0.5e5) + "Input signal for pressure at port c" + annotation (Placement(transformation(extent={{100,-60},{80,-40}}))); + +equation + // + // Connections + // + connect(fs_a[1].port, threeWayValve.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,40},{-7.8,40}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[2].port, threeWayValve_delay.port_a) annotation (Line( + points={{-60,0},{-7.8,0}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[3].port, threeWayValve_delay_leackage.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,-40},{-7.8,-40}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve.port_b, fs_b[1].port) annotation (Line( + points={{0,48},{0,50},{60,50}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve_delay.port_b, fs_b[2].port) annotation (Line( + points={{0,8},{0,10},{20,10},{20,50},{60,50}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve_delay_leackage.port_b, fs_b[3].port) annotation (Line( + points={{0,-32},{0,-30},{20,-30},{20,50},{60,50}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve.port_c, fs_c[1].port) annotation (Line( + points={{0,32},{0,30},{40,30},{40,-50},{60,-50}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve_delay.port_c, fs_c[2].port) annotation (Line( + points={{0,-8},{0,-10},{40,-10},{40,-50},{60,-50}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve_delay_leackage.port_c, fs_c[3].port) annotation (Line( + points={{0,-48},{0,-50},{60,-50}}, + color={0,140,72}, + thickness=1)); + + for ind in 1:3 loop + connect(input_T.y, fs_b[ind].T_input) annotation (Line(points={{79,0},{70,0}, + {70,48},{61.2,48}}, + color={0,0,127})); + connect(input_T.y, fs_c[ind].T_input) annotation (Line(points={{79,0},{70,0},{70, + -48},{61.2,-48}}, color={0,0,127})); + + connect(input_p_b.y, fs_b[ind].p_input) annotation (Line(points={{79,50},{70, + 50},{70,55},{61.2,55}}, color={0,0,127})); + connect(input_p_c.y, fs_c[ind].p_input) annotation (Line(points={{79,-50},{70,-50}, + {70,-55},{61.2,-55}}, color={0,0,127})); + end for; + + connect(input_lRel.y, threeWayValve.position) + annotation (Line(points={{10,79},{10,40},{7,40}}, color={0,0,127})); + connect(input_lRel.y, threeWayValve_delay.position) + annotation (Line(points={{10,79},{10,0},{7,0}}, color={0,0,127})); + connect(input_lRel.y, threeWayValve_delay_leackage.position) + annotation (Line(points={{10,79},{10,-40},{7,-40}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the compressible three-way valve. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_CompressibleThreeWayValve; diff --git a/SorpLib/Components/Valves/VLEValves/Tester/Test_CompressibleValve.mo b/SorpLib/Components/Valves/VLEValves/Tester/Test_CompressibleValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..53d564827b896a87be7807a9a0f56d31ba875d43 --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/Tester/Test_CompressibleValve.mo @@ -0,0 +1,286 @@ +within SorpLib.Components.Valves.VLEValves.Tester; +model Test_CompressibleValve + "Tester for the valve for compressible fluids" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource[9] fs_a( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each p_fixed(displayUnit="bar") = 50000, + each T_fixed=373.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource[9] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of valves + // + SorpLib.Components.Valves.VLEValves.CompressibleValve valve_controllable_Kvs_cType1( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=1) "Compressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,80},{10,100}}))); + SorpLib.Components.Valves.VLEValves.CompressibleValve valve_controllable_Kvs_cType2( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=2) "Compressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,60},{10,80}}))); + SorpLib.Components.Valves.VLEValves.CompressibleValve valve_controllable_Kvs_cType3( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=3) "Compressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,40},{10,60}}))); + + SorpLib.Components.Valves.VLEValves.CompressibleValve valve_controllable_delay_Kvs_cType1( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=1, + opening_initial=0) "Compressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + SorpLib.Components.Valves.VLEValves.CompressibleValve valve_controllable_delay_Kvs_cType2( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=2, + opening_initial=0) "Compressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + SorpLib.Components.Valves.VLEValves.CompressibleValve valve_controllable_delay_Kvs_cType3( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=3, + opening_initial=0) "Compressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + + SorpLib.Components.Valves.VLEValves.CompressibleValve valve_controllable_delay_leackage_check_Kvs_cType1( + controllableOpening=true, + useTimeConstant=true, + tau=1, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=1, + opening_initial=0) "Compressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,-60},{10,-40}}))); + SorpLib.Components.Valves.VLEValves.CompressibleValve valve_controllable_delay_leackage_check_Kvs_cType2( + controllableOpening=true, + useTimeConstant=true, + tau=1, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=2, + opening_initial=0) "Compressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,-80},{10,-60}}))); + SorpLib.Components.Valves.VLEValves.CompressibleValve valve_controllable_delay_leackage_check_Kvs_cType3( + controllableOpening=true, + useTimeConstant=true, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=3, + opening_initial=0) "Compressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,-100},{10,-80}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Trapezoid input_lRel( + amplitude=1, + rising=150, + width=50, + falling=0, + period=250, + offset=0) + "Input signal for relative filling level" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + + Modelica.Blocks.Sources.Sine input_p( + amplitude=-0.4e5, + f=1/100, + offset=0.5e5) + "Input signal for pressure" + annotation (Placement(transformation(extent={{100,10},{80,30}}))); + Modelica.Blocks.Sources.Sine input_T( + amplitude=25, + f=1/100, + offset=273.15 + 150) + "Input signal for temperature" + annotation (Placement(transformation(extent={{100,-30},{80,-10}}))); + +equation + // + // Connections + // + connect(fs_a[1].port, valve_controllable_Kvs_cType1.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,90},{-8,90}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[2].port, valve_controllable_Kvs_cType2.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,70},{-8,70}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[3].port, valve_controllable_Kvs_cType3.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,50},{-8,50}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[4].port, valve_controllable_delay_Kvs_cType1.port_a) annotation ( + Line( + points={{-60,0},{-20,0},{-20,20},{-8,20}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[5].port, valve_controllable_delay_Kvs_cType2.port_a) annotation ( + Line( + points={{-60,0},{-8,0}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[6].port, valve_controllable_delay_Kvs_cType3.port_a) annotation ( + Line( + points={{-60,0},{-20,0},{-20,-20},{-8,-20}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[7].port, valve_controllable_delay_leackage_check_Kvs_cType1.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-50},{-8,-50}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[8].port, valve_controllable_delay_leackage_check_Kvs_cType2.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-70},{-8,-70}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[9].port, valve_controllable_delay_leackage_check_Kvs_cType3.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-90},{-8,-90}}, + color={0,140,72}, + thickness=1)); + + connect(fs_b[1].port, valve_controllable_Kvs_cType1.port_b) annotation (Line( + points={{60,0},{20,0},{20,90},{8,90}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[2].port, valve_controllable_Kvs_cType2.port_b) annotation (Line( + points={{60,0},{20,0},{20,70},{8,70}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[3].port, valve_controllable_Kvs_cType3.port_b) annotation (Line( + points={{60,0},{20,0},{20,50},{8,50}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[4].port, valve_controllable_delay_Kvs_cType1.port_b) annotation ( + Line( + points={{60,0},{20,0},{20,20},{8,20}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[5].port, valve_controllable_delay_Kvs_cType2.port_b) annotation ( + Line( + points={{60,0},{8,0}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[6].port, valve_controllable_delay_Kvs_cType3.port_b) annotation ( + Line( + points={{60,0},{20,0},{20,-20},{8,-20}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[7].port, valve_controllable_delay_leackage_check_Kvs_cType1.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-50},{8,-50}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[8].port, valve_controllable_delay_leackage_check_Kvs_cType2.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-70},{8,-70}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[9].port, valve_controllable_delay_leackage_check_Kvs_cType3.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-90},{8,-90}}, + color={0,140,72}, + thickness=1)); + + for ind in 1:9 loop + connect(input_T.y, fs_b[ind].T_input) annotation (Line(points={{79,-20},{70, + -20},{70,-2},{61.2,-2}}, + color={0,0,127})); + connect(input_p.y, fs_b[ind].p_input) + annotation (Line(points={{79,20},{70,20},{70,5},{61.2,5}}, + color={0,0,127})); + end for; + + connect(input_lRel.y, valve_controllable_Kvs_cType1.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,97},{0,97}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_Kvs_cType2.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,77},{0,77}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_Kvs_cType3.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,57},{0,57}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType1.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,27},{0,27}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType2.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,7},{0,7}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType3.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-13},{0,-13}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType1.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-43},{0,-43}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType2.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-63},{0,-63}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType3.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-83},{0,-83}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the compressible valve. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_CompressibleValve; diff --git a/SorpLib/Components/Valves/VLEValves/Tester/Test_CondensateRefluxValve.mo b/SorpLib/Components/Valves/VLEValves/Tester/Test_CondensateRefluxValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..8e268abbd3e8afbbec695cee59c8e3e8ccbb495f --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/Tester/Test_CondensateRefluxValve.mo @@ -0,0 +1,215 @@ +within SorpLib.Components.Valves.VLEValves.Tester; +model Test_CondensateRefluxValve + "Tester for the condensate reflux valve" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource[9] fs_a( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each p_fixed(displayUnit="kPa") = 1000*(4.246*1.1), + each T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource[9] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each p_fixed(displayUnit="kPa") = 1000*(1.7051*1.1), + each T_fixed=288.15) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of valves + // + SorpLib.Components.Valves.VLEValves.CondensateRefluxValve refluxValve_cType1( + controlType=1) "Condensate reflux valve: No check valve, control type 1" + annotation (Placement(transformation(extent={{-10,80},{10,100}}))); + SorpLib.Components.Valves.VLEValves.CondensateRefluxValve refluxValve_cType2( + controlType=2) "Condensate reflux valve: No check valve, control type 2" + annotation (Placement(transformation(extent={{-10,60},{10,80}}))); + SorpLib.Components.Valves.VLEValves.CondensateRefluxValve refluxValve_cType3( + controlType=3) "Condensate reflux valve: No check valve, control type 3" + annotation (Placement(transformation(extent={{-10,40},{10,60}}))); + + SorpLib.Components.Valves.VLEValves.CondensateRefluxValve refluxValve_cType1_checkValve( + controlType=1, + checkValve=true) "Condensate reflux valve: Ceck valve, control type 1" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + SorpLib.Components.Valves.VLEValves.CondensateRefluxValve refluxValve_cType2_checkValve( + controlType=2, + checkValve=true) "Condensate reflux valve: Check valve, control type 2" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + SorpLib.Components.Valves.VLEValves.CondensateRefluxValve refluxValve_cType3_checkValve( + controlType=3, + checkValve=true) "Condensate reflux valve: Check valve, control type 3" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + + SorpLib.Components.Valves.VLEValves.CondensateRefluxValve refluxValve_cType1_strictCheckValve( + controlType=1, + checkValve=true, + strictCheckValve=true) + "Condensate reflux valve: Ceck valve, control type 1" + annotation (Placement(transformation(extent={{-10,-60},{10,-40}}))); + SorpLib.Components.Valves.VLEValves.CondensateRefluxValve refluxValve_cType2_strictCheckValve( + controlType=2, + checkValve=true, + strictCheckValve=true) + "Condensate reflux valve: Check valve, control type 2" + annotation (Placement(transformation(extent={{-10,-80},{10,-60}}))); + SorpLib.Components.Valves.VLEValves.CondensateRefluxValve refluxValve_cType3_strictCheckValve( + controlType=3, + checkValve=true, + strictCheckValve=true) + "Condensate reflux valve: Check valve, control type 3" + annotation (Placement(transformation(extent={{-10,-100},{10,-80}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Trapezoid input_lRel( + amplitude=-0.6, + rising=200, + width=50, + falling=200, + period=500, + offset=0.75) + "Input signal for relative filling leveö" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + +equation + // + // Connections + // + connect(fs_a[1].port, refluxValve_cType1.port_a) annotation (Line( + points={{-60,0},{-32,0},{-32,90},{-8,90}}, + color={0,140,72}, + thickness=1)); + connect(refluxValve_cType3.port_a, fs_a[2].port) annotation (Line( + points={{-8,50},{-32,50},{-32,0},{-60,0}}, + color={0,140,72}, + thickness=1)); + connect(refluxValve_cType2.port_a, fs_a[3].port) annotation (Line( + points={{-8,70},{-32,70},{-32,0},{-60,0}}, + color={0,140,72}, + thickness=1)); + connect(refluxValve_cType1_checkValve.port_a, fs_a[4].port) annotation (Line( + points={{-8,20},{-32,20},{-32,0},{-60,0}}, + color={0,140,72}, + thickness=1)); + connect(refluxValve_cType2_checkValve.port_a, fs_a[5].port) annotation (Line( + points={{-8,0},{-60,0}}, + color={0,140,72}, + thickness=1)); + connect(refluxValve_cType3_checkValve.port_a, fs_a[6].port) annotation (Line( + points={{-8,-20},{-32,-20},{-32,0},{-60,0}}, + color={0,140,72}, + thickness=1)); + connect(refluxValve_cType1_strictCheckValve.port_a, fs_a[7].port) annotation ( + Line( + points={{-8,-50},{-32,-50},{-32,0},{-60,0}}, + color={0,140,72}, + thickness=1)); + connect(refluxValve_cType2_strictCheckValve.port_a, fs_a[8].port) annotation ( + Line( + points={{-8,-70},{-32,-70},{-32,0},{-60,0}}, + color={0,140,72}, + thickness=1)); + connect(refluxValve_cType3_strictCheckValve.port_a, fs_a[9].port) annotation ( + Line( + points={{-8,-90},{-32,-90},{-32,0},{-60,0}}, + color={0,140,72}, + thickness=1)); + + connect(fs_b[1].port, refluxValve_cType1.port_b) annotation (Line( + points={{60,0},{30,0},{30,90},{8,90}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[2].port, refluxValve_cType2.port_b) annotation (Line( + points={{60,0},{30,0},{30,70},{8,70}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[3].port, refluxValve_cType3.port_b) annotation (Line( + points={{60,0},{30,0},{30,50},{8,50}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[4].port, refluxValve_cType1_checkValve.port_b) annotation (Line( + points={{60,0},{30,0},{30,20},{8,20}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[5].port, refluxValve_cType2_checkValve.port_b) annotation (Line( + points={{60,0},{8,0}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[6].port, refluxValve_cType3_checkValve.port_b) annotation (Line( + points={{60,0},{30,0},{30,-20},{8,-20}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[7].port, refluxValve_cType1_strictCheckValve.port_b) annotation ( + Line( + points={{60,0},{30,0},{30,-50},{8,-50}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[8].port, refluxValve_cType2_strictCheckValve.port_b) annotation ( + Line( + points={{60,0},{30,0},{30,-70},{8,-70}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[9].port, refluxValve_cType3_strictCheckValve.port_b) annotation ( + Line( + points={{60,0},{30,0},{30,-90},{8,-90}}, + color={0,140,72}, + thickness=1)); + + connect(input_lRel.y, refluxValve_cType1.processVariable) annotation (Line( + points={{-79,0},{-70,0},{-70,94.2},{-2.6,94.2}}, color={0,0,127})); + connect(input_lRel.y, refluxValve_cType2.processVariable) annotation (Line( + points={{-79,0},{-70,0},{-70,74.2},{-2.6,74.2}}, color={0,0,127})); + connect(input_lRel.y, refluxValve_cType3.processVariable) annotation (Line( + points={{-79,0},{-70,0},{-70,54.2},{-2.6,54.2}}, color={0,0,127})); + connect(input_lRel.y, refluxValve_cType1_checkValve.processVariable) + annotation (Line(points={{-79,0},{-70,0},{-70,24.2},{-2.6,24.2}}, color={0,0, + 127})); + connect(input_lRel.y, refluxValve_cType2_checkValve.processVariable) + annotation (Line(points={{-79,0},{-70,0},{-70,16},{-40,16},{-40,4.2},{-2.6,4.2}}, + color={0,0,127})); + connect(input_lRel.y, refluxValve_cType3_checkValve.processVariable) + annotation (Line(points={{-79,0},{-70,0},{-70,-15.8},{-2.6,-15.8}}, color={0, + 0,127})); + connect(input_lRel.y, refluxValve_cType1_strictCheckValve.processVariable) + annotation (Line(points={{-79,0},{-70,0},{-70,-45.8},{-2.6,-45.8}}, color={0, + 0,127})); + connect(input_lRel.y, refluxValve_cType2_strictCheckValve.processVariable) + annotation (Line(points={{-79,0},{-70,0},{-70,-65.8},{-2.6,-65.8}}, color={0, + 0,127})); + connect(input_lRel.y, refluxValve_cType3_strictCheckValve.processVariable) + annotation (Line(points={{-79,0},{-70,0},{-70,-85.8},{-2.6,-85.8}}, color={0, + 0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the condensate reflux valve. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + Minor revisions (documentation, test new functionalities). + </li> + <li> + January 20, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_CondensateRefluxValve; diff --git a/SorpLib/Components/Valves/VLEValves/Tester/Test_IncompressibleThreeWayValve.mo b/SorpLib/Components/Valves/VLEValves/Tester/Test_IncompressibleThreeWayValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..dc6553b30897123a8996126780db46db3742aa9a --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/Tester/Test_IncompressibleThreeWayValve.mo @@ -0,0 +1,178 @@ +within SorpLib.Components.Valves.VLEValves.Tester; +model Test_IncompressibleThreeWayValve + "Tester for the three-way valve for incompressible fluids" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource[3] fs_a( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each p_fixed(displayUnit="bar") = 1000000, + each T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource[3] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source b" + annotation (Placement(transformation(extent={{70,40},{50,60}}))); + + SorpLib.Basics.Sources.Fluids.VLESource[3] fs_c( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source c" + annotation (Placement(transformation(extent={{70,-40},{50,-60}}))); + + // + // Definition of valves + // + SorpLib.Components.Valves.VLEValves.IncompressibleThreeWayValve threeWayValve( + controllablePosition=true) + "Three-way valve: Controllable, no time constant, no leackage" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,40}))); + + SorpLib.Components.Valves.VLEValves.IncompressibleThreeWayValve threeWayValve_delay( + controllablePosition=true, + useTimeConstant=true, + tau=10, + position_initial=0) + "Three-way valve: Controllable, time constant, no leackage" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,0}))); + + SorpLib.Components.Valves.VLEValves.IncompressibleThreeWayValve threeWayValve_delay_leackage( + controllablePosition=true, + useTimeConstant=true, + leackage=true, + position_initial=0) + "Three-way valve: Controllable, time constant, leackage" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,-40}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Trapezoid input_lRel( + amplitude=1, + rising=150, + width=50, + falling=0, + period=250, + offset=0) + "Input signal for relative filling level" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, + rotation=270, + origin={10,90}))); + + Modelica.Blocks.Sources.Sine input_p_b( + amplitude=-1e5, + f=1/100, + offset=10e5) "Input signal for pressure at port b" + annotation (Placement(transformation(extent={{100,40},{80,60}}))); + Modelica.Blocks.Sources.Sine input_T( + amplitude=25, + f=1/100, + offset=273.15 + 50) + "Input signal for temperature" + annotation (Placement(transformation(extent={{100,-10},{80,10}}))); + Modelica.Blocks.Sources.Sine input_p_c( + amplitude=-1e5, + f=1/100, + offset=10e5) "Input signal for pressure at port c" + annotation (Placement(transformation(extent={{100,-60},{80,-40}}))); + +equation + // + // Connections + // + connect(fs_a[1].port, threeWayValve.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,40},{-7.8,40}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[2].port, threeWayValve_delay.port_a) annotation (Line( + points={{-60,0},{-7.8,0}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[3].port, threeWayValve_delay_leackage.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,-40},{-7.8,-40}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve.port_b, fs_b[1].port) annotation (Line( + points={{0,48},{0,50},{60,50}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve_delay.port_b, fs_b[2].port) annotation (Line( + points={{0,8},{0,10},{20,10},{20,50},{60,50}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve_delay_leackage.port_b, fs_b[3].port) annotation (Line( + points={{0,-32},{0,-30},{20,-30},{20,50},{60,50}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve.port_c, fs_c[1].port) annotation (Line( + points={{0,32},{0,30},{40,30},{40,-50},{60,-50}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve_delay.port_c, fs_c[2].port) annotation (Line( + points={{0,-8},{0,-10},{40,-10},{40,-50},{60,-50}}, + color={0,140,72}, + thickness=1)); + connect(threeWayValve_delay_leackage.port_c, fs_c[3].port) annotation (Line( + points={{0,-48},{0,-50},{60,-50}}, + color={0,140,72}, + thickness=1)); + + for ind in 1:3 loop + connect(input_T.y, fs_b[ind].T_input) annotation (Line(points={{79,0},{70,0}, + {70,48},{61.2,48}}, + color={0,0,127})); + connect(input_T.y, fs_c[ind].T_input) annotation (Line(points={{79,0},{70,0},{70, + -48},{61.2,-48}}, color={0,0,127})); + + connect(input_p_b.y, fs_b[ind].p_input) annotation (Line(points={{79,50},{70, + 50},{70,55},{61.2,55}}, color={0,0,127})); + connect(input_p_c.y, fs_c[ind].p_input) annotation (Line(points={{79,-50},{70,-50}, + {70,-55},{61.2,-55}}, color={0,0,127})); + end for; + + connect(input_lRel.y, threeWayValve.position) + annotation (Line(points={{10,79},{10,40},{7,40}}, color={0,0,127})); + connect(input_lRel.y, threeWayValve_delay.position) + annotation (Line(points={{10,79},{10,0},{7,0}}, color={0,0,127})); + connect(input_lRel.y, threeWayValve_delay_leackage.position) + annotation (Line(points={{10,79},{10,-40},{7,-40}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the incompressible three-way valve. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_IncompressibleThreeWayValve; diff --git a/SorpLib/Components/Valves/VLEValves/Tester/Test_IncompressibleValve.mo b/SorpLib/Components/Valves/VLEValves/Tester/Test_IncompressibleValve.mo new file mode 100644 index 0000000000000000000000000000000000000000..4bfd0ff46f15665e148cc2b019a77757b2ecc9b6 --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/Tester/Test_IncompressibleValve.mo @@ -0,0 +1,286 @@ +within SorpLib.Components.Valves.VLEValves.Tester; +model Test_IncompressibleValve + "Tester for the valve for incompressible fluids" + extends Modelica.Icons.Example; + + // + // Definition of boundary models + // + SorpLib.Basics.Sources.Fluids.VLESource[9] fs_a( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each p_fixed(displayUnit="bar") = 1000000, + each T_fixed=303.15) + "Fluid source a" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + + SorpLib.Basics.Sources.Fluids.VLESource[9] fs_b( + each boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + each boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + each use_pInput=true, + each use_TInput=true) + "Fluid source b" + annotation (Placement(transformation(extent={{70,-10},{50,10}}))); + + // + // Definition of valves + // + SorpLib.Components.Valves.VLEValves.IncompressibleValve valve_controllable_Kvs_cType1( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=1) "Incompressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,80},{10,100}}))); + SorpLib.Components.Valves.VLEValves.IncompressibleValve valve_controllable_Kvs_cType2( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=2) "Incompressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,60},{10,80}}))); + SorpLib.Components.Valves.VLEValves.IncompressibleValve valve_controllable_Kvs_cType3( + controllableOpening=true, + useTimeConstant=false, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=3) "Incompressible valve: Controllable, no time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,40},{10,60}}))); + + SorpLib.Components.Valves.VLEValves.IncompressibleValve valve_controllable_delay_Kvs_cType1( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=1, + opening_initial=0) "Incompressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + SorpLib.Components.Valves.VLEValves.IncompressibleValve valve_controllable_delay_Kvs_cType2( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=2, + opening_initial=0) "Incompressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + SorpLib.Components.Valves.VLEValves.IncompressibleValve valve_controllable_delay_Kvs_cType3( + controllableOpening=true, + useTimeConstant=true, + tau=10, + leackage=false, + checkValve=false, + useKvsValue=true, + valveCharacteristic=3, + opening_initial=0) "Incompressible valve: Controllable, time constant, no leackage, no check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + + SorpLib.Components.Valves.VLEValves.IncompressibleValve valve_controllable_delay_leackage_check_Kvs_cType1( + controllableOpening=true, + useTimeConstant=true, + tau=1, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=1, + opening_initial=0) "Incompressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 1" + annotation (Placement(transformation(extent={{-10,-60},{10,-40}}))); + SorpLib.Components.Valves.VLEValves.IncompressibleValve valve_controllable_delay_leackage_check_Kvs_cType2( + controllableOpening=true, + useTimeConstant=true, + tau=1, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=2, + opening_initial=0) "Incompressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 2" + annotation (Placement(transformation(extent={{-10,-80},{10,-60}}))); + SorpLib.Components.Valves.VLEValves.IncompressibleValve valve_controllable_delay_leackage_check_Kvs_cType3( + controllableOpening=true, + useTimeConstant=true, + leackage=true, + checkValve=true, + useKvsValue=true, + valveCharacteristic=3, + opening_initial=0) "Incompressible valve: Controllable, time constant, leackage, check valve, + Kvs-approach, and characterisitc 3" + annotation (Placement(transformation(extent={{-10,-100},{10,-80}}))); + + // + // Definition of input signals + // +protected + Modelica.Blocks.Sources.Trapezoid input_lRel( + amplitude=1, + rising=150, + width=50, + falling=0, + period=250, + offset=0) + "Input signal for relative filling level" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + + Modelica.Blocks.Sources.Sine input_p( + amplitude=-1e5, + f=1/100, + offset=10e5) + "Input signal for pressure" + annotation (Placement(transformation(extent={{100,10},{80,30}}))); + Modelica.Blocks.Sources.Sine input_T( + amplitude=25, + f=1/100, + offset=273.15 + 50) + "Input signal for temperature" + annotation (Placement(transformation(extent={{100,-30},{80,-10}}))); + +equation + // + // Connections + // + connect(fs_a[1].port, valve_controllable_Kvs_cType1.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,90},{-8,90}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[2].port, valve_controllable_Kvs_cType2.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,70},{-8,70}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[3].port, valve_controllable_Kvs_cType3.port_a) annotation (Line( + points={{-60,0},{-20,0},{-20,50},{-8,50}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[4].port, valve_controllable_delay_Kvs_cType1.port_a) annotation ( + Line( + points={{-60,0},{-20,0},{-20,20},{-8,20}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[5].port, valve_controllable_delay_Kvs_cType2.port_a) annotation ( + Line( + points={{-60,0},{-8,0}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[6].port, valve_controllable_delay_Kvs_cType3.port_a) annotation ( + Line( + points={{-60,0},{-20,0},{-20,-20},{-8,-20}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[7].port, valve_controllable_delay_leackage_check_Kvs_cType1.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-50},{-8,-50}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[8].port, valve_controllable_delay_leackage_check_Kvs_cType2.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-70},{-8,-70}}, + color={0,140,72}, + thickness=1)); + connect(fs_a[9].port, valve_controllable_delay_leackage_check_Kvs_cType3.port_a) + annotation (Line( + points={{-60,0},{-20,0},{-20,-90},{-8,-90}}, + color={0,140,72}, + thickness=1)); + + connect(fs_b[1].port, valve_controllable_Kvs_cType1.port_b) annotation (Line( + points={{60,0},{20,0},{20,90},{8,90}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[2].port, valve_controllable_Kvs_cType2.port_b) annotation (Line( + points={{60,0},{20,0},{20,70},{8,70}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[3].port, valve_controllable_Kvs_cType3.port_b) annotation (Line( + points={{60,0},{20,0},{20,50},{8,50}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[4].port, valve_controllable_delay_Kvs_cType1.port_b) annotation ( + Line( + points={{60,0},{20,0},{20,20},{8,20}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[5].port, valve_controllable_delay_Kvs_cType2.port_b) annotation ( + Line( + points={{60,0},{8,0}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[6].port, valve_controllable_delay_Kvs_cType3.port_b) annotation ( + Line( + points={{60,0},{20,0},{20,-20},{8,-20}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[7].port, valve_controllable_delay_leackage_check_Kvs_cType1.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-50},{8,-50}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[8].port, valve_controllable_delay_leackage_check_Kvs_cType2.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-70},{8,-70}}, + color={0,140,72}, + thickness=1)); + connect(fs_b[9].port, valve_controllable_delay_leackage_check_Kvs_cType3.port_b) + annotation (Line( + points={{60,0},{20,0},{20,-90},{8,-90}}, + color={0,140,72}, + thickness=1)); + + for ind in 1:9 loop + connect(input_T.y, fs_b[ind].T_input) annotation (Line(points={{79,-20},{70, + -20},{70,-2},{61.2,-2}}, + color={0,0,127})); + connect(input_p.y, fs_b[ind].p_input) + annotation (Line(points={{79,20},{70,20},{70,5},{61.2,5}}, + color={0,0,127})); + end for; + + connect(input_lRel.y, valve_controllable_Kvs_cType1.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,97},{0,97}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_Kvs_cType2.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,77},{0,77}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_Kvs_cType3.opening) annotation (Line( + points={{-79,0},{-70,0},{-70,57},{0,57}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType1.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,27},{0,27}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType2.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,7},{0,7}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_Kvs_cType3.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-13},{0,-13}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType1.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-43},{0,-43}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType2.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-63},{0,-63}}, color={0,0,127})); + connect(input_lRel.y, valve_controllable_delay_leackage_check_Kvs_cType3.opening) + annotation (Line(points={{-79,0},{-70,0},{-70,-83},{0,-83}}, color={0,0,127})); + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the incompressible valve. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_IncompressibleValve; diff --git a/SorpLib/Components/Valves/VLEValves/Tester/package.mo b/SorpLib/Components/Valves/VLEValves/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f17a000992af8e59b29cd5a7294ce62086b463d3 --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/Tester/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Components.Valves.VLEValves; +package Tester "Models to test and varify models for VLE valves" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented VLE valves. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Valves/VLEValves/Tester/package.order b/SorpLib/Components/Valves/VLEValves/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bee4d72f03251d499c4ebffa84ee532e36fe164a --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/Tester/package.order @@ -0,0 +1,5 @@ +Test_CondensateRefluxValve +Test_IncompressibleValve +Test_IncompressibleThreeWayValve +Test_CompressibleValve +Test_CompressibleThreeWayValve diff --git a/SorpLib/Components/Valves/VLEValves/package.mo b/SorpLib/Components/Valves/VLEValves/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..825d59326e8b227af142066c1c64a05c31dae05c --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Valves; +package VLEValves "VLE valves" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains VLE valves based on the open-source Modelica Standard +Library (MSL). +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end VLEValves; diff --git a/SorpLib/Components/Valves/VLEValves/package.order b/SorpLib/Components/Valves/VLEValves/package.order new file mode 100644 index 0000000000000000000000000000000000000000..25c6f5e841cadc6d4baa49cec2e0f43f20f85b54 --- /dev/null +++ b/SorpLib/Components/Valves/VLEValves/package.order @@ -0,0 +1,6 @@ +CondensateRefluxValve +IncompressibleValve +IncompressibleThreeWayValve +CompressibleValve +CompressibleThreeWayValve +Tester diff --git a/SorpLib/Components/Valves/VLE_Valves/Partial/PartialValve.mo b/SorpLib/Components/Valves/VLE_Valves/Partial/PartialValve.mo deleted file mode 100644 index 3caa614f9eaa3be4432a40754a2f54cf2d46f29c..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Valves/VLE_Valves/Partial/PartialValve.mo +++ /dev/null @@ -1,69 +0,0 @@ -within SorpLib.Components.Valves.VLE_Valves.Partial; -partial model PartialValve - - /*********************** SIM ***********************************/ - - parameter TILMedia.VLEFluidTypes.BaseVLEFluid vleFluidType=sim.vleFluidType1 - "VLE fluid type" annotation (Dialog(tab="SIM", group="SIM"), choices( - choice=sim.vleFluidType1 "VLE fluid 1 as defined in SIM", - choice=sim.vleFluidType2 "VLE fluid 2 as defined in SIM", - choice=sim.vleFluidType3 "VLE fluid 3 as defined in SIM")); -protected - outer TIL.SystemInformationManager sim "System information manager"; - - /********************** Connecotrs *****************************/ - -public - TIL.Connectors.VLEFluidPort portA(final vleFluidType=vleFluidType) "portA" - annotation (Placement(transformation(extent={{-90,-10},{-70,10}}, rotation= - 0))); - TIL.Connectors.VLEFluidPort portB(final vleFluidType=vleFluidType) "portB" - annotation (Placement(transformation(extent={{70,-10},{90,10}}, rotation=0))); - -equation - portA.xi_outflow = inStream(portB.xi_outflow); - portB.xi_outflow = inStream(portA.xi_outflow); - - portA.h_outflow = inStream(portB.h_outflow); - portB.h_outflow = inStream(portA.h_outflow); - - portA.h_limit = -1e6; - // no limiter - portB.h_limit = -1e6; - - portB.m_flow + portA.m_flow = 0 "mass balance"; - - annotation (Icon(coordinateSystem(extent={{-100,-60},{100,60}}), graphics={ - Bitmap(extent={{-82,-48},{80,82}}, fileName= - "modelica://SorpLib/Resources/Images/MassTransfer.png")}), - Diagram(coordinateSystem(extent={{-100,-60},{100,60}}), graphics), - Documentation(info="<html> - <p> - The VLE valves are used to connect two VLE volumes and determine the mass flow between the volumes. - The valve is modeled isenthalpic with no volume. - The partial model includes the main equations, used for VLE valves models including: - <ul> - <li>2 vle ports</li> - <li>Mass balance</li> - <li>Energy balance</li> - </ul> - </p> - <h4>Main equations</h4> - <p> - The VLE valve is modelled as isenthalpic valves with no storage volume. - Thus, the mass balance reads: - <p align=\"center\"><i><code>ṁ</code></i><sub>in</sub> = <i><code>ṁ</code></i><sub>out</sub> </p> - The energy balance boils down to equal specific enthalpies: - <p align=\"center\"><i>h</i><sub>in</sub> = <i>h</i><sub>out</sub> </p> - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>December 11, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html> -")); -end PartialValve; diff --git a/SorpLib/Components/Valves/VLE_Valves/Partial/package.mo b/SorpLib/Components/Valves/VLE_Valves/Partial/package.mo deleted file mode 100644 index 810b43eb64d914d9c07f259c9a0640b322ba0c43..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Valves/VLE_Valves/Partial/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Components.Valves.VLE_Valves; -package Partial -extends SorpLib.Internals.ClassTypes.PartialPackage; - -end Partial; diff --git a/SorpLib/Components/Valves/VLE_Valves/Partial/package.order b/SorpLib/Components/Valves/VLE_Valves/Partial/package.order deleted file mode 100644 index 32ff56625d25a723b60bc191436650c53e1d7cd1..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Valves/VLE_Valves/Partial/package.order +++ /dev/null @@ -1 +0,0 @@ -PartialValve diff --git a/SorpLib/Components/Valves/VLE_Valves/Testers/TestValveConstantFillingLevel.mo b/SorpLib/Components/Valves/VLE_Valves/Testers/TestValveConstantFillingLevel.mo deleted file mode 100644 index ffd01ad84b63edf648f2b9ad2540aaf15babb32c..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Valves/VLE_Valves/Testers/TestValveConstantFillingLevel.mo +++ /dev/null @@ -1,140 +0,0 @@ -within SorpLib.Components.Valves.VLE_Valves.Testers; -model TestValveConstantFillingLevel - import SorpLib; - - inner TIL.SystemInformationManager sim(redeclare - TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType1) - annotation (Placement(transformation(extent={{80,80},{100,100}}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundaryEvp( - streamVariablesInputType="T", - boundaryType="m_flow", - use_pressureInput=false, - use_massFlowRateInput=true, - TFixed=333.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=270, - origin={10,-42}))); - SorpLib.Components.Valves.VLE_Valves.ValveConstantFillingLevel - valve_returnflow( - vleFluidType=sim.vleFluidType1, - kp=0.1, - ls=0.1, - l=vlePhaseSeparatorCond.l_relative) annotation (Placement(transformation( - extent={{-10,-6},{10,6}}, - rotation=90, - origin={-22,8}))); - TIL.VLEFluidComponents.Boundaries.Boundary vleBoundaryCond( - boundaryType="m_flow", - use_pressureInput=false, - use_massFlowRateInput=true, - streamVariablesInputType="h", - hFixed=2.5e6, - TFixed=333.15) annotation (Placement(transformation( - extent={{-4,-10},{4,10}}, - rotation=90, - origin={10,52}))); - Modelica.Blocks.Sources.Pulse pulseEvp( - period=1000, - amplitude=-0.001, - offset=0.001) annotation (Placement(transformation( - extent={{-3,-3},{3,3}}, - rotation=270, - origin={12,-30}))); - Modelica.Blocks.Sources.Pulse pulseEvp1( - period=1000, - amplitude=-0.001, - offset=0) annotation (Placement(transformation( - extent={{-3,-3},{3,3}}, - rotation=90, - origin={8,38}))); - SorpLib.Components.Cells.VLEPhaseSeparator.VLEPhaseSeparator vlePhaseSeparatorEvp( - vleFluidType=sim.vleFluidType1, - volume(displayUnit="l") = 0.005, - area=0.03, - includeDefaultSummary=true, - n=1, - k=1, - dInitial=300, - TInitial=298.15) annotation (Placement(transformation( - extent={{5,8},{-5,-8}}, - rotation=180, - origin={10,-58}))); - SorpLib.Components.Cells.VLEPhaseSeparator.VLEPhaseSeparator vlePhaseSeparatorCond( - vleFluidType=sim.vleFluidType1, - area=0.03, - includeDefaultSummary=true, - n=1, - k=1, - volume(displayUnit="l") = 0.002, - dInitial=200, - TInitial=298.15) annotation (Placement(transformation( - extent={{-5,8},{5,-8}}, - rotation=0, - origin={10,68}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary1( - use_heatFlowRateInput=false, - boundaryType="T", - TFixed=288.15) - annotation (Placement(transformation(extent={{52,-64},{44,-52}}))); - SorpLib.Components.HeatTransfer.HeatTransfer heatTransfer(redeclare model - HeatTransfer = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=1000)) - annotation (Placement(transformation(extent={{24,-62},{40,-54}}))); - SorpLib.Components.HeatTransfer.HeatTransfer heatTransfer1(redeclare model - HeatTransfer = - SorpLib.Components.HeatTransfer.HeatTransferPhenomena.ConstantAlphaA ( - constantAlphaA=1000)) - annotation (Placement(transformation(extent={{24,64},{40,72}}))); - TIL.OtherComponents.Thermal.HeatBoundary heatBoundary2( - use_heatFlowRateInput=false, - boundaryType="T", - TFixed=308.15) - annotation (Placement(transformation(extent={{52,62},{44,74}}))); -equation - connect(vleBoundaryEvp.m_flow_in, pulseEvp.y) - annotation (Line(points={{12,-38},{12,-33.3}}, color={0,0,127})); - connect(vleBoundaryCond.m_flow_in, pulseEvp1.y) - annotation (Line(points={{8,48},{8,41.3}}, color={0,0,127})); - connect(vleBoundaryEvp.port, vlePhaseSeparatorEvp.vleVapourPort[1]) - annotation (Line( - points={{10,-42},{10,-50}}, - color={153,204,0}, - thickness=0.5)); - connect(vlePhaseSeparatorEvp.vleLiquidPort[1], valve_returnflow.portA) - annotation (Line( - points={{10,-66},{10,-66},{10,-78},{-22,-78},{-22,0}}, - color={153,204,0}, - thickness=0.5)); - connect(vlePhaseSeparatorCond.vleVapourPort[1], vleBoundaryCond.port) - annotation (Line( - points={{10,60},{10,60},{10,52}}, - color={153,204,0}, - thickness=0.5)); - connect(vlePhaseSeparatorCond.vleLiquidPort[1], valve_returnflow.portB) - annotation (Line( - points={{10,76},{10,86},{-22,86},{-22,16}}, - color={153,204,0}, - thickness=0.5)); - connect(vlePhaseSeparatorEvp.heatPort, heatTransfer.heatPortA) annotation ( - Line( - points={{15,-58},{19.5,-58},{24,-58}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransfer.heatPortB[1], heatBoundary1.heatPort) annotation (Line( - points={{40,-58},{44,-58},{48,-58}}, - color={204,0,0}, - thickness=0.5)); - connect(vlePhaseSeparatorCond.heatPort, heatTransfer1.heatPortA) annotation ( - Line( - points={{15,68},{18,68},{24,68}}, - color={204,0,0}, - thickness=0.5)); - connect(heatTransfer1.heatPortB[1], heatBoundary2.heatPort) annotation (Line( - points={{40,68},{48,68}}, - color={204,0,0}, - thickness=0.5)); - annotation ( - experiment(StopTime=5000), - __Dymola_experimentSetupOutput); -end TestValveConstantFillingLevel; diff --git a/SorpLib/Components/Valves/VLE_Valves/Testers/package.mo b/SorpLib/Components/Valves/VLE_Valves/Testers/package.mo deleted file mode 100644 index 03d89ee86ec75b48bc95ed0a4fef3adf5407f094..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Valves/VLE_Valves/Testers/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Components.Valves.VLE_Valves; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - -end Testers; diff --git a/SorpLib/Components/Valves/VLE_Valves/Testers/package.order b/SorpLib/Components/Valves/VLE_Valves/Testers/package.order deleted file mode 100644 index 97ff343bacbd22eebc600145ee382c38cc996da5..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Valves/VLE_Valves/Testers/package.order +++ /dev/null @@ -1 +0,0 @@ -TestValveConstantFillingLevel diff --git a/SorpLib/Components/Valves/VLE_Valves/ValveConstantFillingLevel.mo b/SorpLib/Components/Valves/VLE_Valves/ValveConstantFillingLevel.mo deleted file mode 100644 index f22abe16cb3708d82cd96cfd1d22410f44bbd3d2..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Valves/VLE_Valves/ValveConstantFillingLevel.mo +++ /dev/null @@ -1,39 +0,0 @@ -within SorpLib.Components.Valves.VLE_Valves; -model ValveConstantFillingLevel - "This valve contains a constant filling level in one component" - extends Partial.PartialValve; - - parameter Real kp(final unit="kg/s") = 0.1 "Linear Valve coefficient"; - - parameter Real ls=0.25 "Desired relative water level"; - - input Real l "relative water level"; - -equation - portA.m_flow = (ls - l)*kp; - - annotation (Documentation(info="<html> - <p> - The VLE valve with constant filling level model extends the <a href=\"modelica://SorpLib.Components.Valves.VLE_Valves.Partial.PartialValve\">SorpLib.Components.Valves.VLE_Valves.Partial.PartialValve</a>.<br> - The VLE valve with constant filling level model determines the mass flow, so that the filling level in one VLE volume model is constant.<br> - </p> - <h4>Main equations</h4> - <p> - The mass flow <code>ṁ</code> is proportional to the difference between current filling level <i>l</i> and set point filling level <i>l</i><sub>set</sub>: - <p align=\"center\"><i><code>ṁ</code></i><sub>in</sub> = <i>k</i> ( <i>l</i> - <i>l</i><sub>set</sub> ).</p> - with a linear mass transfer coefficient <i>k</i>. - </p> - <h4>Typical use and important parameters</h4> - <p> - The VLE valve with constant filling level is mainly used to connect the evaporator and the condenser in an adsorption chiller model. - </p> - <h4>Author Information</h4> - <p> - <ul> - <li>November 30, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> - </p> -</html>")); -end ValveConstantFillingLevel; diff --git a/SorpLib/Components/Valves/VLE_Valves/package.mo b/SorpLib/Components/Valves/VLE_Valves/package.mo deleted file mode 100644 index 9225c830f97ab9ec9cdd98210e6af8e86bd9efa7..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Valves/VLE_Valves/package.mo +++ /dev/null @@ -1,13 +0,0 @@ -within SorpLib.Components.Valves; -package VLE_Valves -extends SorpLib.Internals.ClassTypes.ComponentPackage; - - - - - - - - - -end VLE_Valves; diff --git a/SorpLib/Components/Valves/VLE_Valves/package.order b/SorpLib/Components/Valves/VLE_Valves/package.order deleted file mode 100644 index dcb4766c8d21f4ce2282e53a98239aa3ccd71d1e..0000000000000000000000000000000000000000 --- a/SorpLib/Components/Valves/VLE_Valves/package.order +++ /dev/null @@ -1,3 +0,0 @@ -ValveConstantFillingLevel -Partial -Testers diff --git a/SorpLib/Components/Valves/ValveCharacteristics/Tester/Test_AllValveCharacteristics.mo b/SorpLib/Components/Valves/ValveCharacteristics/Tester/Test_AllValveCharacteristics.mo new file mode 100644 index 0000000000000000000000000000000000000000..d7fba0207427b27875c8d37cbeec4d04be4e5e22 --- /dev/null +++ b/SorpLib/Components/Valves/ValveCharacteristics/Tester/Test_AllValveCharacteristics.mo @@ -0,0 +1,70 @@ +within SorpLib.Components.Valves.ValveCharacteristics.Tester; +model Test_AllValveCharacteristics + "Tester for all valve characteristics" + extends Modelica.Icons.Example; + + // + // Definition of paramters + // + parameter Real fc_min = 0.5 + "Minimal flow coefficient if valve is almost closed (just for equal percentage + valve characteristic)" + annotation (Dialog(tab="General", group="Test Setup")); + parameter Real fc_max = 1.56 + "Maximal flow coefficient" + annotation (Dialog(tab="General", group="Test Setup")); + parameter Real opening_min = 1e-2 + "Minimal valve opening (i.e., position) at which the minimal flow coefficient + is reached (just for equal percentage valve characteristic)" + annotation (Dialog(tab="General", group="Test Setup")); + + // + // Definition of variables + // + Real opening(start=0, fixed=true) + "Actual opening"; + + Real fc_linear= + SorpLib.Components.Valves.ValveCharacteristics.linearCharacteristic( + opening=opening, + fc_max=fc_max) + "Linear valve characteristic"; + Real fc_quadratic= + SorpLib.Components.Valves.ValveCharacteristics.quadraticCharacteristic( + opening=opening, + fc_max=fc_max) + "Quadratic valve characteristic"; + Real fc_equalPercentage= + SorpLib.Components.Valves.ValveCharacteristics.equalPercentageCharacteristic( + opening=opening, + fc_max=fc_max, + fc_min=fc_min, + opening_min=opening_min) + "Equal percentage valve characteristic"; + +equation + // + // Calculate test setup + // + der(opening) = 1/2500 + "Actual opening"; + + // + // Annotations + // + annotation (experiment(StopTime=2500), Documentation(info="<html> +<p> +This model checks the valve characteristics. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 2500 s). +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_AllValveCharacteristics; diff --git a/SorpLib/Components/Valves/ValveCharacteristics/Tester/package.mo b/SorpLib/Components/Valves/ValveCharacteristics/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2e74bfb019e4dbd06fd1ccf105cdc4a018bec7f1 --- /dev/null +++ b/SorpLib/Components/Valves/ValveCharacteristics/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Components.Valves.ValveCharacteristics; +package Tester "Models to test and varify valve characteristic functions" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented valve +characteristics. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Components/Valves/ValveCharacteristics/Tester/package.order b/SorpLib/Components/Valves/ValveCharacteristics/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..29fbe4c8d7dbb1df71b2767af1f52203429be589 --- /dev/null +++ b/SorpLib/Components/Valves/ValveCharacteristics/Tester/package.order @@ -0,0 +1 @@ +Test_AllValveCharacteristics diff --git a/SorpLib/Components/Valves/ValveCharacteristics/equalPercentageCharacteristic.mo b/SorpLib/Components/Valves/ValveCharacteristics/equalPercentageCharacteristic.mo new file mode 100644 index 0000000000000000000000000000000000000000..b058635456d92451392ab65d88a62fae4ca03708 --- /dev/null +++ b/SorpLib/Components/Valves/ValveCharacteristics/equalPercentageCharacteristic.mo @@ -0,0 +1,65 @@ +within SorpLib.Components.Valves.ValveCharacteristics; +function equalPercentageCharacteristic + "Equal percentage valve characteristic" + extends BaseClasses.PartialValveCharacteristic; + + // + // Definition of inputs + // + input Real fc_min = 0.5 + "Minimal flow coefficient if valve is almost closed" + annotation (Dialog(tab="General", group="Inputs")); + input Real opening_min = 1e-2 + "Minimal opening used for linear regularization" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Real weightingFactor= + SorpLib.Numerics.smoothTransition( + x=opening, + transitionPoint=opening_min, + transitionLength=2*opening_min, + noDiff=3) + "Weighting factor used for linear regularization"; + +algorithm + fc := weightingFactor * (opening / opening_min) * + exp(fc_max / fc_min)^(opening_min - 1) * fc_max + + (1-weightingFactor) * exp(fc_max / fc_min)^(opening - 1) * fc_max + "Actual flow coefficient quadratically depends on the maximal flow coefficient"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The equal percentage valve characteristic calculates the flow coefficient such +that the relative change of the flow coefficient is linearly proportional to +the change of the opening: +</p> +<pre> + fc = <strong>exp</strong>(fc_max / fc_min)<sup>(opening - 1)</sup> * fc_max; +</pre> +<p> +If the opening is below a minimal opening <i>opening_min</i>, the flow coefficient +is calculated linearly proportional to the flow coefficient of the minimal opening: +</p> +<pre> + fc = (opening / opening_min) * <strong>exp</strong>(fc_max / fc_min)<sup>(opening_min - 1)</sup> * fc_max; +</pre> +<p> +This function is based on the function +<a href=\"Modelica://Modelica.Fluid.Valves.BaseClasses.ValveCharacteristics.equalPercentage\">Modelica.Fluid.Valves.BaseClasses.ValveCharacteristics.equalPercentage</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end equalPercentageCharacteristic; diff --git a/SorpLib/Components/Valves/ValveCharacteristics/linearCharacteristic.mo b/SorpLib/Components/Valves/ValveCharacteristics/linearCharacteristic.mo new file mode 100644 index 0000000000000000000000000000000000000000..dc71dfd2e3de0837efdd703d0f8f62e8f8638064 --- /dev/null +++ b/SorpLib/Components/Valves/ValveCharacteristics/linearCharacteristic.mo @@ -0,0 +1,31 @@ +within SorpLib.Components.Valves.ValveCharacteristics; +function linearCharacteristic "Linear valve characteristic" + extends BaseClasses.PartialValveCharacteristic; + +algorithm + fc := opening * fc_max + "Actual flow coefficient linearly depends on the maximal flow coefficient"; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The linear valve characteristic calculates the flow coefficient linearly +proportional to the maximum flow coefficient <i>fc_max</i>: +</p> +<pre> + fc = opening * fc_max; +</pre> +<p> +This function is based on the function +<a href=\"Modelica://Modelica.Fluid.Valves.BaseClasses.ValveCharacteristics.linear\">Modelica.Fluid.Valves.BaseClasses.ValveCharacteristics.linear</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end linearCharacteristic; diff --git a/SorpLib/Components/Valves/ValveCharacteristics/package.mo b/SorpLib/Components/Valves/ValveCharacteristics/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f5b9c2dd94c887a39ce244ed2736ec8d979277d5 --- /dev/null +++ b/SorpLib/Components/Valves/ValveCharacteristics/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Components.Valves; +package ValveCharacteristics "Package containing functions describing valve characteristics" + extends Modelica.Icons.FunctionsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains different functions describing valve characteristics. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ValveCharacteristics; diff --git a/SorpLib/Components/Valves/ValveCharacteristics/package.order b/SorpLib/Components/Valves/ValveCharacteristics/package.order new file mode 100644 index 0000000000000000000000000000000000000000..11e6a7edb76466ea902999d00120d2f1ca1ffc7a --- /dev/null +++ b/SorpLib/Components/Valves/ValveCharacteristics/package.order @@ -0,0 +1,4 @@ +linearCharacteristic +quadraticCharacteristic +equalPercentageCharacteristic +Tester diff --git a/SorpLib/Components/Valves/ValveCharacteristics/quadraticCharacteristic.mo b/SorpLib/Components/Valves/ValveCharacteristics/quadraticCharacteristic.mo new file mode 100644 index 0000000000000000000000000000000000000000..d76cf7beb0144c4e71761d7035fb1fa0437aa643 --- /dev/null +++ b/SorpLib/Components/Valves/ValveCharacteristics/quadraticCharacteristic.mo @@ -0,0 +1,31 @@ +within SorpLib.Components.Valves.ValveCharacteristics; +function quadraticCharacteristic "Quadratic valve characteristic" + extends BaseClasses.PartialValveCharacteristic; + +algorithm + fc := opening^2 * fc_max + "Actual flow coefficient quadratically depends on the maximal flow coefficient"; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +The linear valve characteristic calculates the flow coefficient quadratically +proportional to the maximum flow coefficient <i>fc_max</i>: +</p> +<pre> + fc = opening<sup>2</sup> * fc_max; +</pre> +<p> +This function is based on the function +<a href=\"Modelica://Modelica.Fluid.Valves.BaseClasses.ValveCharacteristics.quadratic\">Modelica.Fluid.Valves.BaseClasses.ValveCharacteristics.quadratic</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation + </li> +</ul> +</html>")); +end quadraticCharacteristic; diff --git a/SorpLib/Components/Valves/package.mo b/SorpLib/Components/Valves/package.mo index 50df2885e2035cb563fab8889dc9f22c57380f1e..286d1ba574c93e2a738cc629104ee07e49b872ac 100644 --- a/SorpLib/Components/Valves/package.mo +++ b/SorpLib/Components/Valves/package.mo @@ -1,9 +1,21 @@ within SorpLib.Components; -package Valves "Valve models" -extends SorpLib.Internals.ClassTypes.ComponentPackage; +package Valves "Valves to regulate and control fluid flows" + extends SorpLib.Icons.ValvesPackage; - - - -annotation (classOrder={"*","Testers"}); + annotation (Documentation(info="<html> +<p> +This package includes various valves for (ideal) liquids, ideal gases, ideal gas +mixtures, ideal gas-vapor mixtures, and real substances (i.e., with a two-phase +region). The valve types include simple orfice valves for incompressible or +compressible fluids, three-way valves for incompressible or compressible fluids, +and P-like control valves. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); end Valves; diff --git a/SorpLib/Components/Valves/package.order b/SorpLib/Components/Valves/package.order index 7f62b5ad3ec9e37be642493ab800e56ba78fd508..caa3a3273a960d1bdf82cad37462b149e18f90a5 100644 --- a/SorpLib/Components/Valves/package.order +++ b/SorpLib/Components/Valves/package.order @@ -1 +1,6 @@ -VLE_Valves +BaseClasses +LiquidValves +GasValves +VLEValves +ValveCharacteristics +Utilities diff --git a/SorpLib/Components/package.mo b/SorpLib/Components/package.mo index 280f0c24254f953c7ee2384f90b218b286198bf7..154ad1ad1c9f4fe0a4a45f5d31ee7151b9135b60 100644 --- a/SorpLib/Components/package.mo +++ b/SorpLib/Components/package.mo @@ -1,29 +1,18 @@ within SorpLib; -package Components "Component models for adsorption energy systems" - - - - - - - - - - - - - - - - - - - - -annotation (Icon(graphics={Ellipse( - extent={{-100,100},{102,-100}}, - fillColor={170,213,255}, - fillPattern=FillPattern.Solid, - pattern=LinePattern.None, - lineColor={0,0,0})})); +package Components "Library containing components used to build sorption modules and sorption systems" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains models of components typically used within sorption +systems. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); end Components; diff --git a/SorpLib/Components/package.order b/SorpLib/Components/package.order index bfe1f7161677e3643b0c2a664083211e2b1900c5..57da18379662cda326268a7d2a2d0d88decfa2d6 100644 --- a/SorpLib/Components/package.order +++ b/SorpLib/Components/package.order @@ -1,8 +1,10 @@ -Cells +AdsorberColumns +Fans +Fittings +HeatExchanger HeatTransfer MassTransfer -ClosedAdsorber -EvpCond -OpenAdsorber -HeatExchanger +Pumps +Sensors +Tubes Valves diff --git a/SorpLib/Examples/TwoBedAdsorptionChiller.mo b/SorpLib/Examples/TwoBedAdsorptionChiller.mo new file mode 100644 index 0000000000000000000000000000000000000000..52b130f6a7bab9c65cc1e3d3744fbbb1e5e4c157 --- /dev/null +++ b/SorpLib/Examples/TwoBedAdsorptionChiller.mo @@ -0,0 +1,218 @@ +within SorpLib.Examples; +model TwoBedAdsorptionChiller + "Example of a two-bed adsorption chiller" + extends Modelica.Icons.Example; + Components.HeatExchanger.CondensersEvaporators.SimpleCondenser condenser( + no_fluidVolumes=5, + nPortsVapor=2, + nPortsLiquid=1) "Condenser" + annotation (Placement(transformation(extent={{-10,50},{10,30}}))); + Components.HeatExchanger.CondensersEvaporators.SimpleEvaporator evaporator( + no_fluidVolumes=5, + nPortsVapor=2, + nPortsLiquid=1) "Evaporator model" + annotation (Placement(transformation(extent={{-10,-60},{10,-40}}))); + Components.HeatExchanger.Adsorbers.SimpleAdsorberDX adsorber1(no_fluidVolumes= + 5, no_sorbentVolumes=1, + redeclare model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT, + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Dubinin, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.BoilingCurve, + approachSpecificVolume=SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve, + limitLowerPressureAdsorptive=true)) "First adsorber bed" annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={30,0}))); + + Components.HeatExchanger.Adsorbers.SimpleAdsorberDX adsorber2( + no_fluidVolumes=5, + no_sorbentVolumes=1, + redeclare model WorkingPair = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT, + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Dubinin, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.BoilingCurve, + approachSpecificVolume=SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve, + limitLowerPressureAdsorptive=true)) "Second adsorber bed" annotation ( + Placement(transformation( + extent={{-10,10},{10,-10}}, + rotation=90, + origin={-30,0}))); + + Components.Valves.VLEValves.CondensateRefluxValve condensateRefluxValve + annotation (Placement(transformation( + extent={{-10,10},{10,-10}}, + rotation=270, + origin={-70,0}))); + Modelica.Blocks.Sources.RealExpression fillingLevelInput(y=condenser.phaseSeparatorVolume.l_liq_rel) + "Relativ filling level of the condenser" + annotation (Placement(transformation(extent={{-100,-10},{-80,10}}))); + Basics.Sources.Fluids.LiquidSource fs_evapA( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + V_flow_fixed=-10/60/1000, + T_fixed=288.15, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Evaporator inlet" + annotation (Placement(transformation(extent={{-30,-60},{-10,-40}}))); + + Basics.Sources.Fluids.LiquidSource fs_evapB( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + V_flow_fixed=-10/60/1000, + T_fixed=288.15, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Evaporator outlet" + annotation (Placement(transformation(extent={{10,-60},{30,-40}}))); + + Basics.Sources.Fluids.LiquidSource fs_condA( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + V_flow_fixed=-10/60/1000, + T_fixed=298.15, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Condenser inlet" + annotation (Placement(transformation(extent={{-30,30},{-10,50}}))); + + Basics.Sources.Fluids.LiquidSource fs_condB( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + V_flow_fixed=-10/60/1000, + T_fixed=288.15, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Condenser outlet" + annotation (Placement(transformation(extent={{10,30},{30,50}}))); + + Basics.Sources.Fluids.LiquidSource fs_adsA1( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + V_flow_fixed=-10/60/1000, + use_TInput=true, + T_fixed=298.15, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Adsorber inlet" + annotation (Placement(transformation(extent={{-50,-22},{-30,-2}}))); + + Basics.Sources.Fluids.LiquidSource fs_adsA2( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.VolumeFlowRate, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + V_flow_fixed=-10/60/1000, + use_TInput=true, + T_fixed=298.15, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Adsorber inlet" + annotation (Placement(transformation(extent={{50,-22},{30,-2}}))); + + Basics.Sources.Fluids.LiquidSource fs_adsB1( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=1000000, + V_flow_fixed=-10/60/1000, + use_TInput=false, + T_fixed=298.15, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Adsorber outlet" + annotation (Placement(transformation(extent={{-50,2},{-30,22}}))); + + Basics.Sources.Fluids.LiquidSource fs_adsB2( + boundaryTypePotentialFlow=SorpLib.Choices.BoundaryFluidPotentialFlow.Pressure, + boundaryTypeStreamEnthalpy=SorpLib.Choices.BoundaryFluidStreamEnthalpy.Temperature, + p_fixed=1000000, + V_flow_fixed=-10/60/1000, + use_TInput=false, + T_fixed=298.15, + redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater) + "Adsorber outlet" + annotation (Placement(transformation(extent={{30,2},{50,22}}))); + + Modelica.Blocks.Sources.Trapezoid inlet_TAds1( + amplitude=60, + rising=25, + width=490, + falling=25, + period=1000, + offset=273.15 + 25) "Adsorber inlet temperature" + annotation (Placement(transformation(extent={{-60,-20},{-48,-8}}))); + Modelica.Blocks.Sources.Trapezoid inlet_TAds2( + amplitude=-60, + rising=25, + width=490, + falling=25, + period=1000, + offset=273.15 + 85) "Adsorber inlet temperature" + annotation (Placement(transformation(extent={{60,-20},{48,-8}}))); +equation + connect(evaporator.vaporPort[1], adsorber1.evaporatorPort) annotation (Line( + points={{0,-46.3},{0,-20},{26,-20},{26,-10}}, + color={0,140,72}, + thickness=1)); + connect(adsorber2.evaporatorPort, evaporator.vaporPort[2]) annotation (Line( + points={{-26,-10},{-26,-20},{0,-20},{0,-45.3}}, + color={0,140,72}, + thickness=1)); + connect(condenser.vaporPort[1], adsorber2.condenserPort) annotation (Line( + points={{0,36.3},{0,20},{-26,20},{-26,10}}, + color={0,140,72}, + thickness=1)); + connect(condenser.vaporPort[2], adsorber1.condenserPort) annotation (Line( + points={{0,35.3},{0,20},{26,20},{26,10}}, + color={0,140,72}, + thickness=1)); + connect(condensateRefluxValve.port_b, evaporator.liquidPort[1]) annotation ( + Line( + points={{-70,-8},{-70,-60},{0,-60},{0,-53.8}}, + color={0,140,72}, + thickness=1)); + connect(condenser.liquidPort[1], condensateRefluxValve.port_a) annotation ( + Line( + points={{0,43.8},{0,50},{-70,50},{-70,8}}, + color={0,140,72}, + thickness=1)); + connect(fillingLevelInput.y, condensateRefluxValve.processVariable) + annotation (Line(points={{-79,0},{-78,0},{-78,2.6},{-74.2,2.6}}, color={0,0, + 127})); + connect(fs_evapA.port, evaporator.port_a) annotation (Line( + points={{-20,-50},{-10,-50}}, + color={28,108,200}, + thickness=1)); + connect(fs_evapB.port, evaporator.port_b) annotation (Line( + points={{20,-50},{10,-50}}, + color={28,108,200}, + thickness=1)); + connect(fs_condA.port, condenser.port_a) annotation (Line( + points={{-20,40},{-10,40}}, + color={28,108,200}, + thickness=1)); + connect(condenser.port_b, fs_condB.port) annotation (Line( + points={{10,40},{20,40}}, + color={28,108,200}, + thickness=1)); + connect(fs_adsA1.port, adsorber2.port_a) annotation (Line( + points={{-40,-12},{-30,-12},{-30,-10}}, + color={28,108,200}, + thickness=1)); + connect(fs_adsB1.port, adsorber2.port_b) annotation (Line( + points={{-40,12},{-30,12},{-30,10}}, + color={28,108,200}, + thickness=1)); + connect(fs_adsB2.port, adsorber1.port_b) annotation (Line( + points={{40,12},{30,12},{30,10}}, + color={28,108,200}, + thickness=1)); + connect(fs_adsA2.port, adsorber1.port_a) annotation (Line( + points={{40,-12},{30,-12},{30,-10}}, + color={28,108,200}, + thickness=1)); + connect(inlet_TAds1.y, fs_adsA1.T_input) + annotation (Line(points={{-47.4,-14},{-41.2,-14}}, color={0,0,127})); + connect(inlet_TAds2.y, fs_adsA2.T_input) + annotation (Line(points={{47.4,-14},{41.2,-14}}, color={0,0,127})); + annotation (experiment( + StopTime=5000, + __Dymola_NumberOfIntervals=5000, + __Dymola_Algorithm="Dassl")); +end TwoBedAdsorptionChiller; diff --git a/SorpLib/Examples/package.mo b/SorpLib/Examples/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5d75544d784cb1dd55a906b65cce31a1e4ec9b8e --- /dev/null +++ b/SorpLib/Examples/package.mo @@ -0,0 +1,17 @@ +within SorpLib; +package Examples "Library containing example models" +extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This packge contains example models of sorptions systems. +</p> +</html>")); +end Examples; diff --git a/SorpLib/Examples/package.order b/SorpLib/Examples/package.order new file mode 100644 index 0000000000000000000000000000000000000000..01c58f5a45eadbf1bb51dc27524d2404984974c6 --- /dev/null +++ b/SorpLib/Examples/package.order @@ -0,0 +1 @@ +TwoBedAdsorptionChiller diff --git a/SorpLib/Icons/AdsorberColumnsPackage/package.mo b/SorpLib/Icons/AdsorberColumnsPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..fdb36a31618a8d43381f00d14ef034249d94d4ce --- /dev/null +++ b/SorpLib/Icons/AdsorberColumnsPackage/package.mo @@ -0,0 +1,1305 @@ +within SorpLib.Icons; +partial package AdsorberColumnsPackage "Icon for packages containing adsorber column models" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing adsorber column models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(graphics={ + Ellipse( + extent={{-30,-60},{-36,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,-52},{-32,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{-40,62},{0,-62}}, + lineColor={0,0,0}, + lineThickness=1), + Ellipse( + extent={{-22,-60},{-28,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,-60},{-20,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-6,-60},{-12,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-10,-52},{-16,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,-52},{-24,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,-44},{-36,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,-36},{-32,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-22,-44},{-28,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,-44},{-20,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-6,-44},{-12,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-10,-36},{-16,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,-36},{-24,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,-28},{-36,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,-20},{-32,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-22,-28},{-28,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,-28},{-20,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-6,-28},{-12,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-10,-20},{-16,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,-20},{-24,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,-12},{-36,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,-4},{-32,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-22,-12},{-28,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,-12},{-20,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-6,-12},{-12,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-10,-4},{-16,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,-4},{-24,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,4},{-36,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,12},{-32,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-22,4},{-28,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,4},{-20,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-6,4},{-12,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-10,12},{-16,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,12},{-24,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,20},{-36,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,28},{-32,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-22,20},{-28,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,20},{-20,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-6,20},{-12,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-10,28},{-16,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,28},{-24,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,36},{-36,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,44},{-32,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-22,36},{-28,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,36},{-20,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-6,36},{-12,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-10,44},{-16,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-18,44},{-24,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-30,52},{-36,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-22,52},{-28,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,52},{-20,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-6,52},{-12,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,-60},{4,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{14,-52},{8,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{0,62},{40,-62}}, + lineColor={0,0,0}, + lineThickness=1), + Ellipse( + extent={{18,-60},{12,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{26,-60},{20,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,-60},{28,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,-52},{24,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,-52},{16,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,-44},{4,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{14,-36},{8,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{18,-44},{12,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{26,-44},{20,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,-44},{28,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,-36},{24,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,-36},{16,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,-28},{4,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{14,-20},{8,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{18,-28},{12,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{26,-28},{20,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,-28},{28,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,-20},{24,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,-20},{16,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,-12},{4,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{14,-4},{8,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{18,-12},{12,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{26,-12},{20,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,-12},{28,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,-4},{24,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,-4},{16,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,4},{4,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{14,12},{8,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{18,4},{12,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{26,4},{20,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,4},{28,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,12},{24,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,12},{16,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,20},{4,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{14,28},{8,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{18,20},{12,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{26,20},{20,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,20},{28,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,28},{24,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,28},{16,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,36},{4,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{14,44},{8,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{18,36},{12,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{26,36},{20,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,36},{28,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{30,44},{24,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,44},{16,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,52},{4,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{18,52},{12,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{26,52},{20,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,52},{28,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{50,-60},{44,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{54,-52},{48,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{40,62},{80,-62}}, + lineColor={0,0,0}, + lineThickness=1), + Ellipse( + extent={{58,-60},{52,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{66,-60},{60,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{74,-60},{68,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,-52},{64,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{62,-52},{56,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{50,-44},{44,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{54,-36},{48,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,-44},{52,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{66,-44},{60,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{74,-44},{68,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,-36},{64,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{62,-36},{56,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{50,-28},{44,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{54,-20},{48,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,-28},{52,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{66,-28},{60,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{74,-28},{68,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,-20},{64,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{62,-20},{56,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{50,-12},{44,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{54,-4},{48,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,-12},{52,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{66,-12},{60,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{74,-12},{68,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,-4},{64,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{62,-4},{56,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{50,4},{44,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{54,12},{48,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,4},{52,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{66,4},{60,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{74,4},{68,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,12},{64,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{62,12},{56,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{50,20},{44,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{54,28},{48,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,20},{52,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{66,20},{60,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{74,20},{68,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,28},{64,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{62,28},{56,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{50,36},{44,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{54,44},{48,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,36},{52,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{66,36},{60,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{74,36},{68,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,44},{64,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{62,44},{56,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{50,52},{44,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,52},{52,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{66,52},{60,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{74,52},{68,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,-60},{-76,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,-52},{-72,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{-80,62},{-40,-62}}, + lineColor={0,0,0}, + lineThickness=1), + Ellipse( + extent={{-62,-60},{-68,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-54,-60},{-60,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-46,-60},{-52,-54}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,-52},{-56,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,-52},{-64,-46}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,-44},{-76,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,-36},{-72,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,-44},{-68,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-54,-44},{-60,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-46,-44},{-52,-38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,-36},{-56,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,-36},{-64,-30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,-28},{-76,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,-20},{-72,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,-28},{-68,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-54,-28},{-60,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-46,-28},{-52,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,-20},{-56,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,-20},{-64,-14}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,-12},{-76,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,-4},{-72,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,-12},{-68,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-54,-12},{-60,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-46,-12},{-52,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,-4},{-56,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,-4},{-64,2}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,4},{-76,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,12},{-72,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,4},{-68,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-54,4},{-60,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-46,4},{-52,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,12},{-56,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,12},{-64,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,20},{-76,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,28},{-72,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,20},{-68,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-54,20},{-60,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-46,20},{-52,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,28},{-56,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,28},{-64,34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,36},{-76,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,44},{-72,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,36},{-68,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-54,36},{-60,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-46,36},{-52,42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,44},{-56,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,44},{-64,50}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,52},{-76,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,52},{-68,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-54,52},{-60,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-46,52},{-52,58}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid)})); +end AdsorberColumnsPackage; diff --git a/SorpLib/Icons/AdsorberColumnsPackage/package.order b/SorpLib/Icons/AdsorberColumnsPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/AdsorbersPackage/package.mo b/SorpLib/Icons/AdsorbersPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..8d07b880719a00d8b3e953f7b40b63bae3eaf8b3 --- /dev/null +++ b/SorpLib/Icons/AdsorbersPackage/package.mo @@ -0,0 +1,632 @@ +within SorpLib.Icons; +partial package AdsorbersPackage "Icon for packages containing adsorber models" + extends Modelica.Icons.Package; + + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle( + extent={{-92,60},{94,-60}}, + lineColor={0,0,0}, + lineThickness=1), + Line( + points={{94,40},{-86,40},{74,0},{-86,-40},{94,-40}}, + color={0,0,0}, + thickness=1), + Ellipse( + extent={{-80,42},{-86,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-20,42},{-26,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-32,42},{-38,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-44,42},{-50,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-56,42},{-62,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-68,42},{-74,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,42},{46,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{40,42},{34,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{28,42},{22,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{16,42},{10,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{4,42},{-2,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,42},{-14,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{64,42},{58,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{76,42},{70,48}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{76,-48},{70,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{64,-48},{58,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{52,-48},{46,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{40,-48},{34,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{28,-48},{22,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{16,-48},{10,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{4,-48},{-2,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-8,-48},{-14,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-20,-48},{-26,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-32,-48},{-38,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-44,-48},{-50,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-56,-48},{-62,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-68,-48},{-74,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-80,-48},{-86,-42}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{82,-38},{76,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,-38},{64,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,-38},{52,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,-38},{40,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,-38},{28,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,-38},{16,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,-38},{4,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-2,-38},{-8,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,-38},{-20,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,-38},{-32,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-38,-38},{-44,-32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,-40},{-56,-34}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,34},{-56,40}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-38,32},{-44,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-26,32},{-32,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,32},{-20,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-2,32},{-8,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{10,32},{4,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{22,32},{16,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,32},{28,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,32},{40,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{58,32},{52,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,32},{64,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{82,32},{76,38}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-72,30},{-78,36}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,26},{-64,32}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-42,22},{-48,28}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-24,18},{-30,24}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-10,14},{-16,20}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{6,10},{0,16}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{24,6},{18,12}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{38,2},{32,8}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{54,-2},{48,4}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,24},{-20,30}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{0,20},{-6,26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{16,16},{10,22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{32,12},{26,18}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,8},{40,14}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{62,4},{56,10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-72,-36},{-78,-30}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,-32},{-64,-26}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-42,-28},{-48,-22}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-24,-24},{-30,-18}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-10,-20},{-16,-14}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{6,-16},{0,-10}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{24,-12},{18,-6}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{38,-8},{32,-2}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{62,-10},{56,-4}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,-14},{40,-8}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{32,-18},{26,-12}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{18,-22},{12,-16}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{0,-26},{-6,-20}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,-30},{-20,-24}}, + lineColor={244,125,35}, + lineThickness=1, + fillColor={244,125,35}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-50,24},{-56,30}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-60,34},{-66,40}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-82,34},{-88,40}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-14,42},{-20,48}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-20,26},{-26,32}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-2,12},{-8,18}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{24,14},{18,20}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{46,0},{40,6}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{28,32},{22,38}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{70,42},{64,48}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{76,32},{70,38}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{14,-14},{8,-8}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-34,-26},{-40,-20}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,-40},{-64,-34}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-84,-42},{-90,-36}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-38,-48},{-44,-42}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{4,-38},{-2,-32}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{34,-48},{28,-42}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{64,-38},{58,-32}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{40,-16},{34,-10}}, + lineColor={0,140,72}, + lineThickness=1, + fillColor={0,140,72}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This icon indicates a package containing adsorber models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end AdsorbersPackage; diff --git a/SorpLib/Icons/AdsorbersPackage/package.order b/SorpLib/Icons/AdsorbersPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/CondensersEvaporatorsPackage/package.mo b/SorpLib/Icons/CondensersEvaporatorsPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5a943af5d925bed92a4ded26fa60f496b47cc651 --- /dev/null +++ b/SorpLib/Icons/CondensersEvaporatorsPackage/package.mo @@ -0,0 +1,126 @@ +within SorpLib.Icons; +partial package CondensersEvaporatorsPackage "Icon for packages containing condensers and evaporators" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing recooler models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-40}, + {100,40}}), graphics={ + Text( + extent={{-60,30},{-40,10}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.None, + fontSize=20, + textString="1"), + Text( + extent={{40,30},{60,10}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.None, + fontSize=20, + textString="n"), + Line( + points={{0,40},{0,22},{-2,14},{2,0},{-2,-14},{2,-24},{0,-40}}, + color={0,0,0}, + smooth=Smooth.Bezier), + Rectangle( + extent={{-100,-2},{100,-40}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Polygon( + points={{-100,-10},{-80,8},{-54,-2},{-36,0},{-6,6},{14,-2},{42,4},{74, + 4},{94,-6},{-100,-10}}, + lineColor={28,108,200}, + lineThickness=0.5, + smooth=Smooth.Bezier, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{-100,40},{100,-40}}, + lineColor={0,0,0}, + lineThickness=1), + Polygon( + points={{-20,4},{-20,4},{-32,18},{-8,18},{-20,4}}, + lineColor={0,0,0}, + lineThickness=0.5), + Ellipse( + extent={{-66,38},{-78,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-28,38},{-40,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-12,38},{-24,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{16,22},{4,10}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{28,38},{16,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{36,22},{24,10}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-58,24},{-70,12}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{74,38},{62,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{48,38},{36,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{86,24},{74,12}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-84,34},{-96,22}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid)})); +end CondensersEvaporatorsPackage; diff --git a/SorpLib/Icons/CondensersEvaporatorsPackage/package.order b/SorpLib/Icons/CondensersEvaporatorsPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/ControllerPackage/package.mo b/SorpLib/Icons/ControllerPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..adda22cdddd14eba8d3d31a3dcc719bb2b78aff0 --- /dev/null +++ b/SorpLib/Icons/ControllerPackage/package.mo @@ -0,0 +1,33 @@ +within SorpLib.Icons; +partial package ControllerPackage "Icon for packages containing controller models of sorption modules" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing controller models of sorption modules. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(graphics={ + Ellipse(extent={{-80,-80},{80,80}}), + Line(points={{80,0},{60,0}}), + Line(points={{69.282,40},{51.962,30}}), + Line(points={{40,69.282},{30,51.962}}), + Line(points={{0,80},{0,60}}), + Line(points={{-40,69.282},{-30,51.962}}), + Line(points={{-69.282,40},{-51.962,30}}), + Line(points={{-80,0},{-60,0}}), + Line(points={{-69.282,-40},{-51.962,-30}}), + Line(points={{-40,-69.282},{-30,-51.962}}), + Line(points={{0,-80},{0,-60}}), + Line(points={{40,-69.282},{30,-51.962}}), + Line(points={{69.282,-40},{51.962,-30}}), + Line(points={{80,0},{60,0}}), + Line(points={{0,0},{-50,50}}), + Line(points={{0,0},{40,0}})})); +end ControllerPackage; diff --git a/SorpLib/Icons/ControllerPackage/package.order b/SorpLib/Icons/ControllerPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/FansPackage/package.mo b/SorpLib/Icons/FansPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a055b0f20cebe50079d1d7b6172e295d00c35d47 --- /dev/null +++ b/SorpLib/Icons/FansPackage/package.mo @@ -0,0 +1,60 @@ +within SorpLib.Icons; +partial package FansPackage "Icon for packages containing fan models" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing pump models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle( + extent={{-90,44},{90,-48}}, + fillColor={244,125,35}, + fillPattern=FillPattern.HorizontalCylinder, + lineColor={0,0,0}), + Polygon( + points={{-48,-48},{-72,-88},{72,-88},{48,-48},{-48,-48}}, + lineColor={0,0,0}, + pattern=LinePattern.None, + fillPattern=FillPattern.VerticalCylinder, + fillColor={0,0,0}), + Ellipse( + extent={{-80,78},{80,-82}}, + fillPattern=FillPattern.Sphere, + fillColor={244,125,35}, + lineColor={0,0,0}), + Polygon( + points={{46,20},{46,-20},{86,0},{46,20}}, + pattern=LinePattern.None, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={255,255,255}), + Polygon( + points={{-100,100},{-100,100}}, + lineColor={0,0,0}, + pattern=LinePattern.None, + fillPattern=FillPattern.Sphere, + fillColor={0,0,0}), + Polygon( + points={{54,40},{42,52},{-48,-40},{-38,-50},{54,40}}, + lineColor={0,0,0}, + pattern=LinePattern.None, + fillPattern=FillPattern.Sphere, + fillColor={255,255,255}, + smooth=Smooth.Bezier, + lineThickness=0.5), + Polygon( + points={{42,-52},{52,-40},{-38,50},{-48,40},{42,-52}}, + lineColor={0,0,0}, + pattern=LinePattern.None, + fillPattern=FillPattern.Sphere, + fillColor={255,255,255}, + smooth=Smooth.Bezier, + lineThickness=0.5)})); +end FansPackage; diff --git a/SorpLib/Icons/FansPackage/package.order b/SorpLib/Icons/FansPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/FittingsPackage/package.mo b/SorpLib/Icons/FittingsPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9abce094cdb8e36a9c727317bd2630887f1fb91e --- /dev/null +++ b/SorpLib/Icons/FittingsPackage/package.mo @@ -0,0 +1,36 @@ +within SorpLib.Icons; +partial package FittingsPackage "Icon for packages containing fitting models" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing fitting models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle( + extent={{-80,50},{80,-50}}, + lineColor={28,108,200}, + fillColor={28,108,200}, + fillPattern=FillPattern.HorizontalCylinder), + Line( + points={{-60,-30},{-60,30},{60,-30},{60,30}}, + thickness=0.5, + color={255,255,255}), + Line( + points={{-60,70},{40,70}}, + color={0,0,0}, + thickness=0.5), + Polygon( + points={{60,70},{40,80},{40,60},{60,70}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={0,0,0})})); +end FittingsPackage; diff --git a/SorpLib/Icons/FittingsPackage/package.order b/SorpLib/Icons/FittingsPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/HeatExchangersPackage/package.mo b/SorpLib/Icons/HeatExchangersPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..85c43aeb17f65390243bdf5568ba95135871a314 --- /dev/null +++ b/SorpLib/Icons/HeatExchangersPackage/package.mo @@ -0,0 +1,95 @@ +within SorpLib.Icons; +partial package HeatExchangersPackage "Icon for packages containing heat exchanger models" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing heat exchanger models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle( + extent={{-100,-24},{100,-28}}, + fillColor={95,95,95}, + fillPattern=FillPattern.Forward), + Rectangle( + extent={{-100,32},{100,28}}, + fillColor={95,95,95}, + fillPattern=FillPattern.Forward), + Rectangle( + extent={{-100,62},{100,32}}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={0,63,125}), + Rectangle( + extent={{-100,-28},{100,-58}}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={0,63,125}), + Rectangle( + extent={{-100,28},{100,-24}}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={0,128,255}), + Line( + points={{30,-83},{-60,-83}}, + color={0,128,255}), + Polygon( + points={{20,-68},{60,-83},{20,-98},{20,-68}}, + lineColor={0,128,255}, + fillColor={0,128,255}, + fillPattern=FillPattern.Solid), + Line( + points={{30,79},{-60,79}}, + color={0,128,255}), + Polygon( + points={{-50,94},{-90,79},{-50,64},{-50,94}}, + lineColor={0,128,255}, + fillColor={0,128,255}, + fillPattern=FillPattern.Solid), + Line( + points={{-36,40},{-56,32},{-62,18},{-50,10},{-36,0},{-38,-12}}, + color={238,46,47}, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.Filled}, + thickness=1), + Line( + points={{-16,40},{-36,32},{-42,18},{-30,10},{-16,0},{-18,-12}}, + color={238,46,47}, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.Filled}, + thickness=1), + Line( + points={{-54,40},{-74,32},{-80,18},{-68,10},{-54,0},{-56,-12}}, + color={238,46,47}, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.Filled}, + thickness=1), + Line( + points={{13,26},{-7,18},{-13,4},{-1,-4},{13,-14},{11,-26}}, + color={238,46,47}, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.Filled}, + thickness=1, + origin={67,-16}, + rotation=180), + Line( + points={{13,26},{-7,18},{-13,4},{-1,-4},{13,-14},{11,-26}}, + color={238,46,47}, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.Filled}, + thickness=1, + origin={47,-16}, + rotation=180), + Line( + points={{13,26},{-7,18},{-13,4},{-1,-4},{13,-14},{11,-26}}, + color={238,46,47}, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.Filled}, + thickness=1, + origin={29,-16}, + rotation=180)})); +end HeatExchangersPackage; diff --git a/SorpLib/Icons/HeatExchangersPackage/package.order b/SorpLib/Icons/HeatExchangersPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/HeatTransfersPackage/package.mo b/SorpLib/Icons/HeatTransfersPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..79d57da192195aac41a1dc3989ec060a714de053 --- /dev/null +++ b/SorpLib/Icons/HeatTransfersPackage/package.mo @@ -0,0 +1,62 @@ +within SorpLib.Icons; +partial package HeatTransfersPackage "Icon for packages containing heat transfer models" + extends Modelica.Icons.Package; + + annotation (Icon(graphics={ + Polygon( + origin={15.758,27.517}, + lineColor = {128,128,128}, + fillColor = {192,192,192}, + fillPattern = FillPattern.Solid, + points = {{-54,-6},{-61,-7},{-75,-15},{-79,-24},{-80,-34},{-78,-42},{-73,-49},{-64,-51},{-57,-51},{-47,-50},{-41,-43},{-38,-35},{-40,-27},{-40,-20},{-42,-13},{-47,-7},{-54,-5},{-54,-6}}), + Polygon( + origin={15.758,27.517}, + fillColor = {160,160,164}, + fillPattern = FillPattern.Solid, + points = {{-75,-15},{-79,-25},{-80,-34},{-78,-42},{-72,-49},{-64,-51},{-57,-51},{-47,-50},{-57,-47},{-65,-45},{-71,-40},{-74,-33},{-76,-23},{-75,-15},{-75,-15}}), + Polygon( + origin={15.758,27.517}, + lineColor = {160,160,164}, + fillColor = {192,192,192}, + fillPattern = FillPattern.Solid, + points = {{39,-6},{32,-7},{18,-15},{14,-24},{13,-34},{15,-42},{20,-49},{29,-51},{36,-51},{46,-50},{52,-43},{55,-35},{53,-27},{53,-20},{51,-13},{46,-7},{39,-5},{39,-6}}), + Polygon( + origin={15.758,27.517}, + fillColor = {160,160,164}, + fillPattern = FillPattern.Solid, + points = {{18,-15},{14,-25},{13,-34},{15,-42},{21,-49},{29,-51},{36,-51},{46,-50},{36,-47},{28,-45},{22,-40},{19,-33},{17,-23},{18,-15},{18,-15}}), + Polygon( + origin={15.758,27.517}, + lineColor = {191,0,0}, + fillColor = {191,0,0}, + fillPattern = FillPattern.Solid, + points = {{-9,-23},{-9,-10},{18,-17},{-9,-23}}), + Line( + origin={15.758,27.517}, + points = {{-41,-17},{-9,-17}}, + color = {191,0,0}, + thickness = 0.5), + Line( + origin={15.758,27.517}, + points = {{-17,-40},{15,-40}}, + color = {191,0,0}, + thickness = 0.5), + Polygon( + origin={15.758,27.517}, + lineColor = {191,0,0}, + fillColor = {191,0,0}, + fillPattern = FillPattern.Solid, + points = {{-17,-46},{-17,-34},{-40,-40},{-17,-46}})}), Documentation( + info="<html> +<p> +This icon indicates a package containing heat transfer models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end HeatTransfersPackage; diff --git a/SorpLib/Icons/HeatTransfersPackage/package.order b/SorpLib/Icons/HeatTransfersPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/MassTransfersPackage/package.mo b/SorpLib/Icons/MassTransfersPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..59d1f8149d619754f437716cadf39dfeae0afb4f --- /dev/null +++ b/SorpLib/Icons/MassTransfersPackage/package.mo @@ -0,0 +1,202 @@ +within SorpLib.Icons; +partial package MassTransfersPackage "Icon for packages containing mass transfer models" + extends Modelica.Icons.Package; + + annotation (Icon(graphics={ + Ellipse( + extent={{84,60},{-36,-60}}, + lineColor={0,0,0}, + fillColor={175,175,175}, + fillPattern=FillPattern.Solid), + Polygon( + points={{-8,54},{-4,46},{-4,38},{-2,32},{2,26},{10,16},{24,14},{56,14}, + {54,8},{44,8},{22,10},{20,6},{28,2},{44,0},{50,-4},{52,-10},{50,-20}, + {46,-26},{42,-34},{32,-38},{22,-40},{16,-40},{6,-36},{8,-32},{14,-36}, + {22,-36},{30,-34},{36,-28},{42,-22},{44,-14},{42,-8},{36,-6},{30,-4}, + {26,-2},{20,0},{16,4},{18,-2},{24,-8},{30,-16},{24,-16},{20,-8},{14, + -2},{12,2},{14,8},{10,12},{4,16},{0,18},{0,14},{-2,10},{0,8},{0,2}, + {0,0},{0,-2},{2,-4},{4,-6},{8,-12},{0,-6},{0,-10},{0,-12},{0,-20}, + {-6,-26},{-4,-10},{-2,-4},{-6,-2},{-20,0},{-26,4},{-24,6},{-12,2}, + {-4,0},{-4,6},{-6,10},{-10,12},{-18,20},{-24,30},{-18,26},{-6,14}, + {-4,20},{-6,26},{-10,32},{-6,40},{-8,54}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + smooth=Smooth.Bezier), + Text( + extent={{-36,78},{-16,58}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.None, + textString="D", + textStyle={TextStyle.Italic}), + Line( + points={{-20,64},{-14,60},{-8,52}}, + color={0,140,72}, + smooth=Smooth.Bezier, + arrow={Arrow.None,Arrow.Filled}, + thickness=0.5), + Line( + points={{-6,50},{-6,42},{-2,28},{8,16},{18,8},{24,0},{38,-4},{48,-12}, + {44,-24},{32,-36},{16,-38},{8,-34}}, + color={0,140,72}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.None,Arrow.Filled}), + Ellipse( + extent={{-8,52},{-6,50}}, + lineColor={0,140,72}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{8,-32},{10,-34}}, + lineColor={0,140,72}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-64,50},{-56,58}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-56,38},{-48,46}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,30},{-62,38}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-56,18},{-48,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-68,10},{-60,18}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-56,0},{-48,8}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-80,18},{-72,26}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-80,42},{-72,50}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-52,60},{-44,68}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-76,62},{-68,70}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-62,72},{-54,80}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-78,-2},{-70,6}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-66,-8},{-58,0}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-52,-20},{-44,-12}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-70,-24},{-62,-16}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-84,-16},{-76,-8}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-82,-36},{-74,-28}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-60,-36},{-52,-28}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-44,-42},{-36,-34}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-72,-52},{-64,-44}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-56,-54},{-48,-46}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-82,-66},{-74,-58}}, + lineColor={28,108,200}, + lineThickness=0.5, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid)}), + Documentation(info="<html> +<p> +This icon indicates a package containing mass transfer models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end MassTransfersPackage; diff --git a/SorpLib/Icons/MassTransfersPackage/package.order b/SorpLib/Icons/MassTransfersPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/MediaPackage/package.mo b/SorpLib/Icons/MediaPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..31c420fffcdf5138dd2e22539394f39d68489cad --- /dev/null +++ b/SorpLib/Icons/MediaPackage/package.mo @@ -0,0 +1,46 @@ +within SorpLib.Icons; +partial package MediaPackage "Icon for packages containing fluid property models" + extends Modelica.Icons.Package; + + annotation (Icon(graphics={ + Line( + points={{-30,30},{-34,98},{-34,98}}, + color={175,175,175}), + Line( + points={{-50,-18},{-64,94},{-64,94}}, + color={175,175,175}), + Line( + points={{-66,-70},{-84,-6},{-84,-6}}, + color={175,175,175}), + Line( + points={{-30,30},{78,30}}, + color={175,175,175}), + Line( + points={{-50,-18},{66,-18}}, + color={175,175,175}), + Line( + points={{-66,-70},{48,-70}}, + color={175,175,175}), + Line( + points={{-66,-70},{-52,-20},{-22,50},{14,76},{58,76},{83,55},{72,2},{58, + -40},{48,-70}}, + color={64,64,64}, + smooth=Smooth.Bezier), + Line( + points={{66,-18},{80,-70}}, + color={175,175,175}), + Line( + points={{78,30},{96,-48}}, + color={175,175,175})}), Documentation(info="<html> +<p> +This icon indicates a package containing fluid property models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end MediaPackage; diff --git a/SorpLib/Icons/MediaPackage/package.order b/SorpLib/Icons/MediaPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/PumpsPackage/package.mo b/SorpLib/Icons/PumpsPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..87e08efe43eab4033b0ee57afa0bb24bcbf881d2 --- /dev/null +++ b/SorpLib/Icons/PumpsPackage/package.mo @@ -0,0 +1,35 @@ +within SorpLib.Icons; +partial package PumpsPackage "Icon for packages containing pump models" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing pump models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle( + extent={{-90,44},{90,-48}}, + fillColor={0,127,255}, + fillPattern=FillPattern.HorizontalCylinder), + Polygon( + points={{-48,-48},{-72,-88},{72,-88},{48,-48},{-48,-48}}, + lineColor={0,0,255}, + pattern=LinePattern.None, + fillPattern=FillPattern.VerticalCylinder), + Ellipse( + extent={{-80,78},{80,-82}}, + fillPattern=FillPattern.Sphere, + fillColor={0,100,199}), + Polygon( + points={{-32,24},{-32,-36},{46,-8},{-32,24}}, + pattern=LinePattern.None, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={255,255,255})})); +end PumpsPackage; diff --git a/SorpLib/Icons/PumpsPackage/package.order b/SorpLib/Icons/PumpsPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/RecoolersPackage/package.mo b/SorpLib/Icons/RecoolersPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..121d59b8b9676ac1ace92b3b5aea92748e2a8105 --- /dev/null +++ b/SorpLib/Icons/RecoolersPackage/package.mo @@ -0,0 +1,152 @@ +within SorpLib.Icons; +partial package RecoolersPackage "Icon for packages containing recoolers" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing recooler models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Polygon( + points={{-100,40},{-100,-40},{-60,-60},{60,-60},{100,-40},{100,40},{60, + 60},{-60,60},{-100,40}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Line( + points={{-100,0},{-80,60},{-60,-60},{-40,60},{-20,-60},{0,60},{20,-60}, + {40,60},{60,-60},{80,60},{98,0}}, + color={28,108,200}, + thickness=1, + smooth=Smooth.Bezier), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-60,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-40,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-20,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={0,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={20,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={40,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={244,125,35}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={60,-46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-60,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-40,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={-20,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={0,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={20,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={40,46}, + rotation=180), + Line( + points={{0,-10},{0,10}}, + color={238,46,47}, + thickness=0.5, + smooth=Smooth.Bezier, + arrow={Arrow.Filled,Arrow.None}, + origin={60,46}, + rotation=180), + Ellipse( + extent={{-60,64},{0,58}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{0,64},{60,58}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid)})); +end RecoolersPackage; diff --git a/SorpLib/Icons/RecoolersPackage/package.order b/SorpLib/Icons/RecoolersPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/SorpLibPackage/package.mo b/SorpLib/Icons/SorpLibPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..17da8123edaff106aa3c2cdae2c4de0f5bd0660b --- /dev/null +++ b/SorpLib/Icons/SorpLibPackage/package.mo @@ -0,0 +1,89 @@ +within SorpLib.Icons; +partial package SorpLibPackage "Icon for the SorpLib Modelica library" + extends Modelica.Icons.Package; + +annotation (Documentation(info="<html> +<p> +This icon is the base icon for the Modelica library SorpLib. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle( + extent={{-92,32},{28,-88}}, + lineColor={0,0,0}, + lineThickness=0.5), + Rectangle( + extent={{-32,92},{88,-28}}, + lineColor={0,0,0}, + lineThickness=0.5), + Line( + points={{-32,92},{-50,74},{-92,32}}, + color={0,0,0}, + thickness=0.5), + Line( + points={{-32,-28},{-50,-46},{-92,-88}}, + color={0,0,0}, + thickness=0.5), + Line( + points={{88,-28},{70,-46},{28,-88}}, + color={0,0,0}, + thickness=0.5), + Line( + points={{88,92},{70,74},{28,32}}, + color={0,0,0}, + thickness=0.5), + Ellipse( + extent={{-94,-90},{-88,-84}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{24,-90},{30,-84}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{84,-30},{90,-24}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-34,-30},{-28,-24}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-34,88},{-28,94}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-94,28},{-88,34}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{24,28},{30,34}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{84,88},{90,94}}, + lineColor={0,0,0}, + lineThickness=0.5, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid)})); +end SorpLibPackage; diff --git a/SorpLib/Icons/SorpLibPackage/package.order b/SorpLib/Icons/SorpLibPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/TubesPackage/package.mo b/SorpLib/Icons/TubesPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..ec883384886ac97e720e1f33d3cfea7e0ac3822a --- /dev/null +++ b/SorpLib/Icons/TubesPackage/package.mo @@ -0,0 +1,44 @@ +within SorpLib.Icons; +partial package TubesPackage "Icon for packages containing tube models" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing heat exchanger models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle( + extent={{-100,-24},{100,-28}}, + fillColor={95,95,95}, + fillPattern=FillPattern.Forward), + Rectangle( + extent={{-100,32},{100,28}}, + fillColor={95,95,95}, + fillPattern=FillPattern.Forward), + Rectangle( + extent={{-100,28},{100,-24}}, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={0,128,255}), + Line( + points={{48,-58},{-52,-58}}, + color={0,0,0}), + Polygon( + points={{20,-44},{60,-59},{20,-74},{20,-44}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Polygon( + points={{-20,15},{20,0},{-20,-15},{-20,15}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid, + origin={-40,-59}, + rotation=180)})); +end TubesPackage; diff --git a/SorpLib/Icons/TubesPackage/package.order b/SorpLib/Icons/TubesPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/ValvesPackage/package.mo b/SorpLib/Icons/ValvesPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2fa52d35992a7a8b502bece5b39d0ad1dede77d6 --- /dev/null +++ b/SorpLib/Icons/ValvesPackage/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Icons; +partial package ValvesPackage "Icon for packages containing valve models" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing valve models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle( + extent={{-20,60},{20,52}}, + fillPattern=FillPattern.Solid), + Line(points={{0,52},{0,0}}), + Polygon(points={{-80,50},{80,-50},{80,50},{0,0},{-80,-50},{-80,50}})})); +end ValvesPackage; diff --git a/SorpLib/Icons/ValvesPackage/package.order b/SorpLib/Icons/ValvesPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/VolumesPackage/package.mo b/SorpLib/Icons/VolumesPackage/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..faedbe3aa4b8246fc91c8c88d4e356a1ae31fe58 --- /dev/null +++ b/SorpLib/Icons/VolumesPackage/package.mo @@ -0,0 +1,50 @@ +within SorpLib.Icons; +partial package VolumesPackage "Icon for packages containing finite volume models" + extends Modelica.Icons.Package; + + annotation (Documentation(info="<html> +<p> +This icon indicates a package containing volume models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>"), Icon(graphics={ + Rectangle(extent={{-90,30},{30,-90}}, lineColor={0,0,0}), + Line(points={{-90,30},{-30,90}}, color={0,0,0}), + Line( + points={{-30,-30},{-90,-90}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line(points={{90,-30},{30,-90}}, color={0,0,0}), + Line(points={{90,90},{30,30}}, color={0,0,0}), + Line(points={{-30,90},{90,90},{90,-30}}, color={0,0,0}), + Line( + points={{90,-30},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line( + points={{-30,90},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dash), + Line( + points={{-60,-60},{60,-60},{60,60},{-60,60},{-60,-60}}, + color={0,0,0}, + pattern=LinePattern.Dot), + Line( + points={{30,-30},{-30,-90},{-30,30},{30,90},{30,30}}, + color={0,0,0}, + pattern=LinePattern.Dot), + Line( + points={{-30,30},{-90,-30},{-30,-30}}, + color={0,0,0}, + pattern=LinePattern.Dot), + Line( + points={{30,-30},{90,30},{30,30}}, + color={0,0,0}, + pattern=LinePattern.Dot)})); +end VolumesPackage; diff --git a/SorpLib/Icons/VolumesPackage/package.order b/SorpLib/Icons/VolumesPackage/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Icons/package.mo b/SorpLib/Icons/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c8bfe402c59cb4b5f2163ba9acaf5cda7f10c74f --- /dev/null +++ b/SorpLib/Icons/package.mo @@ -0,0 +1,19 @@ +within SorpLib; +package Icons "Library of icons" + extends Modelica.Icons.IconsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains definitions of graphical icons used within the Modelica +library SorpLib. The icons should be used via inheritance, using the keyword +\"extends\" in the desired classes. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Icons; diff --git a/SorpLib/Icons/package.order b/SorpLib/Icons/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e481d6911136c9e14764b209df239e4017d5fe60 --- /dev/null +++ b/SorpLib/Icons/package.order @@ -0,0 +1,16 @@ +AdsorbersPackage +AdsorberColumnsPackage +CondensersEvaporatorsPackage +ControllerPackage +FansPackage +FittingsPackage +HeatExchangersPackage +HeatTransfersPackage +MassTransfersPackage +MediaPackage +PumpsPackage +RecoolersPackage +TubesPackage +SorpLibPackage +ValvesPackage +VolumesPackage diff --git a/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/Schmidt.mo b/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/Schmidt.mo deleted file mode 100644 index 9acbc65c85ee26665e3c2505379910528966996e..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/Schmidt.mo +++ /dev/null @@ -1,53 +0,0 @@ -within SorpLib.Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube; -model Schmidt "Schmidt-Korrelation" - extends - TIL.LiquidComponents.Tubes.TransportPhenomena.HeatTransfer.PartialHeatTransfer( - final computeTransportProperties=true, final useAlphaAState=true); - - Real Re "Reynolds-Number"; - Real Nu "Nusselt-Number"; - - Modelica.SIunits.CoefficientOfHeatTransfer alpha "Heat transfer coefficient"; - - Real zeta "Resistance coefficient"; - - parameter Modelica.SIunits.Diameter coilDiameter=0.05 "Diameter of tube coil"; - -equation - - Re = noEvent(abs(mdotHydraulic))/cellGeometry.hydraulicCrossSectionalArea*tubeGeometry.hydraulicDiameter/properties.transp.eta; - zeta = 0.3164/Re^0.25+0.03*(tubeGeometry.hydraulicDiameter/coilDiameter)^0.5; - - Nu = (zeta/8*Re*properties.transp.Pr)/(1 + 12.7*sqrt(zeta/8)*(properties.transp.Pr^(2/3) - 1)); - alpha = Nu*properties.transp.lambda/tubeGeometry.hydraulicDiameter; - - alphaA = alpha*cellGeometry.heatTransferArea; - annotation (Documentation(info="<html> -<p> - This transfer model calculates heat transfer coefficients according to the Schmidt-Correlation (1967) for tube coils. - The original form of the equation is slightly simplified by neglecting the viscosity factor. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> <i>Q</i><sub>in</sub> = <i><code>α</code> A</i> (<i>T</i><sub>in</sub> - <i>T</i><sub>out</sub>) </p> - <p>where <i><code>α</code></i> is the heat tranfer coefficient and <i>A</i> is the heat transfer area. <i><code>α</code></i> is derived from a correlation between between the dimensionless quantities Nusselt number <i>Nu</i>, Reynolds number <i>Re</i> and Prandtl number <i>Pr</i>: </p> - <p align=\"center\"> <i>Nu</i> = (<i><code>ζ</code></i>/8 <i>Re</i> <i>Pr</i>) / (1 + 12.7 <code>√</code>(<i><code>ζ</code></i>/8) (<i>Pr</i><sup>2/3</sup> - 1)) </p> - with - <p align=\"center\"> <i><code>ζ</code></i> = 0.3164/<i>Re</i><sup>0.25</sup> + 0.03 (<i>d</i><sub>i</sub>/<i>D</i><sub>coil</sub>)<sup>0.5</sup> </p> - <p>where <i>d</i><sub>i</sub> is the hydraulic diameter and <i>D</i><sub>coil</sub> is the diameter of the tube coil. </p> -</p> -<h4>References</h4> -<ul> - <li>Schmidt E. F. Wärmeübergang und Druckverlust in Rohrschlangen. Chemie Ingenieur Technik, 1967.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - December 06, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end Schmidt; diff --git a/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/SiederTate.mo b/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/SiederTate.mo deleted file mode 100644 index 56d0ee904c94ea293de872ffb55293d12fc80540..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/SiederTate.mo +++ /dev/null @@ -1,47 +0,0 @@ -within SorpLib.Internals.AdditionalTransferPhenomena.HeatTransfer_insideTube; -model SiederTate "SiederTate-Korrelation" - extends - TIL.LiquidComponents.Tubes.TransportPhenomena.HeatTransfer.PartialHeatTransfer( - final computeTransportProperties=true, final useAlphaAState=true); - - Real Re "Reynolds-Number"; - Real Nu "Nusselt-Number"; - - Modelica.SIunits.CoefficientOfHeatTransfer alpha "Heat tranfer coefficient"; - - parameter Real SiederTateConstant=0.027 "Sider-Tate-Constant"; - -equation - Re = noEvent(abs(mdotHydraulic))/cellGeometry.hydraulicCrossSectionalArea*tubeGeometry.hydraulicDiameter/properties.transp.eta; - - Nu = SiederTateConstant*Re^0.8*properties.transp.Pr^(1/3); - alpha = Nu*properties.transp.lambda/tubeGeometry.hydraulicDiameter; - - alphaA = alpha*cellGeometry.heatTransferArea; - annotation (Documentation(info="<html> -<p> - This transfer model calculates heat transfer coefficients according to the Sieder-Tate-Correlation (1936) for turbulend liquid flows in tubes. - The original form of the equation is slightly simplified by neglecting the viscosity factor. -</p> -<h4>Main equations</h4> -<p> - <p align=\"center\"> <i>Q</i><sub>in</sub> = <i><code>α</code> A</i> (<i>T</i><sub>in</sub> - <i>T</i><sub>out</sub>) </p> - <p>where <i><code>α</code></i> is the heat tranfer coefficient and <i>A</i> is the heat transfer area. <i><code>α</code></i> is derived from a correlation between between the dimensionless quantities Nusselt number <i>Nu</i>, Reynolds number <i>Re</i> and Prandtl number <i>Pr</i>: </p> - <p align=\"center\"> <i>Nu</i> = <i>C</i><sub>ST</sub> <i>Re</i><sup>0.8</sup> <i>Pr</i><sup>1/3</sup> </p> - <p>where <i>C</i><sub>ST</sub> is the Sieder-Tate-Constant. </p> -</p> -<h4>References</h4> -<ul> - <li>Sieder E. N. and Tate G. E. Heat Transfer and Pressure Drop of Liquids in Tubes. Industrial and Engineering Chemistry, 1936.</li> -</ul> -<h4>Author Information</h4> -<p> - <ul> - <li> - December 06, 2017, by Andrej Gibelhaus:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end SiederTate; diff --git a/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/package.mo b/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/package.mo deleted file mode 100644 index edd9923dfd12f502f29b8a491b56857bb450b211..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/package.mo +++ /dev/null @@ -1,11 +0,0 @@ -within SorpLib.Internals.AdditionalTransferPhenomena; -package HeatTransfer_insideTube - extends SorpLib.Internals.ClassTypes.ModelPackage; - - -annotation (Documentation(info="<html> -<p> - This package contains additional heat transfer phenomena, which can be used in the tube model of the TIL library. -</p> -</html>")); -end HeatTransfer_insideTube; diff --git a/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/package.order b/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/package.order deleted file mode 100644 index 27969ddef7d3e0094931e001b4ab120a074b43d4..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/AdditionalTransferPhenomena/HeatTransfer_insideTube/package.order +++ /dev/null @@ -1,2 +0,0 @@ -SiederTate -Schmidt diff --git a/SorpLib/Internals/AdditionalTransferPhenomena/package.mo b/SorpLib/Internals/AdditionalTransferPhenomena/package.mo deleted file mode 100644 index 8565cdc95306e3931551e0da929aef30854f5fc2..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/AdditionalTransferPhenomena/package.mo +++ /dev/null @@ -1,5 +0,0 @@ -within SorpLib.Internals; -package AdditionalTransferPhenomena - extends SorpLib.Internals.ClassTypes.ModelPackage; - -end AdditionalTransferPhenomena; diff --git a/SorpLib/Internals/AdditionalTransferPhenomena/package.order b/SorpLib/Internals/AdditionalTransferPhenomena/package.order deleted file mode 100644 index 14d0e73bb9d743abbfcb1a8c4cf3249d70a4596c..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/AdditionalTransferPhenomena/package.order +++ /dev/null @@ -1 +0,0 @@ -HeatTransfer_insideTube diff --git a/SorpLib/Internals/ClassTypes/ApplicationPackage.mo b/SorpLib/Internals/ClassTypes/ApplicationPackage.mo deleted file mode 100644 index 51e2a2a4a1c26102946357088c0ff6785b0dddc1..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/ClassTypes/ApplicationPackage.mo +++ /dev/null @@ -1,11 +0,0 @@ -within SorpLib.Internals.ClassTypes; -partial class ApplicationPackage - - annotation (Icon(graphics={Ellipse( - extent={{-100,100},{100,-100}}, - pattern=LinePattern.None, - fillColor={213,0,0}, - fillPattern=FillPattern.Solid, - lineColor={0,0,0})})); - -end ApplicationPackage; diff --git a/SorpLib/Internals/ClassTypes/ComponentPackage.mo b/SorpLib/Internals/ClassTypes/ComponentPackage.mo deleted file mode 100644 index 1481b14ac129e34a6461972046f6242b589be897..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/ClassTypes/ComponentPackage.mo +++ /dev/null @@ -1,11 +0,0 @@ -within SorpLib.Internals.ClassTypes; -partial class ComponentPackage - - annotation (Icon(graphics={Ellipse( - extent={{-100,100},{100,-100}}, - fillColor={170,213,255}, - fillPattern=FillPattern.Solid, - pattern=LinePattern.None, - lineColor={0,0,0})}), classOrder={"*","Internals","Testers"}); - -end ComponentPackage; diff --git a/SorpLib/Internals/ClassTypes/InternalPackage.mo b/SorpLib/Internals/ClassTypes/InternalPackage.mo deleted file mode 100644 index 919c334585768f627239c22995ca1dbdb6283741..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/ClassTypes/InternalPackage.mo +++ /dev/null @@ -1,10 +0,0 @@ -within SorpLib.Internals.ClassTypes; -partial class InternalPackage - - annotation (Icon(graphics={Ellipse( - extent={{-100,100},{100,-100}}, - pattern=LinePattern.None, - fillColor={215,215,215}, - fillPattern=FillPattern.Solid, - lineColor={0,0,0})})); -end InternalPackage; diff --git a/SorpLib/Internals/ClassTypes/ModelPackage.mo b/SorpLib/Internals/ClassTypes/ModelPackage.mo deleted file mode 100644 index 8d265c06c8815b4c0af6ef01001ca4314a0e28b3..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/ClassTypes/ModelPackage.mo +++ /dev/null @@ -1,10 +0,0 @@ -within SorpLib.Internals.ClassTypes; -partial class ModelPackage - - annotation (Icon(graphics={Ellipse( - extent={{-100,100},{100,-100}}, - pattern=LinePattern.None, - fillColor={240,221,5}, - fillPattern=FillPattern.Solid, - lineColor={0,0,0})})); -end ModelPackage; diff --git a/SorpLib/Internals/ClassTypes/PartialPackage.mo b/SorpLib/Internals/ClassTypes/PartialPackage.mo deleted file mode 100644 index 6d4411bab971d9d9b16e4de357fde00f9192d9d6..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/ClassTypes/PartialPackage.mo +++ /dev/null @@ -1,11 +0,0 @@ -within SorpLib.Internals.ClassTypes; -partial class PartialPackage - - annotation (Icon(graphics={Ellipse( - extent={{-100,100},{100,-100}}, - pattern=LinePattern.None, - fillColor={34,139,34}, - fillPattern=FillPattern.Solid, - lineColor={0,0,0})})); - -end PartialPackage; diff --git a/SorpLib/Internals/ClassTypes/Record.mo b/SorpLib/Internals/ClassTypes/Record.mo deleted file mode 100644 index 4d5188ebfc5a58c71f142b13ceb2a059005f0aa5..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/ClassTypes/Record.mo +++ /dev/null @@ -1,13 +0,0 @@ -within SorpLib.Internals.ClassTypes; -partial record Record "Partial Record" - - annotation (Icon(graphics={Text( - extent={{-100,110},{100,70}}, - lineColor={0,0,0}, - textString="%name"),Bitmap( - extent={{-100,60},{100,-100}}, - imageSource= - "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAABnRSTlMA/wAAAACkwsAdAAAACXBIWXMAAAsTAAALEwEAmpwYAAACp0lEQVR42u3cMU4CQRSA4V2lVDsDYTmMpbUJcACtSTgJ6i2AS1ChHoAbQELCFSgsKCxNXJ7uW7+/32Qz8+VNsztlv1sVanyj8Wj2Okv0wpfXVze2rfltNpvt49P9x3uWFy5PE2u3367Xb/avmQ0fhunm1hcs+9fYqt4g3Zl4YdtytZgvppMpWDrfgTgeJrIFVpqeX2aJbIHFFljKYwsstsBSHltgsQWW8tgCiy2wlMcWWGyBpTy2wGILLOWxBRZbIXXqPLw6HG1kM20VRbGcL0+2isn0978NNLHMLbCUxxZYbIGlPLbAYgss5bEFFltgKY8tsNgCS3lsgcVWiC2w2AqxBRZbIbbAYivEFlhshdgCSyG2wFKILbAUYgsshdgCSyG2wFKILbAUYgsshdgCSyG2wFKILbAUYgsshdgCSyG2wFKILbAUYgsshdgCSyG2wFKILbAUYgsshdgCSyG2wFKIrY51yVLVG6R4z9M9zSaWQmyV/W5VFMVuv7UcOuNkNbEUElgCS2AJLAksgSWwJLAElsCSwBJYAksCS2AJLAksgaX/Vq2/dFaHoxVscXe3P+dhYslRKLAElgSWwBJYElgCS2BJYAksgSWBJbAElgSWwBJYElgCS2BJYAksgSWBJbAElgSWwBJYElgCS2BJYAksgSWBJbDU4mrd817nHnCZWBJYAktgSWAJLIElgSWwBJYElsASWBJYAktgSWAJLIElfVOtj9ZXh6MVbHF1/mkwseQoFFgCSwJLYAksCSyBJbAksASWwJLAElgCSwJLYAksCSyBJbAksASWwJLAElgCSwJLYAksCSyBJbAksASWwJLAElhqcbXuea9zD7hMLAksgSWwJLAElsCSwBJYAksCS2AJLAksgSWwJLD0R5X9bmUVZGIpR5/i9W1YEPGgigAAAABJRU5ErkJggg==", - fileName="modelica://TIL/Images/Record.png")})); - -end Record; diff --git a/SorpLib/Internals/ClassTypes/RecordPackage.mo b/SorpLib/Internals/ClassTypes/RecordPackage.mo deleted file mode 100644 index ddc5a36db1980134835cfefc9db5af6990e99f35..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/ClassTypes/RecordPackage.mo +++ /dev/null @@ -1,11 +0,0 @@ -within SorpLib.Internals.ClassTypes; -partial class RecordPackage - - annotation (Icon(graphics={Ellipse( - extent={{-100,100},{100,-100}}, - fillColor={255,165,0}, - fillPattern=FillPattern.Solid, - pattern=LinePattern.None, - lineColor={0,0,0})}), classOrder={"*","Internals","Testers"}); - -end RecordPackage; diff --git a/SorpLib/Internals/ClassTypes/package.mo b/SorpLib/Internals/ClassTypes/package.mo deleted file mode 100644 index 81511be2fc528289f6bf0c974b7b933d2cbbce70..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/ClassTypes/package.mo +++ /dev/null @@ -1,19 +0,0 @@ -within SorpLib.Internals; -package ClassTypes "Icon definitions" - - - - - - - - - - -annotation (Icon(graphics={Ellipse( - extent={{-100,100},{100,-100}}, - pattern=LinePattern.None, - fillColor={215,215,215}, - fillPattern=FillPattern.Solid, - lineColor={0,0,0})})); -end ClassTypes; diff --git a/SorpLib/Internals/ClassTypes/package.order b/SorpLib/Internals/ClassTypes/package.order deleted file mode 100644 index 515302a00cf4acdfb35464b7dfd81cbc02b9aed0..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/ClassTypes/package.order +++ /dev/null @@ -1,7 +0,0 @@ -ModelPackage -ComponentPackage -ApplicationPackage -InternalPackage -PartialPackage -RecordPackage -Record diff --git a/SorpLib/Internals/SmoothTransition/SmoothSwitch.mo b/SorpLib/Internals/SmoothTransition/SmoothSwitch.mo deleted file mode 100644 index 612a21d3b11a0ff1994484541de505438ce1dde8..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/SmoothTransition/SmoothSwitch.mo +++ /dev/null @@ -1,53 +0,0 @@ -within SorpLib.Internals.SmoothTransition; -model SmoothSwitch - - Modelica.Blocks.Interfaces.BooleanInput u(start=false, fixed=true) - annotation (Placement(transformation(extent={{-115,-15},{-85,15}}))); - Modelica.Blocks.Interfaces.RealOutput y - annotation (Placement(transformation(extent={{87,-13},{113,13}}))); - - discrete Modelica.SIunits.Time start_time; - parameter Modelica.SIunits.Time interval=5 - "duration of smooth transition period"; - -protected - Boolean z(start=true, fixed=true); - Modelica.SIunits.Time time_act; - Modelica.SIunits.Time interval_act; - -initial equation - start_time = if u then 1000000 else -1000000; -equation - - time_act = if u then -time else time; - interval_act = if u then -interval/2 else interval/2; - - z = not u; - - when edge(u) or edge(z) then - start_time = -(pre(time_act) + pre(interval_act)); - end when; - - y = TIL.Utilities.Numerics.smoothTransition( - time_act, - start_time, - interval); - - annotation (Diagram(graphics), Icon(graphics={Rectangle( - extent={{-100,-100},{100,100}}, - lineColor={0,0,127}, - fillColor={255,255,255}, - fillPattern=FillPattern.Solid),Line(points={{-80,68},{-80,-80}}, - color={192,192,192}),Polygon( - points={{-80,90},{-88,68},{-72,68},{-80,90}}, - lineColor={192,192,192}, - fillColor={192,192,192}, - fillPattern=FillPattern.Solid),Line(points={{-90,-70},{82,-70}}, - color={192,192,192}),Polygon( - points={{90,-70},{68,-62},{68,-78},{90,-70}}, - lineColor={192,192,192}, - fillColor={192,192,192}, - fillPattern=FillPattern.Solid),Line(points={{-80,-70},{-50,-70},{-40, - -69.8838},{-30,-66.8763},{-20,-52.2781},{-10,-20.3259},{0,20.3259},{ - 10,52.2781},{20,66.8763},{30,69.8838},{40,70},{70,70}}, color={0,0,0})})); -end SmoothSwitch; diff --git a/SorpLib/Internals/SmoothTransition/Testers/package.mo b/SorpLib/Internals/SmoothTransition/Testers/package.mo deleted file mode 100644 index 8ddab8e6223bb877d34c7ba60441d893374c7888..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/SmoothTransition/Testers/package.mo +++ /dev/null @@ -1,21 +0,0 @@ -within SorpLib.Internals.SmoothTransition; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - model SmoothTransitionTester - - SmoothSwitch smoothSwitch - annotation (Placement(transformation(extent={{-2,2},{18,22}}))); - Modelica.Blocks.Sources.BooleanPulse booleanPulse(period=50, startTime=50) - annotation (Placement(transformation(extent={{-40,2},{-20,22}}))); - equation - connect(booleanPulse.y, smoothSwitch.u) annotation (Line( - points={{-19,12},{-2,12}}, - color={255,0,255}, - smooth=Smooth.None)); - annotation ( - Diagram(graphics), - experiment(StopTime=200, Interval=0.1), - __Dymola_experimentSetupOutput); - end SmoothTransitionTester; -end Testers; diff --git a/SorpLib/Internals/SmoothTransition/Testers/package.order b/SorpLib/Internals/SmoothTransition/Testers/package.order deleted file mode 100644 index 9913f813b620ff9770e85fe30b440d394836b8dd..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/SmoothTransition/Testers/package.order +++ /dev/null @@ -1 +0,0 @@ -SmoothTransitionTester diff --git a/SorpLib/Internals/SmoothTransition/package.mo b/SorpLib/Internals/SmoothTransition/package.mo deleted file mode 100644 index 55c35bbe9e2e4d002c36241ffcdf37ad05fc4de6..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/SmoothTransition/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Internals; -package SmoothTransition -extends SorpLib.Internals.ClassTypes.ComponentPackage; - - -end SmoothTransition; diff --git a/SorpLib/Internals/SmoothTransition/package.order b/SorpLib/Internals/SmoothTransition/package.order deleted file mode 100644 index 378e45a4a38c086840fe0a55bbd8d641a2a5134a..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/SmoothTransition/package.order +++ /dev/null @@ -1,2 +0,0 @@ -SmoothSwitch -Testers diff --git a/SorpLib/Internals/package.mo b/SorpLib/Internals/package.mo deleted file mode 100644 index c0fd3f09fb1b804011b0732c26e3716cda45f676..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/package.mo +++ /dev/null @@ -1,12 +0,0 @@ -within SorpLib; -package Internals "Internal functions" - - - -annotation (Icon(graphics={Ellipse( - extent={{-100,100},{100,-100}}, - pattern=LinePattern.None, - fillColor={215,215,215}, - fillPattern=FillPattern.Solid, - lineColor={0,0,0})})); -end Internals; diff --git a/SorpLib/Internals/package.order b/SorpLib/Internals/package.order deleted file mode 100644 index 442300f68e8a058e4f0408da1f35ededdcaa24c5..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/package.order +++ /dev/null @@ -1,4 +0,0 @@ -ClassTypes -SmoothTransition -AdditionalTransferPhenomena -systime diff --git a/SorpLib/Internals/systime.mo b/SorpLib/Internals/systime.mo deleted file mode 100644 index d191e769a52dd2404e84d1edb3f37b54caa6b3dc..0000000000000000000000000000000000000000 --- a/SorpLib/Internals/systime.mo +++ /dev/null @@ -1,9 +0,0 @@ -within SorpLib.Internals; -function systime "Returns current timestamp (of computer, not the simulation) " - output Real systime; - -external"C"; - annotation (Include="#include <systime.c>"); - // Don't forget to move systime.c to current working folder - -end systime; diff --git a/SorpLib/Media/AdsorbentAdsorbate/AQSOAZ02WaterGoldsworthy.mo b/SorpLib/Media/AdsorbentAdsorbate/AQSOAZ02WaterGoldsworthy.mo deleted file mode 100644 index 6ea6411e688e2658f4731c2f0ad613bead732105..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/AQSOAZ02WaterGoldsworthy.mo +++ /dev/null @@ -1,45 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate; -model AQSOAZ02WaterGoldsworthy "AQSOA Z02 / Water, published by Goldsworthy (2014)" - extends SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin( - c_Sorbent=1000); - - final parameter Real[4] c={3.466e-4,3.094e5,-9.765e4, - 7.312e-7} "Coefficients for characteristic curve"; - -equation - W = SorpLib.Media.Functions.CharCurve1Arctan(A,c); - h_bond = -A + T*water.VLEAdditional.beta_l*W/ - SorpLib.Media.Functions.CharCurve1Arctan_dWdA(A,c); - - assert(A>100e3, "The characteristic curve is not valid in this range of adsorption potential A"); - assert(A<1500e3, "The characteristic curve is not valid in this range of adsorption potential A"); - - annotation (Documentation(info="<html> -<p> - This model provides the equilibrium data for the working pair AQSOA Z02 / Water as measured by Goldsworthy (2014). <br> - The implementation is based on the Dubinin model, see <a href=\"modelica://SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin\">SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin</a>.<br> - The fit parameters were generated at the Chair of Technical Thermodynamics based on the reported measurement data by Goldsworthy (2014). -</p> -<h4>Main equations</h4> -<p> - see <a href=\"modelica://SorpLib.Media.Functions.CharCurve1Arctan\">SorpLib.Media.Functions.CharCurve1Arctan</a><br> - see <a href=\"modelica://SorpLib.Media.Functions.CharCurve1Arctan_dWdA\">SorpLib.Media.Functions.CharCurve1Arctan_dWdA</a> -</p> -<h4>References</h4> -<p> - <ul> - <li>Dubinin, M.M. Adsorption in micropores. J. Colloid Interface Sci., 1967, 23(4), 487-499.</li> - <li>Goldsworthy, M.J. Measurements of water vapour sorption isotherms for RD silica gel, AQSOA-Z01, AQSOA-Z02, AQSOA-Z05 and CECA zeolite 3A. Microporous and Mesoporous Materials, 2014, 196, 59-67.. </li> - </ul> -</p> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 17, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end AQSOAZ02WaterGoldsworthy; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Partial/PartialAdsorbentWater.mo b/SorpLib/Media/AdsorbentAdsorbate/Partial/PartialAdsorbentWater.mo deleted file mode 100644 index 7b548bb4fdfeb137662d4d3e636bbeda81574e6a..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Partial/PartialAdsorbentWater.mo +++ /dev/null @@ -1,57 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate.Partial; -partial model PartialAdsorbentWater "Base model for Adsorbent / Water System" - - Modelica.SIunits.Pressure p(start=5000) "Partial Water pressure"; - input Real x(unit="kg/kg") "Water mass fraction"; - input Modelica.SIunits.Temperature T "Temperature"; - - Modelica.SIunits.SpecificEnthalpy h_ads "Enthalpy of water in adsorbed phase"; - Modelica.SIunits.SpecificInternalEnergy u_ads - "Internal energy of water in adsorbed phase"; - Real dudT_x(unit="J/(kg.K)") "Partial derivative of u wrt T at constant x"; - - /********************** Parameters *********************************/ - - final Modelica.SIunits.SpecificHeatCapacity R_Water=Modelica.Constants.R/water.M - "Specific gas constant of water [J/kg K]"; - - parameter Modelica.SIunits.SpecificHeatCapacity c_Sorbent=1000 - "Constant Heat Capacity of Sorbent [J/kg K]"; - - final parameter TILMedia.VLEFluidTypes.TILMedia_Water vleFluidType; - - /********************** Object water *********************************/ - - TILMedia.VLEFluid_dT water( - final vleFluidType=vleFluidType, - T=T, - d=water.VLE.d_l, - computeVLEAdditionalProperties=true) - annotation (Placement(transformation(extent={{-10,-12},{10,8}}))); - -equation - u_ads=h_ads-p/water.d; - dudT_x = c_Sorbent + x*water.VLEAdditional.cp_l; - - annotation (Icon(graphics={Bitmap(extent={{-190,-168},{192,124}}, fileName= - "modelica://SorpLib/Resources/Images/AdsorbensAdsorbate.png")}), - Documentation(info="<html> -<p>This partial model contains all necessary variables and the basic equations to describe equilibrium data </p> -<p>The partial model needs to be extended by the specific functions for each working pair </p> -<h4>Main equations</h4> -<p align=\"center\"><i>u<sub>ads</sub> = h<sub>ads</sub> - p<sub>ad</sub> / <code>ρ</code><sub>ad</sub> </i></p> -<p>where <i>u</i><sub>ads</sub> is the specific internal energy of the adsorbate, <i>h</i><sub>ads</sub> is the specific enthalpy of the adsorbate of the adsorbate, <i>p</i><sub>ad</sub> is the -pressure and <i><code>ρ</code></i><sub>ad</sub> is the density of the adsorbate</p> -<p align=\"center\"><i>dudT_x = c<sub>sor</sub> + x * c<sub>ad</sub> , </i></p> -<p>where <i>dudT_x</i> is the specific heat capacity of adsorbent and adsorbate, <i>c</i><sub>sor</sub> is the specific heat capacity of the adsorbent, <i>x</i> is the loading and -<i>c</i><sub>ad</sub> is the specific heat capacity of the adsorbate (approximated by the specific heat capacity of liquid water).</p> -<h4>References</h4> -<ul> -<li>Núñez, T. Charakterisierung und Bewertung von Adsorbentien für Wärmetransformationsanwendungen. PhD Thesis. Freiburg, 2001. </li> -</ul> -<h4>Author Information</h4> -<ul> -<li>November 17, 2017, by Uwe Bau:<br>Tidy up implementation and enhance documentation for publication of library.<br></li> -</ul> -</html>")); -end PartialAdsorbentWater; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Partial/PartialAdsorbentWaterDubinin.mo b/SorpLib/Media/AdsorbentAdsorbate/Partial/PartialAdsorbentWaterDubinin.mo deleted file mode 100644 index e981cec1b47c5c991bb6eeb6e71a70dbb39afefd..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Partial/PartialAdsorbentWaterDubinin.mo +++ /dev/null @@ -1,34 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate.Partial; -partial model PartialAdsorbentWaterDubinin - "Base model for Adsorbent / Water System based on the model of Dubinin" - extends SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWater; - - Modelica.SIunits.SpecificVolume W(start=5e-5) "Specific volume of adsorbate"; - Modelica.SIunits.SpecificEnergy A(start=1e5) "Adsorption Potential"; - Modelica.SIunits.SpecificEnthalpy h_bond "Bonding enthalpy"; - -equation - W = x/water.VLE.d_l; - p = water.p*exp(-A/R_Water/T); - h_ads = water.VLE.h_l + h_bond; - annotation (Documentation(info="<html> -<p>This partial model provides the basic equations to describe equilibrium data for the working pair according to the Dubinin (1967) model.</p><p>The partial model needs to be extended by the specific functions based on the characteristic curve: W = f(A) and h<sub>bond</sub>. </p> -<h4>Main equations</h4> -<p align=\"center\"><i>W = x / <code>ρ</code><sub>ad</sub>(T) , </i></p> -<p>where <i>W</i> is the specific volume of the adsorbate, <i>x</i> is the loading, <code><i>ρ</i></code><sub>ad</sub> is the density of the adsorbate, and <i>T</i> is the temperature. </p> -<p align=\"center\"><i>p = p<sub>s</sub>(T) exp(-A / (R T)) , </i></p> -<p>where <i>A</i> is the adsorption potential, <i>p</i><sub>s</sub>(<i>T</i>) is the saturation pressure at temperature <i>T</i>, and <i>R</i> is the specific gas constant of water.</p> -<p><br><i>h</i><sub>ads</sub> describes the specific enthalpy of the adsorbate given the specific enthalpy of water as reference state. </p> -<p align=\"center\"><i>h<sub>ads</sub> = h<sub>l</sub> + h<sub>bond</sub> , </i></p> -<p>where <i>h</i><sub>l</sub> is specific enthalpy of liquid water and <i>h</i><sub>bond</sub> is the specific bonding enthalpy. </p> -<h4>References</h4> -<ul> -<li>Dubinin, M.M. Adsorption in micropores. J. Colloid Interface Sci., 1967, 23(4), 487-499. </li> -<li>Núñez, T. Charakterisierung und Bewertung von Adsorbentien für Wärmetransformationsanwendungen. PhD Thesis. Freiburg, 2001. </li> -</ul> -<h4>Author Information</h4> -<ul> -<li>November 17, 2017, by Uwe Bau:<br>Tidy up implementation and enhance documentation for publication of library.<br></li> -</ul> -</html>")); -end PartialAdsorbentWaterDubinin; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Partial/package.mo b/SorpLib/Media/AdsorbentAdsorbate/Partial/package.mo deleted file mode 100644 index 847d5128a483518e5ea1e5ebbe7f919ad7d82d73..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Partial/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate; -package Partial - extends SorpLib.Internals.ClassTypes.PartialPackage; - - -end Partial; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Partial/package.order b/SorpLib/Media/AdsorbentAdsorbate/Partial/package.order deleted file mode 100644 index ed8adc1607208295f1d06b2626ef97aac489db57..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Partial/package.order +++ /dev/null @@ -1,2 +0,0 @@ -PartialAdsorbentWater -PartialAdsorbentWaterDubinin diff --git a/SorpLib/Media/AdsorbentAdsorbate/SilgelGrace123WaterSchawe.mo b/SorpLib/Media/AdsorbentAdsorbate/SilgelGrace123WaterSchawe.mo deleted file mode 100644 index defd18ea086b59123a5e424bf2a6bf991f8f933d..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/SilgelGrace123WaterSchawe.mo +++ /dev/null @@ -1,44 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate; -model SilgelGrace123WaterSchawe - "Silicagel Grace 123 / Water, published by Schawe (1999)" - extends SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin( - c_Sorbent=1000); - - final parameter Real[4] c={5.072313e-4,1.305531e5,-8.492403e4,4.128962e-6} "Coefficients for characteristic curve"; - -equation - W = SorpLib.Media.Functions.CharCurve1Arctan(A,c); - h_bond = -A + T*water.VLEAdditional.beta_l*W/ - SorpLib.Media.Functions.CharCurve1Arctan_dWdA(A,c); - - assert(A>17e3, "The characteristic curve is not valid in this range of adsorption potential A"); - assert(A<1940e3, "The characteristic curve is not valid in this range of adsorption potential A"); - - annotation (Documentation(info="<html> -<p> - This model provides the equilibrium data for the working pair Silica gel Grace 123 / Water as measured by Schawe (1999).<br> - The implementation is based on the Dubinin model, see <a href=\"modelica://SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin\">SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin</a>. -</p> -<h4>Main equations</h4> -<p> - see <a href=\"modelica://SorpLib.Media.Functions.CharCurve1Arctan\">SorpLib.Media.Functions.CharCurve1Arctan</a><br> - see <a href=\"modelica://SorpLib.Media.Functions.CharCurve1Arctan_dWdA\">SorpLib.Media.Functions.CharCurve1Arctan_dWdA</a> -</p> -<h4>References</h4> -<p> - <ul> - <li>Dubinin, M.M. Adsorption in micropores. J. Colloid Interface Sci., 1967, 23(4), 487-499.</li> - <li>Schawe, D. Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers. PhD Thesis. Stuttgart, 1999. </li> - </ul> -</p> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 17, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end SilgelGrace123WaterSchawe; diff --git a/SorpLib/Media/AdsorbentAdsorbate/SilgelGrace125WaterNunez.mo b/SorpLib/Media/AdsorbentAdsorbate/SilgelGrace125WaterNunez.mo deleted file mode 100644 index 6832389d709f4be494fb650e33f2c26fa3d04a18..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/SilgelGrace125WaterNunez.mo +++ /dev/null @@ -1,47 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate; -model SilgelGrace125WaterNunez - "Silicagel Grace 125 / Water, published by Nunez (2001)" - extends SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin( - c_Sorbent=1000); - - final parameter Real[3] cNom={5.66e-14,0,0.3545} - "Coefficients for nominator of characteristic curve"; - final parameter Real[3] cDenom={4.13143e-8,0,1000} - "Coefficients for denominator of characteristic curve"; - -equation - W = SorpLib.Media.Functions.CharCurve2Polynomial(A,cNom,cDenom); - h_bond = -A + T*water.VLEAdditional.beta_l*W/ - SorpLib.Media.Functions.CharCurve2Polynomial_dWdA(A,cNom,cDenom); - - assert(A>17e3, "The characteristic curve is not valid in this range of adsorption potential A"); - assert(A<1940e3, "The characteristic curve is not valid in this range of adsorption potential A"); - - annotation (Documentation(info="<html> -<p> - This model provides the equilibrium data for the working pair Silica gel Grace 125 / Water as measured by Núñez (2001). <br> - The implementation is based on the Dubinin model, see <a href=\"modelica://SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin\">SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin</a>. -</p> -<h4>Main equations</h4> -<p> - see <a href=\"modelica://SorpLib.Media.Functions.CharCurve1Arctan\">SorpLib.Media.Functions.CharCurve1Arctan</a><br> - see <a href=\"modelica://SorpLib.Media.Functions.CharCurve1Arctan_dWdA\">SorpLib.Media.Functions.CharCurve1Arctan_dWdA</a> -</p> -<h4>References</h4> -<p> - <ul> - <li>Dubinin, M.M. Adsorption in micropores. J. Colloid Interface Sci., 1967, 23(4), 487-499.</li> - <li>Núñez, T. Charakterisierung und Bewertung von Adsorbentien für Wärmetransformationsanwendungen. PhD Thesis. Freiburg, 2001. </li> - </ul> -</p> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 17, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end SilgelGrace125WaterNunez; diff --git a/SorpLib/Media/AdsorbentAdsorbate/SilgelGrace125WaterSchawe.mo b/SorpLib/Media/AdsorbentAdsorbate/SilgelGrace125WaterSchawe.mo deleted file mode 100644 index 0f4dcb87d340ddf897fe3a01686f8c81fe180b8e..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/SilgelGrace125WaterSchawe.mo +++ /dev/null @@ -1,45 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate; -model SilgelGrace125WaterSchawe - "Silicagel Grace 125 / Water, published by Schawe (1999)" - extends SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin( - c_Sorbent=1000); - - final parameter Real[4] c={4.527805e-4,1.229005e5,-8.847167e4, - 6.034706e-7} "Coefficients for characteristic curve"; - -equation - W = SorpLib.Media.Functions.CharCurve1Arctan(A,c); - h_bond = -A + T*water.VLEAdditional.beta_l*W/ - SorpLib.Media.Functions.CharCurve1Arctan_dWdA(A,c); - - assert(A>20e3, "The characteristic curve is not valid in this range of adsorption potential A"); - assert(A<1570e3, "The characteristic curve is not valid in this range of adsorption potential A"); - - annotation (Documentation(info="<html> -<p> - This model provides the equilibrium data for the working pair Silica gel Grace 125 / Water as measured by Schawe (1999).<br> - The implementation is based on the Dubinin model, see <a href=\"modelica://SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin\">SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin</a>. -</p> -<h4>Main equations</h4> -<p> - see <a href=\"modelica://SorpLib.Media.Functions.CharCurve1Arctan\">SorpLib.Media.Functions.CharCurve1Arctan</a><br> - see <a href=\"modelica://SorpLib.Media.Functions.CharCurve1Arctan_dWdA\">SorpLib.Media.Functions.CharCurve1Arctan_dWdA</a> -</p> -<h4>References</h4> -<p> - <ul> - <li>Dubinin, M.M. Adsorption in micropores. J. Colloid Interface Sci., 1967, 23(4), 487-499.</li> - <li>Schawe, D. Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers. PhD Thesis. Stuttgart, 1999. </li> - </ul> -</p> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 17, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end SilgelGrace125WaterSchawe; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestAQSOAZ02WaterGoldsworthy.mo b/SorpLib/Media/AdsorbentAdsorbate/Testers/TestAQSOAZ02WaterGoldsworthy.mo deleted file mode 100644 index 7d367e575e3eab62fdd86c64bba55c8ed97a6601..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestAQSOAZ02WaterGoldsworthy.mo +++ /dev/null @@ -1,15 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate.Testers; -model TestAQSOAZ02WaterGoldsworthy - - SorpLib.Media.AdsorbentAdsorbate.AQSOAZ02WaterGoldsworthy - aqsoaZ02(x=x, T=T) - annotation (Placement(transformation(extent={{-10,-8},{10,12}}))); - - Real x(start=0.06); - Modelica.SIunits.Temperature T(start=273.15 + 200); - -equation - x = 0.05 + 0.01*time; - T = (273.15 + 60); - annotation (experiment(StopTime=20), __Dymola_experimentSetupOutput); -end TestAQSOAZ02WaterGoldsworthy; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestSilgelGrace123WaterSchawe.mo b/SorpLib/Media/AdsorbentAdsorbate/Testers/TestSilgelGrace123WaterSchawe.mo deleted file mode 100644 index 5ce398068674c850a2b9aa4a58668a85a72887e5..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestSilgelGrace123WaterSchawe.mo +++ /dev/null @@ -1,16 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate.Testers; -model TestSilgelGrace123WaterSchawe - - SorpLib.Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe - silgelGrace123Water_Schawe(x=x, T=T) - annotation (Placement(transformation(extent={{-10,-8},{10,12}}))); - - Real x; - Modelica.SIunits.Temperature T; - -equation - x = 0.05+time*0.0025; - T = 300; - - annotation (experiment(StopTime=100)); -end TestSilgelGrace123WaterSchawe; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestSilgelGrace125WaterNunez.mo b/SorpLib/Media/AdsorbentAdsorbate/Testers/TestSilgelGrace125WaterNunez.mo deleted file mode 100644 index ea8f37fa5eef32ffe9ade19c72156aa51a298903..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestSilgelGrace125WaterNunez.mo +++ /dev/null @@ -1,16 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate.Testers; -model TestSilgelGrace125WaterNunez - - SorpLib.Media.AdsorbentAdsorbate.SilgelGrace125WaterNunez - silgelGrace125WaterNunez(x=x, T=T) - annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); - - Real x; - Modelica.SIunits.Temperature T; - -equation - x = 0.01+time*0.0025; - T = 300; - - annotation (experiment(StopTime=100)); -end TestSilgelGrace125WaterNunez; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestSilgelGrace125WaterSchawe.mo b/SorpLib/Media/AdsorbentAdsorbate/Testers/TestSilgelGrace125WaterSchawe.mo deleted file mode 100644 index 62f2cbe6c8c78aab2683b452888ca2a4c4cd2b0c..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestSilgelGrace125WaterSchawe.mo +++ /dev/null @@ -1,16 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate.Testers; -model TestSilgelGrace125WaterSchawe - - SorpLib.Media.AdsorbentAdsorbate.SilgelGrace125WaterSchawe - silgelGrace125Water_Schawe(x=x, T=T) - annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); - - Real x; - Modelica.SIunits.Temperature T; - -equation - x = 0.01+time*0.0025; - T = 300; - - annotation (experiment(StopTime=100)); -end TestSilgelGrace125WaterSchawe; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestWorkingPairs_comp.mo b/SorpLib/Media/AdsorbentAdsorbate/Testers/TestWorkingPairs_comp.mo deleted file mode 100644 index b8d3ae85c0afa6c6153bbd7f4d6b7c82667a5523..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestWorkingPairs_comp.mo +++ /dev/null @@ -1,32 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate.Testers; -model TestWorkingPairs_comp "Test and compare multiple working pairs" - - SorpLib.Media.AdsorbentAdsorbate.SilgelGrace123WaterSchawe - silgelGrace123Water_Schawe(x=x, T=T) - annotation (Placement(transformation(extent={{56,58},{76,78}}))); - - SorpLib.Media.AdsorbentAdsorbate.SilgelGrace125WaterSchawe - silgelGrace125Water_Schawe(x=x, T=T) - annotation (Placement(transformation(extent={{14,58},{34,78}}))); - - SorpLib.Media.AdsorbentAdsorbate.SilgelGrace125WaterNunez - silgelGrace125WaterNunez(x=x, T=T) - annotation (Placement(transformation(extent={{-30,58},{-10,78}}))); - - SorpLib.Media.AdsorbentAdsorbate.Zeolite13XWaterNunez - zeolite13X(x=x, T=T) - annotation (Placement(transformation(extent={{-74,58},{-54,78}}))); - - SorpLib.Media.AdsorbentAdsorbate.AQSOAZ02WaterGoldsworthy - aqsoaZ02(x=x, T=T) - annotation (Placement(transformation(extent={{-74,24},{-54,44}}))); - - Real x; - Modelica.SIunits.Temperature T; - -equation - x = 0.03 + time*0.0025; - T = 300; - - annotation (experiment(StopTime=100)); -end TestWorkingPairs_comp; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestZeolite13XWaterNunez.mo b/SorpLib/Media/AdsorbentAdsorbate/Testers/TestZeolite13XWaterNunez.mo deleted file mode 100644 index 7e83f097e7f768f5870cc0e63b71e9fe35bbb303..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Testers/TestZeolite13XWaterNunez.mo +++ /dev/null @@ -1,14 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate.Testers; -model TestZeolite13XWaterNunez - - SorpLib.Media.AdsorbentAdsorbate.Zeolite13XWaterNunez - zeolite13X(x=x, T=T) - annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); - - Real x(start=0.06); - Modelica.SIunits.Temperature T(start=273.15 + 200); - -equation - x = 0.05 + 0.01*time; - T = (273.15 + 257)-8.5*time; -end TestZeolite13XWaterNunez; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Testers/package.mo b/SorpLib/Media/AdsorbentAdsorbate/Testers/package.mo deleted file mode 100644 index f883279d368c2a8db13e09715baefe079e18893a..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Testers/package.mo +++ /dev/null @@ -1,10 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - - - - - -end Testers; diff --git a/SorpLib/Media/AdsorbentAdsorbate/Testers/package.order b/SorpLib/Media/AdsorbentAdsorbate/Testers/package.order deleted file mode 100644 index e9816c726455736a1ed7188286dd0a9527312253..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Testers/package.order +++ /dev/null @@ -1,6 +0,0 @@ -TestSilgelGrace123WaterSchawe -TestSilgelGrace125WaterSchawe -TestSilgelGrace125WaterNunez -TestZeolite13XWaterNunez -TestAQSOAZ02WaterGoldsworthy -TestWorkingPairs_comp diff --git a/SorpLib/Media/AdsorbentAdsorbate/Zeolite13XWaterNunez.mo b/SorpLib/Media/AdsorbentAdsorbate/Zeolite13XWaterNunez.mo deleted file mode 100644 index 3df7580539dfd3f235a4b0d7e29d20310b24f3bd..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/Zeolite13XWaterNunez.mo +++ /dev/null @@ -1,46 +0,0 @@ -within SorpLib.Media.AdsorbentAdsorbate; -model Zeolite13XWaterNunez "Zeolite 13 X / Water, published by Nunez (2001)" - extends SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin( - c_Sorbent=1000); - - final parameter Real[4] cNom={-9.39e-20,4.279e-13,-5.968e-7,0.2974} - "Coefficients for nominator of characteristic curve"; - final parameter Real[4] cDenom={2.64e-16,5.361e-10,-1.4929e-3,1000} - "Coefficients for denominator of characteristic curve"; - -equation - W = SorpLib.Media.Functions.CharCurve2Polynomial(A,cNom,cDenom); - h_bond = -A + T*water.VLEAdditional.beta_l*W/ - SorpLib.Media.Functions.CharCurve2Polynomial_dWdA(A,cNom,cDenom); - - assert(A>18e3, "The characteristic curve is not valid in this range of adsorption potential A"); - assert(A<2000e3, "The characteristic curve is not valid in this range of adsorption potential A"); - - annotation (Documentation(info="<html> -<p> - This model provides the equilibrium data for the working pair zeolite 13 X / Water as measured by Núñez (2001).<br> - The implementation is based on the Dubinin model, see <a href=\"modelica://SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin\">SorpLib.Media.AdsorbentAdsorbate.Partial.PartialAdsorbentWaterDubinin</a>. -</p> -<h4>Main equations</h4> -<p> - see <a href=\"modelica://SorpLib.Media.Functions.CharCurve2Polynomial\">SorpLib.Media.Functions.CharCurve2Polynomial</a><br> - see <a href=\"modelica://SorpLib.Media.Functions.CharCurve2Polynomial_dWdA\">SorpLib.Media.Functions.CharCurve2Polynomial_dWdA</a> -</p> -<h4>References</h4> -<p> - <ul> - <li>Dubinin, M.M. Adsorption in micropores. J. Colloid Interface Sci., 1967, 23(4), 487-499.</li> - <li>Núñez, T. Charakterisierung und Bewertung von Adsorbentien für Wärmetransformationsanwendungen. PhD Thesis. Freiburg, 2001. </li> - </ul> -</p> -<h4>Author Information</h4> -<p> - <ul> - <li> - November 17, 2017, by Uwe Bau:<br> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> - </ul> -</p> -</html>")); -end Zeolite13XWaterNunez; diff --git a/SorpLib/Media/AdsorbentAdsorbate/package.mo b/SorpLib/Media/AdsorbentAdsorbate/package.mo deleted file mode 100644 index 6f3b9b8dbdc75b4acea4025ef0cf4e026583fe0f..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/package.mo +++ /dev/null @@ -1,11 +0,0 @@ -within SorpLib.Media; -package AdsorbentAdsorbate -extends SorpLib.Internals.ClassTypes.ModelPackage; - - - - - - - -end AdsorbentAdsorbate; diff --git a/SorpLib/Media/AdsorbentAdsorbate/package.order b/SorpLib/Media/AdsorbentAdsorbate/package.order deleted file mode 100644 index 86e5f6d24f0c8a927f0cfe2e69b06e4c594ff309..0000000000000000000000000000000000000000 --- a/SorpLib/Media/AdsorbentAdsorbate/package.order +++ /dev/null @@ -1,7 +0,0 @@ -SilgelGrace123WaterSchawe -SilgelGrace125WaterSchawe -SilgelGrace125WaterNunez -Zeolite13XWaterNunez -AQSOAZ02WaterGoldsworthy -Partial -Testers diff --git a/SorpLib/Media/Functions/CharCurve1Arctan.mo b/SorpLib/Media/Functions/CharCurve1Arctan.mo deleted file mode 100644 index 33cac6807864a09c2780c8312c3630b05fce2be5..0000000000000000000000000000000000000000 --- a/SorpLib/Media/Functions/CharCurve1Arctan.mo +++ /dev/null @@ -1,56 +0,0 @@ -within SorpLib.Media.Functions; -function CharCurve1Arctan - input Modelica.SIunits.SpecificEnergy A "Adsorption Potential"; - input Real c[4] "Coefficients for arctan function (see Info)"; - output Modelica.SIunits.SpecificVolume W "Specific volume of adsorbate"; - -algorithm - assert(A>0, "The adsorption potential A should be positive"); - - W := c[1]/Modelica.Constants.pi*(Modelica.Math.atan( - (A - c[2])/c[3]) + Modelica.Constants.pi/2) + c[4]; - - assert(W>0, "The specific volume W should be positive"); - - annotation (smoothOrder=2, inverse(A=CharCurve1Arctan_inverse(W,c)), - Documentation(info="<html> -<p> -This function describes characteristic curves based on an arctan function. -</p> -<h4>Main equations</h4> -<p> -The characteristic curve has the following basic equation: -<p align=\"center\" style=\"font-style:italic;\"> -W = c<sub>1</sub> / <code>π</code> [ arctan ((A-c<sub>2</sub>) / c<sub>3</sub>) + <code>π</code> / 2 ] + c<sub>4</sub> + , -</p> -<p> -where <i>c<sub>1</sub></i>,<i>c<sub>2</sub></i>,<i>c<sub>3</sub></i>,<i>c<sub>4</sub></i> are the fit parameters of the chracteristic curve. -</p> -<h4>Assumptions and limitations</h4> -<p> -Both the adsorption potential A and the specific volume of the adsorbate should be non-negative -</p> -<h4>Typical use and important parameters</h4> -<p> -The function is used to describe empirical equilibrium data of working pairs following the Dubinin model. -</p> -<h4>References</h4> -<p> -This type of characteristic curve is used in the following publications: -<ul> - <li> - Schawe, D. Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers. PhD Thesis. Stuttgart, 1999. - </li> -</ul> -</p> -<h4>Author Information</h4> -<p> -<ul> - <li> - November 17, 2017, by Uwe Bau:<br/> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> -</ul> -</p> -</html>")); -end CharCurve1Arctan; diff --git a/SorpLib/Media/Functions/CharCurve1Arctan_dWdA.mo b/SorpLib/Media/Functions/CharCurve1Arctan_dWdA.mo deleted file mode 100644 index 3771b1d580b28bb775aff05fbc23e91d940c74e0..0000000000000000000000000000000000000000 --- a/SorpLib/Media/Functions/CharCurve1Arctan_dWdA.mo +++ /dev/null @@ -1,34 +0,0 @@ -within SorpLib.Media.Functions; -function CharCurve1Arctan_dWdA - input Modelica.SIunits.SpecificEnergy A "Adsorption Potential"; - input Real c[4] "Coefficients for arctan function (see Info)"; - output Real dWdA(unit="m3/J") "Derivative of specific volume of adsorbate W wrt to adsorption potential A"; - -algorithm - assert(A>0, "The adsorption potential A should be positive"); - - dWdA := c[1]/(Modelica.Constants.pi*c[3]*(1 + (A - - c[2])^2/c[3]^2)); - - annotation (smoothOrder=2, - Documentation(info="<html> -<p>This function describes the derivative of the characteristic curve with respect to the adsorption potential <i>A</i>: <i>dW/dA</i> </p> -<h4>Main equations</h4> -<p>The derivative with respect to the adsorption potential has the following basic equation: </p> -<p align=\"center\"><i>dW/dA = c<sub>1</sub> / ( <code>π</code> * c<sub>3</sub> ( 1 + (A-c<sub>2</sub>)<sup>2</sup> / c<sub>3</sub><sup>2</sup> )) </i></p> -<p>where <i>c<sub>1</i></sub>,<i>c<sub>2</i></sub>,<i>c<sub>3</i></sub>,<i>c<sub>4</i></sub> are the fit parameters of the chracteristic curve. </p> -<h4>Assumptions and limitations</h4> -<p>Both the adsorption potential A and the specific volume of the adsorbate should be non-negative </p> -<h4>Typical use and important parameters</h4> -<p>The function is used to describe empirical equilibrium data of working pairs following the Dubinin model. </p> -<h4>References</h4> -<p>This type of characteristic curve is used in the following publications: </p> -<ul> -<li>Schawe, D. Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers. PhD Thesis. Stuttgart, 1999. </li> -</ul> -<h4>Author Information</h4> -<ul> -<li>November 17, 2017, by Uwe Bau:<br>Tidy up implementation and enhance documentation for publication of library.<br> </li> -</ul> -</html>")); -end CharCurve1Arctan_dWdA; diff --git a/SorpLib/Media/Functions/CharCurve1Arctan_inverse.mo b/SorpLib/Media/Functions/CharCurve1Arctan_inverse.mo deleted file mode 100644 index 28821673b60653e927ee3ae2b3e3fabbab279d5a..0000000000000000000000000000000000000000 --- a/SorpLib/Media/Functions/CharCurve1Arctan_inverse.mo +++ /dev/null @@ -1,56 +0,0 @@ -within SorpLib.Media.Functions; -function CharCurve1Arctan_inverse - input Modelica.SIunits.SpecificVolume W "Specific volume of adsorbate"; - input Real c[4] "Coefficients for arctan function (see Info)"; - - output Modelica.SIunits.SpecificEnergy A "Adsorption Potential"; - -algorithm - assert(W>0, "The specific volume W should be positive"); - - A := c[3]*Modelica.Math.tan((W-c[4])/c[1]*Modelica.Constants.pi-Modelica.Constants.pi/2)+c[2]; - - assert(A>0, "The adsorption potential A should be positive"); - - annotation (smoothOrder=2, inverse(W=CharCurve1Arctan(A,c)), - Documentation(info="<html> -<p> -This function implements the inverse function of the arctan characteristic curves. -</p> -<h4>Main equations</h4> -<p> -The characteristic curve has the following basic equation: -<p align=\"center\" style=\"font-style:italic;\"> -A = c<sub>3</sub> tan (( W - c<sub>4</sub> ) * <code>π</code> / c<sub>1</sub> - <code>π</code> / 2 ) + c<sub>2</sub> , -</p> -<p> -where <i>c<sub>1</sub></i>,<i>c<sub>2</sub></i>,<i>c<sub>3</sub></i>,<i>c<sub>4</sub></i> are the fit parameters of the chracteristic curve. -</p> -<h4>Assumptions and limitations</h4> -<p> -Both the adsorption potential A and the specific volume of the adsorbate should be non-negative -</p> -<h4>Typical use and important parameters</h4> -<p> -The function is used to describe empirical equilibrium data of working pairs following the Dubinin model. -</p> -<h4>References</h4> -<p> -This type of characteristic curve is used in the following publications: -<ul> - <li> - Schawe, D. Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers. PhD Thesis. Stuttgart, 1999. - </li> -</ul> -</p> -<h4>Author Information</h4> -<p> -<ul> - <li> - November 17, 2017, by Uwe Bau:<br/> - Tidy up implementation and enhance documentation for publication of library.<br> - </li> -</ul> -</p> -</html>")); -end CharCurve1Arctan_inverse; diff --git a/SorpLib/Media/Functions/CharCurve2Polynomial.mo b/SorpLib/Media/Functions/CharCurve2Polynomial.mo deleted file mode 100644 index 7227ce2a596a2128bc2af64a0ab3661d913ce2e6..0000000000000000000000000000000000000000 --- a/SorpLib/Media/Functions/CharCurve2Polynomial.mo +++ /dev/null @@ -1,53 +0,0 @@ -within SorpLib.Media.Functions; -function CharCurve2Polynomial - input Modelica.SIunits.SpecificEnergy A "Adsorption Potential"; - input Real c_u[:] "Coefficients for nominator (see Info)"; - input Real c_v[:] "Coefficients for denominator (see Info)"; - output Modelica.SIunits.SpecificVolume W "Specific volume of adsorbate"; - -protected - Integer n_u = size(c_u,1); - Integer n_v = size(c_v,1); - Real u "Nominator"; - Real v "Denominator"; - -algorithm - assert(A>0, "The adsorption potential A should be positive"); - - u := c_u[1]; - for i in 2:n_u loop - u := u*A + c_u[i]; - end for; - - v := c_v[1]; - for i in 2:n_v loop - v := v*A + c_v[i]; - end for; - - W := u/v; - - assert(W>0, "The specific volume W should be positive"); - - annotation (smoothOrder=2, - Documentation(info="<html> -<p>This function describes characteristic curves based on polynomial functions. </p> -<h4>Main equations</h4> -<p>The characteristic curve has the following basic equation: </p> -<p align=\"center\"><i>W = <code>∑</code><sub>i=1</sub><sup>N</sup> c<sub>nom,i</sub> A<sup>N-i</sup> / -<code>∑</code><sub>j=1</sub><sup>N</sup> c<sub>denom,j</sub> A<sup>N-j</sup>, </i></p> -<p>where <i>c<sub>nom,i</i></sub> and <i>c<sub>denom,i</i></sub> are the fit parameters of the chracteristic curve. </p> -<h4>Assumptions and limitations</h4> -<p>Both the adsorption potential A and the specific volume of the adsorbate should be non-negative </p> -<h4>Typical use and important parameters</h4> -<p>The function is used to describe empirical equilibrium data of working pairs following the Dubinin model. </p> -<h4>References</h4> -<p>This type of characteristic curve is used in the following publications: </p> -<ul> -<li>Núñez, T. Charakterisierung und Bewertung von Adsorbentien für Wärmetransformationsanwendungen. PhD Thesis. Freiburg, 2001. </li> -</ul> -<h4>Author Information</h4> -<ul> -<li>November 17, 2017, by Uwe Bau:<br>Tidy up implementation and enhance documentation for publication of library.<br></li> -</ul> -</html>")); -end CharCurve2Polynomial; diff --git a/SorpLib/Media/Functions/CharCurve2Polynomial_dWdA.mo b/SorpLib/Media/Functions/CharCurve2Polynomial_dWdA.mo deleted file mode 100644 index 1ae933da4de387202215935fbc171bc9b2ed39ca..0000000000000000000000000000000000000000 --- a/SorpLib/Media/Functions/CharCurve2Polynomial_dWdA.mo +++ /dev/null @@ -1,71 +0,0 @@ -within SorpLib.Media.Functions; -function CharCurve2Polynomial_dWdA - input Modelica.SIunits.SpecificEnergy A "Adsorption Potential"; - input Real c_u[:] "Coefficients for nominator (see Info)"; - input Real c_v[:] "Coefficients for denominator (see Info)"; - output Real dWdA(unit="m3/J") - "Derivative of specific volume of adsorbate W wrt to adsorption potential A"; - - -protected - Integer n_u=size(c_u, 1); - Integer n_v=size(c_v, 1); - Real u "Nominator"; - Real v "Denominator"; - Real u_der "Derivate of nominator wrt A"; - Real v_der "Derivate of denominator wrt A"; - - -algorithm - assert(A > 0, "The adsorption potential A should be positive"); - - u := c_u[1]; - for i in 2:n_u loop - u := u*A + c_u[i]; - end for; - - v := c_v[1]; - for j in 2:n_v loop - v := v*A + c_v[j]; - end for; - - - if n_u > 1 then - u_der := (n_u-1)*c_u[1]; - for i in 2:n_u - 1 loop - u_der := u_der*A + (n_u-i)*c_u[i]; - end for; - else - u_der := 0; - end if; - - if n_v > 1 then - v_der := (n_v-1)*c_v[1]; - for j in 2:n_v - 1 loop - v_der := v_der*A + (n_v-j)*c_v[j]; - end for; - else - v_der := 0; - end if; - - dWdA := ((u_der*v) - (u*v_der))/(v*v); - - annotation (smoothOrder=2, Documentation(info="<html> -<p>This function describes the derivative of the characteristic curve with respect to the adsorption potential A: dW/dA </p> -<h4>Main equations</h4> -<p>The derivative with respect to the adsorption potential for a rational polynomial function is determined by the quotient rule</p> -<h4>Assumptions and limitations</h4> -<p>Both the adsorption potential A and the specific volume of the adsorbate should be non-negative </p> -<h4>Typical use and important parameters</h4> -<p>The function is used to describe empirical equilibrium data of working pairs following the Dubinin model. </p> -<h4>References</h4> -<p>This type of characteristic curve is used in the following publications: </p> -<ul> -<li>Núñez, T. Charakterisierung und Bewertung von Adsorbentien für Wärmetransformationsanwendungen. PhD Thesis. Freiburg, 2001. </li> -</ul> -<h4>Author Information</h4> -<ul> -<li>November 17, 2017, by Uwe Bau:<br>Tidy up implementation and enhance documentation for publication of library.<br></li> -</ul> -</html>")); -end CharCurve2Polynomial_dWdA; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialMulti_h_ads.mo b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialMulti_h_ads.mo new file mode 100644 index 0000000000000000000000000000000000000000..9563530f92eaddf1386415d8a4636f2f1eb24aa1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialMulti_h_ads.mo @@ -0,0 +1,87 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses; +partial function PartialMulti_h_ads + "Base function for functions calculating the sorption enthalpy for multi components" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass[:] M_i + "Molar masses of components" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerUptakeByPressure[size(M_i,1)] dx_adsorpt_dp + "Partial derivatives of the uptakes w.r.t. pressure at constant molar fractions + and temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByMolarFraction[size(M_i,1),size(M_i,1)-1] dx_adsorpt_dy_i + "Partial derivatives of the uptakes w.r.t. the molar fractions of independent + gas phase components at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByTemperature[size(M_i,1)] dx_adsorpt_dT + "Partial derivatives of the uptakes w.r.t. temperature at contant pressure and + molar fractions" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_threshold_min = 100*Modelica.Constants.eps + "Threshold for partial pressures of all components: If a partial pressure is + below the threshold, its value is set to the threshold" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Modelica.Units.SI.MoleFraction y_i_threshold_min = 100*Modelica.Constants.eps + "Threshold for independent mole fractions of the adsorptive phase: If a independent + mole fraction is below the threshold, its value is set to the threshold" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.MolarEnthalpy[size(M_i,1)] h_ads(each displayUnit="kJ/mol") + "Molar adsorption enthalpies of components" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate the +sorption enthalpies for multi components. +<br/><br/> +This partial function defines the molar masses of the components <i>M_i</i>, the +pressure <i>p_adsorpt</i>, the independent mole fractions in the adsorptive phase +<i>y_i</i>, the temperature <i>T_adsorpt</i>, the partial derivatives of the +uptakes with respect to the pressure at constant molar fractions and temperature +<i>dx_adsorpt_dp</i>, the partial derivatives of the uptakes with respect to the +independent mole fractions in the adsorptive phase at constant pressure and +temperature <i>dx_adsorpt_dy_i</i>, and the partial derivatives of the uptakes with +respect to the temperature at constant pressure and molar fractions <i>dx_adsorpt_dT</i> +as inputs. Optional inputs regarding numerics are the thresholds <i>p_threshold_min</i> +and <i>y_i_threshold_min</i>, describing the lower limits of the total pressure +and independent molar fractions of the adsorptive phase. The sorption enthalpies +<i>h_ads</i> are defined as outputs. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialMulti_h_ads; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialPure_dh_ads_dT.mo b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialPure_dh_ads_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..8bfae3e2a3d9ca5eef5d5072a3fa9ac33c244351 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialPure_dh_ads_dT.mo @@ -0,0 +1,48 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses; +partial function PartialPure_dh_ads_dT + "Base function for functions calculating the partial derivative of the sorption enthalpy w.r.t. temperature at constant pressure for pure components" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.MolarHeatCapacity dh_ads_dT(displayUnit="kJ/(mol.K)") + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate the +partial derivative of the sorption enthalpy with respect to the temperature at +consstant pressure for pure components. +<br/><br/> +This partial function defines the temperature <i>T_adsorpt</i> as input and the +partial derivative of the sorption enthalpy fwith respect to the temperature at +constant pressure <i>dh_ads_dT</i> as output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPure_dh_ads_dT; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialPure_dh_ads_dp.mo b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialPure_dh_ads_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..664edce0513e6a9a69843ff7aed30a0bbf1610cf --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialPure_dh_ads_dp.mo @@ -0,0 +1,48 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses; +partial function PartialPure_dh_ads_dp + "Base function for functions calculating the partial derivative of the sorption enthalpy w.r.t. pressure at constant temperature for pure components" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate the +partial derivative of the sorption enthalpy with respect to the pressure at +consstant temperature for pure components. +<br/><br/> +This partial function defines the temperature <i>T_adsorpt</i> as input and the +partial derivative of the sorption enthalpy fwith respect to the pressure at +constant temperature <i>dh_ads_dp</i> as output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPure_dh_ads_dp; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialPure_h_ads.mo b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialPure_h_ads.mo new file mode 100644 index 0000000000000000000000000000000000000000..b4e9f8bd6fe3af93decaea3f892d46a9e33d7163 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialPure_h_ads.mo @@ -0,0 +1,45 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses; +partial function PartialPure_h_ads + "Base function for functions calculating the sorption enthalpy for pure components" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.MolarEnthalpy h_ads(displayUnit="kJ/mol") + "Molar adsorption enthalpy" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate the +sorption enthalpy for pure components. +<br/><br/> +This partial function defines the temperature <i>T_adsorpt</i> as input and the +sorption enthalpy <i>h_ads</i> as output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPure_h_ads; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialTestMulti.mo b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialTestMulti.mo new file mode 100644 index 0000000000000000000000000000000000000000..930beed5705e591805ed09a261bdc46b929fd0ce --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialTestMulti.mo @@ -0,0 +1,126 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses; +partial model PartialTestMulti + "Base model for testers of sorption enthalpy models describing multi-component adsorption" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Integer no_components = 2 + "Number of components of the isotherm model" + annotation (Dialog(tab="Isotherm model", group="General"), + Evaluate=true, + HideResult=true); + parameter Integer no_coefficients = 3 + "Number of coefficients of the isotherm model (i.e., highest number among + different components)" + annotation (Dialog(tab="Isotherm model", group="General"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.MolarMass[no_components] M_i = {0.018, 0.044} + "Molar masses of the components" + annotation (Dialog(tab="Isotherm model", group="General"), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.Pressure p_adsorpt_start = 1 + "Start value of equilibrium pressure" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.MoleFraction[no_components-1] y_i_start={1e-2} + "Start values independent mole fractions" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Temperature T_adsorpt_start = 278.15 + "Start value of equilibrium temperature" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + + parameter Modelica.Units.SI.Pressure p_threshold_min = 1e-6 + "Threshold for partial pressures of all components: If a partial pressure is + below the threshold, its value is set to the threshold" + annotation (Dialog(tab="Numerics", group="Limiter"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.MoleFraction y_i_threshold_min = 1e-6 + "Threshold for independent mole fractions of the adsorptive phase: If a independent + mole fraction is below the threshold, its value is set to the threshold" + annotation (Dialog(tab="Numerics", group="Limiter"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_adsorpt(start=p_adsorpt_start, fixed=true) + "Pressure"; + Modelica.Units.SI.MoleFraction[no_components-1] y_i(start=y_i_start, each fixed=true) + "Independent mole fractions"; + Modelica.Units.SI.Temperature T_adsorpt(start=T_adsorpt_start, fixed=true) + "Temperature"; + + SorpLib.Units.Uptake[no_components] x_adsorpt + "Uptake"; + SorpLib.Units.DerUptakeByPressure[no_components] dx_adsorpt_dp + "Partial derivative of uptakes w.r.t. pressure at constant mole fractions and + temperature"; + SorpLib.Units.DerUptakeByMolarFraction[no_components,no_components-1] dx_adsorpt_dy_i + "Partial derivatives of the uptakes w.r.t. the molar fractions of independent + components of adsorptive phase at constant pressure and temperature"; + SorpLib.Units.DerUptakeByTemperature[no_components] dx_adsorpt_dT + "Partial derivative of uptakes w.r.t. temperature at constant pressure and + mole fractions"; + + Modelica.Units.SI.MolarEnthalpy[no_components] h_ads(each displayUnit="kJ/mol") + "Molar adsorption enthalpy"; + +protected + Real[no_coefficients,no_components] c + "Coefficients of isotherm model"; + Real[no_coefficients,no_components] dc_dT + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + +equation + // + // Calculate sorptions enthalies + // + h_ads = SorpLib.Media.Functions.SorptionEnthalpies.MultiComponents.h_ads_clausiusClapeyron( + M_i=M_i, + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dy_i=dx_adsorpt_dy_i, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar adsorption enthalpy"; + + // + // Annotations + // + annotation ( + Icon(coordinateSystem(preserveAspectRatio=false)), + Diagram(coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the basic model for all testers of sorption enthalpies for +multi components. This partial model defines all some relevant parameters and +variables that are required for most sorption enthalpy models. +<br/><br/> +Models that inherit properties from this partial model have to specify the +coefficients of the isotherm model (i.e., <i>c</i>) and their partial derivatives +with respect to temperature (i.e., <i>dc_dT</i>). Additionally, equations for the +following variables must be implemted: <i>p_adsorpt</i>, <i>y_i</i>, <i>T_adsorpt</i>, +<i>x_adsorpt</i>, <i>dx_adsorpt_dp</i>, <i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialTestMulti; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialTestPure.mo b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialTestPure.mo new file mode 100644 index 0000000000000000000000000000000000000000..0b6b7c5485e9ef284040d1914570846a7745ee6f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/PartialTestPure.mo @@ -0,0 +1,304 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses; +partial model PartialTestPure + "Base model for testers of sorption enthalpy models describing pure component adsorption" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_ph + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Medium"), + choicesAllMatching = true); + + parameter Integer no_coefficients = 6 + "Number of coefficients of selected isotherm model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Pressure p_adsorpt_start = 700 + "Start value of equilibrium pressure" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Temperature T_adsorpt_start = 278.15 + "Start value of equilibrium temperature" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.MolarMass M_adsorptive = 0.018 + "Molar mass of adsorptive" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference used to calculated partial derivatives numerically" + annotation (Dialog(tab="General",group="Numerics"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculated partial derivatives numerically" + annotation (Dialog(tab="General",group="Numerics"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Units.Uptake dx = 1e-3 + "Uptake difference used to calculated partial derivatives numerically" + annotation (Dialog(tab="General",group="Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_adsorpt(start=p_adsorpt_start, fixed=true) + "Pressure"; + Modelica.Units.SI.Temperature T_adsorpt(start=T_adsorpt_start, fixed=true) + "Temperature"; + SorpLib.Units.Uptake x_adsorpt + "Uptake"; + + Medium.ThermodynamicState state_adsorptive_pT + "State properties of adsorptive at p_adsorpt and T_adsorpt"; + Medium.ThermodynamicState state_bubble_T + "State properties of bubble point at T_adsorpt"; + + Modelica.Units.SI.MolarEnthalpy h_ads(displayUnit="kJ/mol") + "Molar adsorption enthalpy"; + + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T_num + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at + constant temperature calculated numerically"; + + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p(displayUnit="kJ/(mol.K)") + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at + constant pressure"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p_num(displayUnit="kJ/(mol.K)") + "Partial derivative of molar adsorption enthalpy w.r.t. temperature + calculated numerically at constant pressure"; + + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_x(displayUnit="kJ/(mol.K)") + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at + constant uptake"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_x_num(displayUnit="kJ/(mol.K)") + "Partial derivative of molar adsorption enthalpy w.r.t. temperature + calculated numerically at constant uptake"; + + SorpLib.Units.DerMolarEnthalpyByUptake dh_ads_dx_T + "Partial derivative of molar adsorption enthalpy w.r.t. uptake at + constant temperature"; + SorpLib.Units.DerMolarEnthalpyByUptake dh_ads_dx_T_num + "Partial derivative of molar adsorption enthalpy w.r.t. uptake at + constant temperature calculated numerically"; + + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_x + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at + constant uptake"; + SorpLib.Units.DerMolarEnthalpyByUptake dh_ads_dx_p + "Partial derivative of molar adsorption enthalpy w.r.t. uptake at + constant pressure"; + +protected + Real c[no_coefficients] + "Coefficients of the isotherm model"; + Real c_pdT[no_coefficients] + "Coefficients of the isotherm model: T + dT"; + Real c_mdT[no_coefficients] + "Coefficients of the isotherm model: T - dT"; + + Real dc_dT[no_coefficients] + "Partial derivative of coefficients of the isotherm model w.r.t. temperature"; + Real dc_dT_pdT[no_coefficients] + "Partial derivative of coefficients of the isotherm model w.r.t. temperature: + T + dT"; + Real dc_dT_mdT[no_coefficients] + "Partial derivative of coefficients of the isotherm model w.r.t. temperature: + T - dT"; + + Real ddc_dT_dT[no_coefficients] + "Second-order partial derivative of coefficients of the isotherm model w.r.t. + temperature"; + + Medium.SaturationProperties sat_T + "Saturated state properties at T_adsorpt"; + Medium.SaturationProperties sat_T_pdT + "Saturated state properties at T_adsorpt: T + dT"; + Medium.SaturationProperties sat_T_mdT + "Saturated state properties at T_adsorpt: T - dT"; + + Medium.ThermodynamicState state_adsorptive_pT_pdp + "State properties of adsorptive at p_adsorpt and T_adsorpt: p + dp"; + Medium.ThermodynamicState state_adsorptive_pT_mdp + "State properties of adsorptive at p_adsorpt and T_adsorpt: p - dp"; + Medium.ThermodynamicState state_adsorptive_pT_pdT + "State properties of adsorptive at p_adsorpt and T_adsorpt: T + dT"; + Medium.ThermodynamicState state_adsorptive_pT_mdT + "State properties of adsorptive at p_adsorpt and T_adsorpt: T - dT"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant prssure"; + + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at contant + temperature"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at contant + pressure"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + Modelica.Units.SI.MolarEnthalpy h_ads_pdp_T(displayUnit="kJ/mol") + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: p + dp"; + Modelica.Units.SI.MolarEnthalpy h_ads_mdp_T(displayUnit="kJ/mol") + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: p - dp"; + + Modelica.Units.SI.MolarEnthalpy h_ads_pdT_p(displayUnit="kJ/mol") + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: T + dT"; + Modelica.Units.SI.MolarEnthalpy h_ads_mdT_p(displayUnit="kJ/mol") + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: T - dT"; + + Modelica.Units.SI.MolarEnthalpy h_ads_pdT_x(displayUnit="kJ/mol") + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt, T+dT) and T_adsorpt: T + dT"; + Modelica.Units.SI.MolarEnthalpy h_ads_mdT_x(displayUnit="kJ/mol") + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt, T-dT) and T_adsorpt: T - dT"; + + Modelica.Units.SI.MolarEnthalpy h_ads_pdx_T(displayUnit="kJ/mol") + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt+dx) and T_adsorpt"; + Modelica.Units.SI.MolarEnthalpy h_ads_mdx_T(displayUnit="kJ/mol") + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt-dx) and T_adsorpt"; + +equation + // + // Calculation of state properties + // + sat_T = Medium.setSat_T(T=T_adsorpt) + "Saturated state properties at T_adsorpt"; + sat_T_pdT = Medium.setSat_T(T=T_adsorpt+dT) + "Saturated state properties at T_adsorpt: T + dT"; + sat_T_mdT = Medium.setSat_T(T=T_adsorpt-dT) + "Saturated state properties at T_adsorpt: T - dT"; + + state_adsorptive_pT = Medium.setState_pTX( + p=p_adsorpt, + T=T_adsorpt) + "State properties of adsorptive at p_adsorpt and T_adsorpt"; + state_adsorptive_pT_pdp = Medium.setState_pTX( + p=p_adsorpt+dp, + T=T_adsorpt) + "State properties of adsorptive at p_adsorpt and T_adsorpt: p + dp"; + state_adsorptive_pT_mdp = Medium.setState_pTX( + p=p_adsorpt-dp, + T=T_adsorpt) + "State properties of adsorptive at p_adsorpt and T_adsorpt: p - dp"; + state_adsorptive_pT_pdT = Medium.setState_pTX( + p=p_adsorpt, + T=T_adsorpt+dT) + "State properties of adsorptive at p_adsorpt and T_adsorpt: T + dT"; + state_adsorptive_pT_mdT = Medium.setState_pTX( + p=p_adsorpt, + T=T_adsorpt-dT) + "State properties of adsorptive at p_adsorpt and T_adsorpt: T - dT"; + + state_bubble_T = Medium.setBubbleState(sat=sat_T) + "State properties of bubble point at T_adsorpt"; + + // + // Calculate properties + // + dh_ads_dT_x = dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at + constant uptake"; + dh_ads_dx_T = dh_ads_dp_T / dx_adsorpt_dp + "Partial derivative of molar adsorption enthalpy w.r.t. uptake at + constant temperature"; + + dh_ads_dp_x = dh_ads_dp_T - dh_ads_dT_p * dx_adsorpt_dp / dx_adsorpt_dT + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at + constant uptake"; + dh_ads_dx_p = dh_ads_dT_p / dx_adsorpt_dT + "Partial derivative of molar adsorption enthalpy w.r.t. uptake at + constant pressure"; + + // + // Calculate nuermical derivatives + // + dh_ads_dp_T_num = (h_ads_pdp_T - h_ads_mdp_T) / (2*dp) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature calculated numerically"; + dh_ads_dT_p_num = (h_ads_pdT_p - h_ads_mdT_p) / (2*dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure calculated numerically"; + dh_ads_dT_x_num = (h_ads_pdT_x - h_ads_mdT_x) / (2*dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake calculated numerically"; + dh_ads_dx_T_num = (h_ads_pdx_T - h_ads_mdx_T) / (2*dx) + "Partial derivative of molar adsorption enthalpy w.r.t. uptake at constant + temperature calculated numerically"; + + // + // Definition of assertions: Check numerical implementations + // + assert(abs(dh_ads_dp_T-dh_ads_dp_T_num) < 1e-6, + "Partial derivative of h_ads w.r.t. pressure at constant temperature is not " + + "valied: Deviation (|" + + String(abs(dh_ads_dp_T-dh_ads_dp_T_num)) + + "|) is greater than 1e-6 J/mol/Pa!", + level = AssertionLevel.warning); + assert(abs(dh_ads_dT_p-dh_ads_dT_p_num) < 1e-6, + "Partial derivative of h_ads w.r.t. temperature at constant pressure is not " + + "valied: Deviation (|" + + String(abs(dh_ads_dT_p-dh_ads_dT_p_num)) + + "|) is greater than 1e-6 J/mol/K!", + level = AssertionLevel.warning); + assert(abs(dh_ads_dT_x-dh_ads_dT_x_num) < 1e-6, + "Partial derivative of h_ads w.r.t. temperature at constant uptake is not " + + "valied: Deviation (|" + + String(abs(dh_ads_dT_x-dh_ads_dT_x_num)) + + "|) is greater than 1e-6 J/mol/K!", + level = AssertionLevel.warning); + assert(abs(dh_ads_dx_T-dh_ads_dx_T_num) < 1e-6, + "Partial derivative of h_ads w.r.t. uptake at constant temperature is not " + + "valied: Deviation (|" + + String(abs(dh_ads_dx_T-dh_ads_dx_T_num)) + + "|) is greater than 1e-6 J.kg/mol/kg!", + level = AssertionLevel.warning); + + // + // Annotations + // + annotation ( + Icon(coordinateSystem(preserveAspectRatio=false)), + Diagram(coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the basic model for all testers of sorption enthalpies for +pure components. This partial model defines all some relevant parameters and +variables that are required for most sorption enthalpy models. +<br/><br/> +Models that inherit properties from this partial model have to specify the +<i>medium</i> and test setup. Besides, the coefficients of the isotherm model +(i.e., <i>c</i>, <i>c_pdT</i>, and <i>c_mdT</i>) and their partial derivatives +with respect to temperature (i.e., <i>dc_dT</i>, <i>dc_dT_pdT</i>, <i>dc_dT_mdT</i>, +and <i>ddc_dT_dT</i>) have to be implemented. Additionally, equations for the +following variables must be implemted: <i>p_adsorpt</i>, <i>T_adsorpt</i>, +<i>x_adsorpt</i>, <i>dx_adsorpt_dp</i>, <i>dx_adsorpt_dT</i>, <i>ddx_adsorpt_dp_dp</i>, +<i>ddx_adsorpt_dT_dT</i>, <i>ddx_adsorpt_dp_dT</i>, <i>h_ads</i>, <i>dh_ads_dp_T</i>, +<i>dh_ads_dT_p</i>, <i>h_ads_pdp_T</i>, <i>h_ads_mdp_T</i>, <i>h_ads_pdT_p</i>, +<i>h_ads_mdT_p</i>, <i>h_ads_pdT_x</i>, <i>h_ads_mdT_x</i>, <i>h_ads_pdx_T</i>, +and <i>h_ads_mdx_T</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialTestPure; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/package.mo b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2ca64390a1e2b64f621c5489423df9093865183e --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.Functions.SorptionEnthalpies; +package BasesClasses "Base classes used to build new functions calculating sorption enthalpies" + extends Modelica.Icons.BasesPackage; + +annotation (Documentation(revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This package contains partial basic functions and models. These partial functions +and models contain fundamental definitions of functions calculating sorption enthalpies +for pure and multi-component adsorption. The content of this package is only of +interest when adding new functions to the library. +</p> +</html>")); +end BasesClasses; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/package.order b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..7349d12f4d53b54bdcf8458e5aafdfda8afd5398 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/BasesClasses/package.order @@ -0,0 +1,6 @@ +PartialPure_h_ads +PartialPure_dh_ads_dp +PartialPure_dh_ads_dT +PartialMulti_h_ads +PartialTestPure +PartialTestMulti diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/Test_h_ads_clausiusClapeyron_binary.mo b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/Test_h_ads_clausiusClapeyron_binary.mo new file mode 100644 index 0000000000000000000000000000000000000000..7adab1375b5a8c7ecceb444cd881e79f2e1f7121 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/Test_h_ads_clausiusClapeyron_binary.mo @@ -0,0 +1,156 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.MultiComponents.Testers; +model Test_h_ads_clausiusClapeyron_binary + "Tester for the functions 'h_ads_clausiusClapeyron' and 'h_ads_binary_clausiusClapeyron'" + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialTestMulti; + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] x_ref = {0.32, 0.22} + "Saturation uptake at reference temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Real[no_components] chi(each unit="1") = {0, 0.1} + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Real[no_components] b_ref(each unit="1/Pa") = {1.075e-4, 1.075e-4} + "Sips coefficient at reference temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Real[no_components] Q(each unit="J/mol") = {28.752e3, 28.752e3} + "Parameter describing the change of the Sips coefficient with temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Real[no_components] n_ref(each unit="1") = {2.312, 2.812} + "Sips exponent at reference temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Real[no_components] alpha(each unit="1") = {0.5559, 0.5559} + "Parameter describing the change of the Sips exponent with temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Modelica.Units.SI.Temperature[no_components] T_ref = {283, 283} + "Reference temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.MolarEnthalpy[no_components] h_ads_binary(each displayUnit="kJ/mol") + "Molar adsorption enthalpy calculated via binary approach"; + +equation + // + // Definition of derivatives + // + der(p_adsorpt) = 100000/20 + "Predecsriped slope of p_adsorpt to demonstrate the isotherm model"; + der(y_i) = {0.98/20} + "Predecsriped slope of y_i to demonstrate the isotherm model"; + der(T_adsorpt) = 90/20 + "Predecsriped slope of T_adsorpt to demonstrate the isotherm model"; + + // + // Calculate coefficients of the isotherm model + // + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - T_adsorpt/T_ref[ind_comp])) + "Coefficients of isotherm model"; + c[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/T_adsorpt - 1)) + "Coefficients of isotherm model"; + c[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/T_adsorpt)) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -chi[ind_comp]/T_ref[ind_comp] * c[1,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = -Q[ind_comp]/Modelica.Constants.R/T_adsorpt^2 * c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[3,ind_comp] = -T_ref[ind_comp]*alpha[ind_comp]/T_adsorpt^2 / + (1/n_ref[ind_comp] + alpha[ind_comp] * (1 - T_ref[ind_comp]/T_adsorpt))^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + end for; + + // + // Calculate properties + // + x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.x_pyT( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Uptakes"; + + dx_adsorpt_dp = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.dx_dp( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Partial derivative of uptakes w.r.t. pressure at constant mole fractions and + temperature"; + + dx_adsorpt_dy_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.dx_dy( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Partial derivatives of the uptakes w.r.t. the molar fractions of independent + components of adsorptive phase at constant pressure and temperature"; + + dx_adsorpt_dT = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.dx_dT( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + p_threshold_min=p_threshold_min) + "Partial derivative of uptakes w.r.t. temperature at constant pressure and + mole fractions"; + + h_ads_binary = SorpLib.Media.Functions.SorptionEnthalpies.MultiComponents.h_ads_binary_clausiusClapeyron( + M_i=M_i, + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dy_i=dx_adsorpt_dy_i, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar adsorption enthalpy calculated via binary approach"; + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'h_ads_ClausiusClapeyron_binary.' +<br/><br/> +To see the function behavior, plot the variables <i>h_ads_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_h_ads_clausiusClapeyron_binary; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/Test_h_ads_clausiusClapeyron_ternary.mo b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/Test_h_ads_clausiusClapeyron_ternary.mo new file mode 100644 index 0000000000000000000000000000000000000000..8812d4b3d70b36b05b0e6c95fb0f81082e0825fa --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/Test_h_ads_clausiusClapeyron_ternary.mo @@ -0,0 +1,159 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.MultiComponents.Testers; +model Test_h_ads_clausiusClapeyron_ternary + "Tester for the functions 'h_ads_clausiusClapeyron' and 'h_ads_ternary_clausiusClapeyron'" + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialTestMulti( + final no_components = 3, + final M_i={0.018,0.044,0.035}, + final y_i_start={0.01,0.01}); + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] x_ref = {0.32, 0.22, 0.11} + "Saturation uptake at reference temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Real[no_components] chi(each unit="1") = {0, 0.1, 0.2} + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Real[no_components] b_ref(each unit="1/Pa") = {1.075e-4, 1.075e-4, 1.075e-4} + "Sips coefficient at reference temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Real[no_components] Q(each unit="J/mol") = {28.752e3, 28.752e3, 28.752e3} + "Parameter describing the change of the Sips coefficient with temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Real[no_components] n_ref(each unit="1") = {2.312, 2.812, 2.812} + "Sips exponent at reference temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Real[no_components] alpha(each unit="1") = {0.5559, 0.5559, 0.5559} + "Parameter describing the change of the Sips exponent with temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + parameter Modelica.Units.SI.Temperature[no_components] T_ref = {283, 283, 283} + "Reference temperature" + annotation (Dialog(tab="Isotherm model", group="Parameters"), + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.MolarEnthalpy[no_components] h_ads_ternary(each displayUnit="kJ/mol") + "Molar adsorption enthalpy calculated via ternary approach"; + +equation + // + // Definition of derivatives + // + der(p_adsorpt) = 100000/20 + "Predecsriped slope of p_adsorpt to demonstrate the isotherm model"; + der(y_i) = {0.97/20/3*2, 0.97/20/3*1} + "Predecsriped slope of y_i to demonstrate the isotherm model"; + der(T_adsorpt) = 90/20 + "Predecsriped slope of T_adsorpt to demonstrate the isotherm model"; + + // + // Calculate coefficients of the isotherm model + // + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - T_adsorpt/T_ref[ind_comp])) + "Coefficients of isotherm model"; + c[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/T_adsorpt - 1)) + "Coefficients of isotherm model"; + c[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/T_adsorpt)) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -chi[ind_comp]/T_ref[ind_comp] * c[1,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = -Q[ind_comp]/Modelica.Constants.R/T_adsorpt^2 * c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[3,ind_comp] = -T_ref[ind_comp]*alpha[ind_comp]/T_adsorpt^2 / + (1/n_ref[ind_comp] + alpha[ind_comp] * (1 - T_ref[ind_comp]/T_adsorpt))^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + end for; + + // + // Calculate properties + // + x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.x_pyT( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Uptakes"; + + dx_adsorpt_dp = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.dx_dp( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Partial derivative of uptakes w.r.t. pressure at constant mole fractions and + temperature"; + + dx_adsorpt_dy_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.dx_dy( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Partial derivatives of the uptakes w.r.t. the molar fractions of independent + components of adsorptive phase at constant pressure and temperature"; + + dx_adsorpt_dT = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.dx_dT( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + p_threshold_min=p_threshold_min) + "Partial derivative of uptakes w.r.t. temperature at constant pressure and + mole fractions"; + + h_ads_ternary = SorpLib.Media.Functions.SorptionEnthalpies.MultiComponents.h_ads_ternary_clausiusClapeyron( + M_i=M_i, + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dy_i=dx_adsorpt_dy_i, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar adsorption enthalpy calculated via ternary approach"; + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'h_ads_ClausiusClapeyron_ternary.' +<br/><br/> +To see the function behavior, plot the variables <i>h_ads_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_h_ads_clausiusClapeyron_ternary; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/package.mo b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..63ef7a3ca79afd336a6d0468ebfd7b8132850096 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.MultiComponents; +package Testers "Models to test and varify functions for sorption enthalpies for multi components" + extends Modelica.Icons.ExamplesPackage; + + + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions and models of the +'MultiComponents' package. The test models check the implementation of the functions +and models and enable verification of their behavior. In addition, the test models +demonstrate the functions' and models' general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/package.order b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..65d0b1ed3bdfcf02c3c2510c7d5deb0b74148dd2 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/Testers/package.order @@ -0,0 +1,2 @@ +Test_h_ads_clausiusClapeyron_binary +Test_h_ads_clausiusClapeyron_ternary diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/h_ads_binary_clausiusClapeyron.mo b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/h_ads_binary_clausiusClapeyron.mo new file mode 100644 index 0000000000000000000000000000000000000000..6b65aa0db7eb1894862931ee2e19d662cb4cb79d --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/h_ads_binary_clausiusClapeyron.mo @@ -0,0 +1,151 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.MultiComponents; +function h_ads_binary_clausiusClapeyron + "Molar adsorption enthalpies for a binary mixture according to Clausius Clapeyron" + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialMulti_h_ads; + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt_ + "Limited total pressure"; + Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i_ + "Limited mole fractions of independent components in the vapor or gas phase"; + + Real[size(M_i,1)] numerator_i + "Numerators of all components"; + Real numerator_summand_1 + "Summand 1 of the numerator for each component"; + Real numerator_summand_2 + "Summand 2 of the numerator for each component"; + + Real denominator + "Denominator for each component"; + +algorithm + // + // Define initial values + // + p_adsorpt_ := max(p_adsorpt, p_threshold_min) + "Limited total pressure"; + for ind in 1:size(M_i,1)-1 loop + y_i_[ind] := max(y_i[ind], y_i_threshold_min) + "Limited mole fractions of independent components in the vapor or gas phase"; + end for; + + // + // Set up numerators + // + numerator_summand_1 :=(dx_adsorpt_dT[1]*dx_adsorpt_dy_i[2, 1] - + dx_adsorpt_dT[2]*dx_adsorpt_dy_i[1, 1]) + "Summand 1 of the numerator for each component"; + numerator_summand_2 :=(dx_adsorpt_dp[1]*dx_adsorpt_dT[2] - + dx_adsorpt_dp[2]*dx_adsorpt_dT[1]) + "Summand 2 of the numerator for each component"; + + numerator_i[1] := 1 / (p_adsorpt_ * M_i[1] * M_i[2]) * numerator_summand_1 + + 1 / (y_i_[1] * M_i[1] * M_i[2]) * numerator_summand_2 + "Numerator of first component"; + numerator_i[2] := 1 / (p_adsorpt_ * M_i[1] * M_i[2]) * numerator_summand_1 - + 1 / ((1 - y_i_[1]) * M_i[1] * M_i[2]) * numerator_summand_2 + "Numerator of second component"; + + // + // Set up denominator + // + denominator := -1 / (M_i[1] * M_i[2]) * + (dx_adsorpt_dp[1] * dx_adsorpt_dy_i[2,1] - + dx_adsorpt_dp[2] * dx_adsorpt_dy_i[1,1]) + "Denominator for each components"; + + // + // Calculate adsorption enthalpies + // + if p_adsorpt < p_threshold_min then + // + // Vacuum + // + h_ads := fill(100*Modelica.Constants.eps, size(M_i,1)) + "Molar adsorption enthalpy"; + + else + // + // No vacuum + // + if y_i[1] > y_i_threshold_min then + h_ads[1] := Modelica.Constants.R * T_adsorpt^2 * + numerator_i[1] / denominator + "Molar adsorption enthalpy of first component"; + else + h_ads[1] := 100*Modelica.Constants.eps + "Molar adsorption enthalpy of first component"; + end if; + + if 1-y_i[1] > y_i_threshold_min then + h_ads[2] := Modelica.Constants.R * T_adsorpt^2 * + numerator_i[2] / denominator + "Molar adsorption enthalpy of second component"; + else + h_ads[2] := 100*Modelica.Constants.eps + "Molar adsorption enthalpy of second component"; + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the molar adsorption enthalpies for binary mixtures according +to Clausius Clapeyron assumptions. +</p> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads,i</sub></i> of component <i>i</i> +is defined as follows: +</p> +<pre> + Δh<sub>ads,<i>i</i></sub> = R * T<sup>2</sup> * [∂(<strong>ln</strong>(y<sub><i>i</i></sub> * p), x<sub>1</sub>, ..., x<sub>N</sub>) / ∂(p, T, y<sub>1</sub>, ..., y<sub>N-1</sub>)] / [∂(T, x<sub>1</sub>, ..., x<sub>N</sub>) / ∂(p, T, y<sub>1</sub>, ..., y<sub>N-1</sub>)]; +</pre> +<p> +Herein, <i>R</i> is the ideal gas constant, <i>p</i> is the pressure, <i>T</i> is +the temperature, <i>x<sub>i</sub></i> are the uptakes, and <i>y<sub>i</sub></i> +are the independent mole fractions in the adsorptive phase. +<br><br> +The determinants in the numerator and denominator have already been solved. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The specific volume of the adsorpt phase can be neglected compared to the specific + volume of the adsorptive phase. + </li> + <li> + The adsorptive can be treated as an ideal gas mixture. + </li> + <li> + The adsorpt can be treated as an ideal solution. + </li> + <li> + Inert sorbent. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Sircar, S. (1984). Excess Properties and Thermodynamics of Multicomponent Gas Adsorption. Journal of the Chemical Society, Faraday Transactions 1: Physical Chemistry in Condensed Phases, 81:1527-1540. DOI: https://doi.org/10.1039/F19858101527. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end h_ads_binary_clausiusClapeyron; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/h_ads_clausiusClapeyron.mo b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/h_ads_clausiusClapeyron.mo new file mode 100644 index 0000000000000000000000000000000000000000..569b6d48d5f604106f1bb0f22891d90122623434 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/h_ads_clausiusClapeyron.mo @@ -0,0 +1,220 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.MultiComponents; +function h_ads_clausiusClapeyron + "Molar adsorption enthalpies according to Clausius Clapeyron" + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialMulti_h_ads; + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt_ + "Limited total pressure"; + Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i_ + "Limited mole fractions of independent components in the vapor or gas phase"; + + // + // Dimension 1: Components + // Dimension 2: p_adsorpt or T_adsorpt | x_1 | ... | x_size(M_i,1) + // Dimension 3: p_adsorpt | T_adsorpt | y_1 | ... | y_size(M_i,1)-1 + // + Real[size(M_i,1),size(M_i,1)+1,size(M_i,1)+1] numerator_i + "Numerators of all components"; + Real[size(M_i,1),size(M_i,1)+1,size(M_i,1)+1] denominator_i + "Denominators of all components"; + +algorithm + // + // Define initial values + // + p_adsorpt_ := max(p_adsorpt, p_threshold_min) + "Limited total pressure"; + for ind in 1:size(M_i,1)-1 loop + y_i_[ind] := max(y_i[ind], y_i_threshold_min) + "Limited mole fractions of independent components in the vapor or gas phase"; + end for; + + numerator_i:= zeros(size(M_i,1),size(M_i,1)+1,size(M_i,1)+1) + "Numerators of all components"; + denominator_i:= zeros(size(M_i,1),size(M_i,1)+1,size(M_i,1)+1) + "Denominators of all components"; + + // + // Set up numerators and denominators + // + for ind_comp in 1:size(M_i,1) loop + // + // First row of numerators and denominators + // + numerator_i[ind_comp,1,1] :=1/p_adsorpt_ + "Partial derivatives of partial pressures w.r.t. pressure"; + numerator_i[ind_comp,1,2] :=0 + "Partial derivatives of partial pressures w.r.t. temperature"; + + denominator_i[ind_comp,1,1] :=0 + "Partial derivatives of temperature w.r.t. pressure"; + denominator_i[ind_comp,1,2] :=1 + "Partial derivatives of temperature w.r.t. temperature"; + + for ind_indep_comp in 1:size(M_i,1)-1 loop + if ind_comp < size(M_i,1) then + numerator_i[ind_comp,1,2+ind_indep_comp] :=if ind_comp == + ind_indep_comp then 1/y_i_[ind_indep_comp] else 0 + "Partial derivatives of partial pressures w.r.t. independent mole + fractions of adsorptive phase"; + else + numerator_i[ind_comp,1,2+ind_indep_comp] := -1 / (1 - sum(y_i_)) + "Partial derivatives of partial pressures w.r.t. independent mole + fractions of adsorptive phase"; + end if; + + denominator_i[ind_comp,1,2+ind_indep_comp] :=0 + "Partial derivatives of partial pressures w.r.t. independent mole + fractions of adsorptive phase"; + + end for; + + // + // Second to last row of numerators and denominators + // + for ind_comp_inner in 1:size(M_i,1) loop + // + // Partial derivatives w.r.t. pressure + // + numerator_i[ind_comp,1+ind_comp_inner,1] := + 1 / M_i[ind_comp_inner] * dx_adsorpt_dp[ind_comp_inner] + "Partial derivatives of uptake w.r.t. pressure"; + denominator_i[ind_comp,1+ind_comp_inner,1] := + 1 / M_i[ind_comp_inner] * dx_adsorpt_dp[ind_comp_inner] + "Partial derivatives of uptake w.r.t. pressure"; + + // + // Partial derivatives w.r.t. temperature + // + numerator_i[ind_comp,1+ind_comp_inner,2] := + 1 / M_i[ind_comp_inner] * dx_adsorpt_dT[ind_comp_inner] + "Partial derivatives of uptake w.r.t. pressure"; + denominator_i[ind_comp,1+ind_comp_inner,2] := + 1 / M_i[ind_comp_inner] * dx_adsorpt_dT[ind_comp_inner] + "Partial derivatives of uptake w.r.t. pressure"; + + // + // Partial derivatives w.r.t. independent mole fractions of adsorptive phase + // + for ind_indep_comp in 1:size(M_i,1)-1 loop + numerator_i[ind_comp,1+ind_comp_inner,2+ind_indep_comp] := + 1 / M_i[ind_comp_inner] * dx_adsorpt_dy_i[ind_comp_inner,ind_indep_comp] + "Partial derivatives of uptake w.r.t. independent mole fractions"; + denominator_i[ind_comp,1+ind_comp_inner,2+ind_indep_comp] := + 1 / M_i[ind_comp_inner] * dx_adsorpt_dy_i[ind_comp_inner,ind_indep_comp] + "Partial derivatives of uptake w.r.t. independent mole fractions"; + + end for; + end for; + end for; + + // + // Calculate adsorption enthalpies + // + if p_adsorpt < p_threshold_min then + // + // Vacuum + // + h_ads := fill(100*Modelica.Constants.eps, size(M_i,1)) + "Molar adsorption enthalpy"; + + else + // + // Independent components + // + for ind_comp in 1:size(M_i,1)-1 loop + if y_i[ind_comp] > y_i_threshold_min then + h_ads[ind_comp] := Modelica.Constants.R * T_adsorpt^2 * + Modelica.Math.Matrices.det(numerator_i[ind_comp,:,:]) / + Modelica.Math.Matrices.det(denominator_i[ind_comp,:,:]) + "Molar adsorption enthalpy"; + + else + h_ads[ind_comp] := -100*Modelica.Constants.eps + "Molar adsorption enthalpy"; + + end if; + end for; + + // + // Dependent components + // + if 1-sum(y_i) > y_i_threshold_min then + h_ads[size(M_i,1)] := Modelica.Constants.R * T_adsorpt^2 * + Modelica.Math.Matrices.det(numerator_i[size(M_i,1),:,:]) / + Modelica.Math.Matrices.det(denominator_i[size(M_i,1),:,:]) + "Molar adsorption enthalpy"; + + else + h_ads[size(M_i,1)] := 100*Modelica.Constants.eps + "Molar adsorption enthalpy"; + + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the molar adsorption enthalpies for mixtures according to +Clausius Clapeyron assumptions. +</p> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads,i</sub></i> of component <i>i</i> +is defined as follows: +</p> +<pre> + Δh<sub>ads,<i>i</i></sub> = R * T<sup>2</sup> * [∂(<strong>ln</strong>(y<sub><i>i</i></sub> * p), x<sub>1</sub>, ..., x<sub>N</sub>) / ∂(p, T, y<sub>1</sub>, ..., y<sub>N-1</sub>)] / [∂(T, x<sub>1</sub>, ..., x<sub>N</sub>) / ∂(p, T, y<sub>1</sub>, ..., y<sub>N-1</sub>)]; +</pre> +<p> +Herein, <i>R</i> is the ideal gas constant, <i>p</i> is the pressure, <i>T</i> is +the temperature, <i>x<sub>i</sub></i> are the uptakes, and <i>y<sub>i</sub></i> +are the independent mole fractions in the adsorptive phase. +<br><br> +The determinants in the numerator and denominator are calculated using the Modelica +function +<a href=\"Modelica://Modelica.Math.Matrices.det\">Modelica.Math.Matrices.det</a>. +Hence, it is more efficient to use other functions that not rely on the Modelica +function but have the determinats already solved. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The specific volume of the adsorpt phase can be neglected compared to the specific + volume of the adsorptive phase. + </li> + <li> + The adsorptive can be treated as an ideal gas mixture. + </li> + <li> + The adsorpt can be treated as an ideal solution. + </li> + <li> + Inert sorbent. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Sircar, S. (1984). Excess Properties and Thermodynamics of Multicomponent Gas Adsorption. Journal of the Chemical Society, Faraday Transactions 1: Physical Chemistry in Condensed Phases, 81:1527-1540. DOI: https://doi.org/10.1039/F19858101527. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end h_ads_clausiusClapeyron; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/h_ads_ternary_clausiusClapeyron.mo b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/h_ads_ternary_clausiusClapeyron.mo new file mode 100644 index 0000000000000000000000000000000000000000..7e6dd9e5cd27fc065ab6cee2b1f82a51f7edcc0f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/h_ads_ternary_clausiusClapeyron.mo @@ -0,0 +1,191 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.MultiComponents; +function h_ads_ternary_clausiusClapeyron + "Molar adsorption enthalpies for a ternary mixture according to Clausius Clapeyron" + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialMulti_h_ads; + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt_ + "Limited total pressure"; + Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i_ + "Limited mole fractions of independent components in the vapor or gas phase"; + + Real[size(M_i,1)] numerator_i + "Numerators of all components"; + Real numerator_summand_1 + "Summand 1 of the numerator for each component"; + Real numerator_summand_2 + "Summand 2 of the numerator for each component"; + Real numerator_summand_3 + "Summand 3 of the numerator for each component"; + + Real denominator + "Denominator for each component"; + +algorithm + // + // Define initial values + // + p_adsorpt_ := max(p_adsorpt, p_threshold_min) + "Limited total pressure"; + for ind in 1:size(M_i,1)-1 loop + y_i_[ind] := max(y_i[ind], y_i_threshold_min) + "Limited mole fractions of independent components in the vapor or gas phase"; + end for; + + // + // Set up numerators + // + numerator_summand_1 := dx_adsorpt_dT[1] * + (dx_adsorpt_dy_i[2,1] * dx_adsorpt_dy_i[3,2] - + dx_adsorpt_dy_i[3,1] * dx_adsorpt_dy_i[2,2]) - dx_adsorpt_dy_i[1,1] * + (dx_adsorpt_dT[2] * dx_adsorpt_dy_i[3,2] - + dx_adsorpt_dT[3] * dx_adsorpt_dy_i[2,2]) + dx_adsorpt_dy_i[1,2] * + (dx_adsorpt_dT[2] * dx_adsorpt_dy_i[3,1] - + dx_adsorpt_dT[3] * dx_adsorpt_dy_i[2,1]) + "Summand 1 of the numerator for each component"; + numerator_summand_2 :=dx_adsorpt_dp[1] * + (dx_adsorpt_dT[2] * dx_adsorpt_dy_i[3,2] - + dx_adsorpt_dT[3] * dx_adsorpt_dy_i[2,2]) - dx_adsorpt_dT[1] * + (dx_adsorpt_dp[2] * dx_adsorpt_dy_i[3,2] - + dx_adsorpt_dp[3] * dx_adsorpt_dy_i[2,2]) + dx_adsorpt_dy_i[1,2] * + (dx_adsorpt_dp[2] * dx_adsorpt_dT[3] - + dx_adsorpt_dp[3] * dx_adsorpt_dT[2]) + "Summand 2 of the numerator for each component"; + numerator_summand_3 :=dx_adsorpt_dp[1] * + (dx_adsorpt_dT[2] * dx_adsorpt_dy_i[3,1] - + dx_adsorpt_dT[3] * dx_adsorpt_dy_i[2,1]) - dx_adsorpt_dT[1] * + (dx_adsorpt_dp[2] * dx_adsorpt_dy_i[3,1] - + dx_adsorpt_dp[3] * dx_adsorpt_dy_i[2,1]) + dx_adsorpt_dy_i[1,1] * + (dx_adsorpt_dp[2] * dx_adsorpt_dT[3] - + dx_adsorpt_dp[3] * dx_adsorpt_dT[2]) + "Summand 3 of the numerator for each component"; + + numerator_i[1] := + 1 / (p_adsorpt_ * M_i[1] * M_i[2] * M_i[3]) * numerator_summand_1 + + 1 / (y_i_[1] * M_i[1] * M_i[2] * M_i[3]) * numerator_summand_2 + "Numerator of first component"; + numerator_i[2] := + 1 / (p_adsorpt_ * M_i[1] * M_i[2] * M_i[3]) * numerator_summand_1 - + 1 / (y_i_[2] * M_i[1] * M_i[2] * M_i[3]) * numerator_summand_3 + "Numerator of second component"; + numerator_i[3] := + 1 / (p_adsorpt_ * M_i[1] * M_i[2] * M_i[3]) * numerator_summand_1 + + 1 / (-(1 - sum(y_i_)) * M_i[1] * M_i[2] * M_i[3]) * numerator_summand_2 - + 1 / (-(1 - sum(y_i_)) * M_i[1] * M_i[2] * M_i[3]) * numerator_summand_3 + "Numerator of third component"; + + // + // Set up denominator + // + denominator := -1 / (M_i[1] * M_i[2] * M_i[3]) * (dx_adsorpt_dp[1] * + (dx_adsorpt_dy_i[2,1] * dx_adsorpt_dy_i[3,2] - + dx_adsorpt_dy_i[3,1] * dx_adsorpt_dy_i[2,2]) - dx_adsorpt_dy_i[1,1] * + (dx_adsorpt_dp[2] * dx_adsorpt_dy_i[3,2] - + dx_adsorpt_dp[3] * dx_adsorpt_dy_i[2,2]) + dx_adsorpt_dy_i[1,2] * + (dx_adsorpt_dp[2] * dx_adsorpt_dy_i[3,1] - + dx_adsorpt_dp[3] * dx_adsorpt_dy_i[2,1])) + "Denominator for each components"; + + // + // Calculate adsorption enthalpies + // + if p_adsorpt < p_threshold_min then + // + // Vacuum + // + h_ads := fill(100*Modelica.Constants.eps, size(M_i,1)) + "Molar adsorption enthalpy"; + + else + // + // No vacuum + // + if y_i[1] > y_i_threshold_min then + h_ads[1] := Modelica.Constants.R * T_adsorpt^2 * + numerator_i[1] / denominator + "Molar adsorption enthalpy of first component"; + else + h_ads[1] := 100*Modelica.Constants.eps + "Molar adsorption enthalpy of first component"; + end if; + + if y_i[2] > y_i_threshold_min then + h_ads[2] := Modelica.Constants.R * T_adsorpt^2 * + numerator_i[2] / denominator + "Molar adsorption enthalpy of first component"; + else + h_ads[2] := 100*Modelica.Constants.eps + "Molar adsorption enthalpy of second component"; + end if; + + if 1-y_i[1]-y_i[2] > y_i_threshold_min then + h_ads[3] := Modelica.Constants.R * T_adsorpt^2 * + numerator_i[3] / denominator + "Molar adsorption enthalpy of third component"; + else + h_ads[3] := 100*Modelica.Constants.eps + "Molar adsorption enthalpy of third component"; + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the molar adsorption enthalpies for ternary mixtures according +to Clausius Clapeyron assumptions. +</p> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads,i</sub></i> of component <i>i</i> +is defined as follows: +</p> +<pre> + Δh<sub>ads,<i>i</i></sub> = R * T<sup>2</sup> * [∂(<strong>ln</strong>(y<sub><i>i</i></sub> * p), x<sub>1</sub>, ..., x<sub>N</sub>) / ∂(p, T, y<sub>1</sub>, ..., y<sub>N-1</sub>)] / [∂(T, x<sub>1</sub>, ..., x<sub>N</sub>) / ∂(p, T, y<sub>1</sub>, ..., y<sub>N-1</sub>)]; +</pre> +<p> +Herein, <i>R</i> is the ideal gas constant, <i>p</i> is the pressure, <i>T</i> is +the temperature, <i>x<sub>i</sub></i> are the uptakes, and <i>y<sub>i</sub></i> +are the independent mole fractions in the adsorptive phase. +<br><br> +The determinants in the numerator and denominator have already been solved. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The specific volume of the adsorpt phase can be neglected compared to the specific + volume of the adsorptive phase. + </li> + <li> + The adsorptive can be treated as an ideal gas mixture. + </li> + <li> + The adsorpt can be treated as an ideal solution. + </li> + <li> + Inert sorbent. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Sircar, S. (1984). Excess Properties and Thermodynamics of Multicomponent Gas Adsorption. Journal of the Chemical Society, Faraday Transactions 1: Physical Chemistry in Condensed Phases, 81:1527-1540. DOI: https://doi.org/10.1039/F19858101527. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end h_ads_ternary_clausiusClapeyron; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/package.mo b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..856655e84f9591fda4fa5a007a3f29d8c0d18df2 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/package.mo @@ -0,0 +1,28 @@ +within SorpLib.Media.Functions.SorptionEnthalpies; +package MultiComponents "Functions required to calculate sorption enthalpies for multi components" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains models to calculate sorption enthalpies for pure component +adsorption. +</p> + +<h4>Implemented functions for each sorption enthalpy model</h4> +<p> +The following functions are provided for each sorption enthalpy model: +</p> +<ul> + <li> + Sorption enthalpy. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end MultiComponents; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/package.order b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..41622bdb67b10cb2a2909840d1ab11fa26ac9c84 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/MultiComponents/package.order @@ -0,0 +1,4 @@ +h_ads_clausiusClapeyron +h_ads_binary_clausiusClapeyron +h_ads_ternary_clausiusClapeyron +Testers diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/Test_h_ads.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/Test_h_ads.mo new file mode 100644 index 0000000000000000000000000000000000000000..976e199826370500f2461a7809585c054824f904 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/Test_h_ads.mo @@ -0,0 +1,505 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.Testers; +model Test_h_ads + "Tester for the function 'h_ads' and all corresponding functions" + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialTestPure( + final no_coefficients = 6, + final dp = 1e-2, + final dT = 1e-2, + final dx = 1e-4); + + // + // Definition of variables + // +protected + Medium.ThermodynamicState state_adsorptive_pT_pdT_x + "State properties of adsorptive at p_adsorpt(x_adsorpt,T_adsorpt+dT) and + T_adsorpt + dT"; + Medium.ThermodynamicState state_adsorptive_pT_mdT_x + "State properties of adsorptive at p_adsorpt(x_adsorpt,T_adsorpt-dT) and + T_adsorpt - dT"; + Medium.ThermodynamicState state_adsorptive_pT_pdx + "State properties of adsorptive at p_adsorpt(x_adsorpt+dx,T_adsorpt) and T_adsorpt"; + Medium.ThermodynamicState state_adsorptive_pT_mdx + "State properties of adsorptive at p_adsorpt(x_adsorpt-dx,T_adsorpt) and T_adsorpt"; + + Medium.ThermodynamicState state_bubble_T_pdT + "State properties of bubble point at T_adsorpt: T + dT"; + Medium.ThermodynamicState state_bubble_T_mdT + "State properties of bubble point at T_adsorpt: T - dT"; + + Modelica.Units.SI.Pressure p_adsorpt_pdT_x + "Pressure at x_adsorpt and T_adsorpt + dT"; + Modelica.Units.SI.Pressure p_adsorpt_mdT_x + "Pressure at x_adsorpt and T_adsorpt - dT"; + + Modelica.Units.SI.Pressure p_adsorpt_pdx_T + "Pressure at T_adsorpt and x_adsorpt + xT"; + Modelica.Units.SI.Pressure p_adsorpt_mdx_T + "Pressure at T_adsorpt and x_adsorpt - xT"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_pdT_p + "Partial derivative of uptake w.r.t. pressure at constant temperature: T + dT"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_mdT_p + "Partial derivative of uptake w.r.t. pressure at constant temperature: T - dT"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_pdp_T + "Partial derivative of uptake w.r.t. pressure at constant temperature: p + dp"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_mdp_T + "Partial derivative of uptake w.r.t. pressure at constant temperature: p - dp"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_pdT_x + "Partial derivative of uptake w.r.t. pressure at constant temperature: x_adsorpt + and T + dT"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_mdT_x + "Partial derivative of uptake w.r.t. pressure at constant temperature: x_adsorpt + and T - dT"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_pdx_T + "Partial derivative of uptake w.r.t. pressure at constant temperature: x + dx"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_mdx_T + "Partial derivative of uptake w.r.t. pressure at constant temperature: x - dx"; + + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_pdT_p + "Partial derivative of uptake w.r.t. temperature at constant pressure: T + dT"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_mdT_p + "Partial derivative of uptake w.r.t. temperature at constant pressure: T - dT"; + + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_pdp_T + "Partial derivative of uptake w.r.t. temperature at constant pressure: p + dp"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_mdp_T + "Partial derivative of uptake w.r.t. temperature at constant pressure: p - dp"; + + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_pdT_x + "Partial derivative of uptake w.r.t. temperature at constant pressure: x_adsorpt + and T + dT"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_mdT_x + "Partial derivative of uptake w.r.t. temperature at constant pressure: x_adsorpt + and T - dT"; + + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_pdx_T + "Partial derivative of uptake w.r.t. temperature at constant pressure: x + dx"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_mdx_T + "Partial derivative of uptake w.r.t. temperature at constant pressure: x - dx"; + +equation + // + // Definition of derivatives + // + der(p_adsorpt) = 0.75 * dc_dT[1] + "Predecsriped slope of p_adsorpt"; + der(T_adsorpt) = 90/20 + "Predecsriped slope of T_adsorpt"; + + // + // Calculate coefficients of the isotherm model + // + c[1] = state_bubble_T.p; + c[2] = state_bubble_T.d; + c[3] = 5.072313e-1 / 1000; + c[4] = 1.305531e2 * 1000 * 0.018; + c[5] = -8.492403e1 * 1000 * 0.018; + c[6] = 4.128962e-3 / 1000; + + c_pdT[1] = sat_T_pdT.psat; + c_pdT[2] = Medium.bubbleDensity(sat=sat_T_pdT); + c_pdT[3] = 5.072313e-1 / 1000; + c_pdT[4] = 1.305531e2 * 1000 * 0.018; + c_pdT[5] = -8.492403e1 * 1000 * 0.018; + c_pdT[6] = 4.128962e-3 / 1000; + + c_mdT[1] = sat_T_mdT.psat; + c_mdT[2] = Medium.bubbleDensity(sat=sat_T_mdT); + c_mdT[3] = 5.072313e-1 / 1000; + c_mdT[4] = 1.305531e2 * 1000 * 0.018; + c_mdT[5] = -8.492403e1 * 1000 * 0.018; + c_mdT[6] = 4.128962e-3 / 1000; + + // + // Calculate partial derivatives of coefficients of the isotherm model w.r.t. + // temperature + // + dc_dT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T); + dc_dT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T) * dc_dT[1]; + dc_dT[3] = 0; + dc_dT[4] = 0; + dc_dT[5] = 0; + dc_dT[6] = 0; + + dc_dT_pdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_pdT); + dc_dT_pdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_pdT) * dc_dT_pdT[1]; + dc_dT_pdT[3] = 0; + dc_dT_pdT[4] = 0; + dc_dT_pdT[5] = 0; + dc_dT_pdT[6] = 0; + + dc_dT_mdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_mdT); + dc_dT_mdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_mdT) * dc_dT_mdT[1]; + dc_dT_mdT[3] = 0; + dc_dT_mdT[4] = 0; + dc_dT_mdT[5] = 0; + dc_dT_mdT[6] = 0; + + // + // Calculate second-order partial derivatives of coefficients of the isotherm + // model w.r.t. temperature + // + ddc_dT_dT[1] = (dc_dT_pdT[1] - dc_dT_mdT[1]) / (2*dT); + ddc_dT_dT[2] = (dc_dT_pdT[2] - dc_dT_mdT[2]) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = 0; + ddc_dT_dT[6] = 0; + + // + // Calculation of state properties + // + state_adsorptive_pT_pdT_x = Medium.setState_pTX( + p=p_adsorpt_pdT_x, + T=T_adsorpt+dT) + "State properties of adsorptive at p_adsorpt(x_adsorpt,T_adsorpt+dT) and + T_adsorpt + dT"; + state_adsorptive_pT_mdT_x = Medium.setState_pTX( + p=p_adsorpt_mdT_x, + T=T_adsorpt-dT) + "State properties of adsorptive at p_adsorpt(x_adsorpt,T_adsorpt-dT) and + T_adsorpt - dT"; + + state_adsorptive_pT_pdx = Medium.setState_pTX( + p=p_adsorpt_pdx_T, + T=T_adsorpt) + "State properties of adsorptive at p_adsorpt(x_adsorpt+dx,T_adsorpt) and T_adsorpt"; + state_adsorptive_pT_mdx = Medium.setState_pTX( + p=p_adsorpt_mdx_T, + T=T_adsorpt) + "State properties of adsorptive at p_adsorpt(x_adsorpt-dx,T_adsorpt) and T_adsorpt"; + + state_bubble_T_pdT = Medium.setBubbleState(sat=sat_T_pdT) + "State properties of bubble point at T_adsorpt: T + dT"; + state_bubble_T_mdT = Medium.setBubbleState(sat=sat_T_mdT) + "State properties of bubble point at T_adsorpt: T - dT"; + + // + // Calculate properties + // + x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Uptake"; + + dx_adsorpt_dp = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + h_ads = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=1/state_adsorptive_pT.d, + v_adsorpt=1/state_bubble_T.d, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar adsorption enthalpy"; + + dh_ads_dp_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=1/state_adsorptive_pT.d, + v_adsorpt=1/state_bubble_T.d, + dv_adsorptive_dp=(1/state_adsorptive_pT_pdp.d - 1/state_adsorptive_pT_mdp.d) / + (2*dp), + dv_adsorpt_dp=0, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at + constant temperature"; + dh_ads_dT_p = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=1/state_adsorptive_pT.d, + v_adsorpt=1/state_bubble_T.d, + dv_adsorptive_dT=(1/state_adsorptive_pT_pdT.d - 1/state_adsorptive_pT_mdT.d) / + (2*dT), + dv_adsorpt_dT=-1/state_bubble_T.d^2 * dc_dT[2], + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at + constant pressure"; + + // + // Calculate pressures for numerical derivatives + // + p_adsorpt_pdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt+dT, + c=c_pdT, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt and T_adsorpt + dT"; + p_adsorpt_mdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt-dT, + c=c_mdT, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt and T_adsorpt - dT"; + + p_adsorpt_pdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt+dx, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at T_adsorpt and x_adsorpt + dx"; + p_adsorpt_mdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt-dx, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at T_adsorpt and x_adsorpt - dx"; + + // + // Calculate partial derivatives of uptake w.r.t. pressure at constant temperature + // for numerical derivatives + // + dx_adsorpt_dp_pdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt+dp, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature: p + dp"; + dx_adsorpt_dp_mdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt-dp, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature: p - dp"; + + dx_adsorpt_dp_pdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt+dT, + c=c_pdT) + "Partial derivative of uptake w.r.t. pressure at constant temperature: T + dT"; + dx_adsorpt_dp_mdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt-dT, + c=c_mdT) + "Partial derivative of uptake w.r.t. pressure at constant temperature: T - dT"; + + dx_adsorpt_dp_pdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt_pdT_x, + T_adsorpt=T_adsorpt+dT, + c=c_pdT) + "Partial derivative of uptake w.r.t. pressure at constant temperature: x_adsorpt + and T + dT"; + dx_adsorpt_dp_mdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt_mdT_x, + T_adsorpt=T_adsorpt-dT, + c=c_mdT) + "Partial derivative of uptake w.r.t. pressure at constant temperature: x_adsorpt + and T - dT"; + + dx_adsorpt_dp_pdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt_pdx_T, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature: T_adsorpt + and x + dx"; + dx_adsorpt_dp_mdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt_mdx_T, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature: T_adsorpt + and x - dx"; + + // + // Calculate partial derivatives of uptake w.r.t. temperature at constant pressure + // for numerical derivatives + // + dx_adsorpt_dT_pdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt+dp, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: p + dp"; + dx_adsorpt_dT_mdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt-dp, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: p - dp"; + + dx_adsorpt_dT_pdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt+dT, + c=c_pdT, + dc_dT_adsorpt=dc_dT_pdT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: T + dT"; + dx_adsorpt_dT_mdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt-dT, + c=c_mdT, + dc_dT_adsorpt=dc_dT_mdT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: T - dT"; + + dx_adsorpt_dT_pdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt_pdT_x, + T_adsorpt=T_adsorpt+dT, + c=c_pdT, + dc_dT_adsorpt=dc_dT_pdT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: x_adsorpt + and T + dT"; + dx_adsorpt_dT_mdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt_mdT_x, + T_adsorpt=T_adsorpt-dT, + c=c_mdT, + dc_dT_adsorpt=dc_dT_mdT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: x_adsorpt + and T - dT"; + + dx_adsorpt_dT_pdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt_pdx_T, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: T_adsorpt + and x + dx"; + dx_adsorpt_dT_mdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt_mdx_T, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: T_adsorpt + and x - dx"; + + // + // Calculate molar adsorption potentials for numerical derivatives + // + h_ads_pdp_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=1/state_adsorptive_pT_pdp.d, + v_adsorpt=1/state_bubble_T.d, + dx_adsorpt_dp=dx_adsorpt_dp_pdp_T, + dx_adsorpt_dT=dx_adsorpt_dT_pdp_T) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: p + dp"; + h_ads_mdp_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=1/state_adsorptive_pT_mdp.d, + v_adsorpt=1/state_bubble_T.d, + dx_adsorpt_dp=dx_adsorpt_dp_mdp_T, + dx_adsorpt_dT=dx_adsorpt_dT_mdp_T) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: p - dp"; + + h_ads_pdT_p = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt+dT, + v_adsorptive=1/state_adsorptive_pT_pdT.d, + v_adsorpt=1/state_bubble_T_pdT.d, + dx_adsorpt_dp=dx_adsorpt_dp_pdT_p, + dx_adsorpt_dT=dx_adsorpt_dT_pdT_p) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: T + dT"; + h_ads_mdT_p = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt-dT, + v_adsorptive=1/state_adsorptive_pT_mdT.d, + v_adsorpt=1/state_bubble_T_mdT.d, + dx_adsorpt_dp=dx_adsorpt_dp_mdT_p, + dx_adsorpt_dT=dx_adsorpt_dT_mdT_p) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: T - dT"; + + h_ads_pdT_x = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt+dT, + v_adsorptive=1/state_adsorptive_pT_pdT_x.d, + v_adsorpt=1/state_bubble_T_pdT.d, + dx_adsorpt_dp=dx_adsorpt_dp_pdT_x, + dx_adsorpt_dT=dx_adsorpt_dT_pdT_x) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt, T+dT) and T_adsorpt: T + dT"; + h_ads_mdT_x = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt-dT, + v_adsorptive=1/state_adsorptive_pT_mdT_x.d, + v_adsorpt=1/state_bubble_T_mdT.d, + dx_adsorpt_dp=dx_adsorpt_dp_mdT_x, + dx_adsorpt_dT=dx_adsorpt_dT_mdT_x) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt, T-dT) and T_adsorpt: T - dT"; + + h_ads_pdx_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=1/state_adsorptive_pT_pdx.d, + v_adsorpt=1/state_bubble_T.d, + dx_adsorpt_dp=dx_adsorpt_dp_pdx_T, + dx_adsorpt_dT=dx_adsorpt_dT_pdx_T) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt+dx) and T_adsorpt"; + h_ads_mdx_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=1/state_adsorptive_pT_mdx.d, + v_adsorpt=1/state_bubble_T.d, + dx_adsorpt_dp=dx_adsorpt_dp_mdx_T, + dx_adsorpt_dT=dx_adsorpt_dT_mdx_T) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt-dx) and T_adsorpt"; + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'h_ads' function and its +partial derivative with resprect to temperature. +<br/><br/> +To see the function behavior, plot the variables <i>h_ads_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_h_ads; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/Test_h_ads_Dubinin.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/Test_h_ads_Dubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..77fa98a4443d449c6e408d6a67048eef89099e58 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/Test_h_ads_Dubinin.mo @@ -0,0 +1,674 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.Testers; +model Test_h_ads_Dubinin + "Tester for the function 'h_ads_Dubinin' and all corresponding functions" + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialTestPure( + final no_coefficients = 6); + + // + // Definition of variables + // + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + + Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Isobaric expansion coefficient of the adsorpt phase"; + + SorpLib.Units.MolarAdsorptionPotential A + "Molar adsorption potential"; + +protected + Medium.ThermodynamicState state_bubble_T_pdT + "State properties of bubble point at T_adsorpt: T + dT"; + Medium.ThermodynamicState state_bubble_T_mdT + "State properties of bubble point at T_adsorpt: T - dT"; + + SorpLib.Units.Uptake x_adsorpt_pdp_T + "Uptake: T_adsorpt and p + dp"; + SorpLib.Units.Uptake x_adsorpt_mdp_T + "Uptake: T_adsorpt and p - dp"; + SorpLib.Units.Uptake x_adsorpt_pdT_p + "Uptake: p_adsorpt and T + dT"; + SorpLib.Units.Uptake x_adsorpt_mdT_p + "Uptake: p_adsorpt and T - dT"; + + Modelica.Units.SI.Pressure p_adsorpt_pdT_x + "Pressure at x_adsorpt and T_adsorpt + dT"; + Modelica.Units.SI.Pressure p_adsorpt_mdT_x + "Pressure at x_adsorpt and T_adsorpt - dT"; + Modelica.Units.SI.Pressure p_adsorpt_pdx_T + "Pressure at T_adsorpt and x_adsorpt + xT"; + Modelica.Units.SI.Pressure p_adsorpt_mdx_T + "Pressure at T_adsorpt and x_adsorpt - xT"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid_pdp + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): p + dp"; + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid_mdp + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): p - dp"; + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid_pdT + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): T + dT"; + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid_mdT + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): T - dT"; + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid_pdT_x + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): x_adsorpt and T + dT"; + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid_mdT_x + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): x_adsorpt and T - dT"; + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid_pdx_T + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): x_adsorpt + dx and T"; + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid_mdx_T + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): x_adsorpt - dx and T"; + + SorpLib.Units.DerSpecificEnthalpyByPressure dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + SorpLib.Units.DerIsobaricExpansionCoefficientByTemperature dbeta_adsorpt_dT + "Partial derivative of isobaric expansion coefficient of the adsorpt phase + w.r.t. temperature at constant pressure"; + + SorpLib.Units.MolarAdsorptionPotential A_pdp_T + "Molar adsorption potential: T_adsorpt p + dp"; + SorpLib.Units.MolarAdsorptionPotential A_mdp_T + "Molar adsorption potential: T_adsorpt and p - dp"; + SorpLib.Units.MolarAdsorptionPotential A_pdT_p + "Molar adsorption potential: p_adsorpt and T + dT"; + SorpLib.Units.MolarAdsorptionPotential A_mdT_p + "Molar adsorption potential: p_adsorpt and T - dT"; + SorpLib.Units.MolarAdsorptionPotential A_pdT_x + "Molar adsorption potential: x_adsorpt and T + dT"; + SorpLib.Units.MolarAdsorptionPotential A_mdT_x + "Molar adsorption potential: x_adsorpt and T - dT"; + SorpLib.Units.MolarAdsorptionPotential A_pdx_T + "Molar adsorption potential: T_adsorpt and x + dx"; + SorpLib.Units.MolarAdsorptionPotential A_mdx_T + "Molar adsorption potential: T_adsorpt and x - dx"; + + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_pdp_T + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + T_adsorpt and p + dp"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_mdp_T + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + T_adsorpt and p + dp"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_pdT_p + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + p_adsorpt and T + dT"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_mdT_p + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + p_adsorpt and T - dT"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_pdT_x + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + x_adsorpt and T + dT"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_mdT_x + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + x_adsorpt and T - dT"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_pdx_T + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + T_adsorpt and x + dx"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_mdx_T + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + T_adsorpt and x + dx"; + +equation + // + // Definition of derivatives + // + der(p_adsorpt) = 0.75 * dc_dT[1] + "Predecsriped slope of p_adsorpt"; + der(T_adsorpt) = 90/20 + "Predecsriped slope of T_adsorpt"; + + // + // Calculate coefficients of the isotherm model + // + c[1] = state_bubble_T.p; + c[2] = state_bubble_T.d; + c[3] = 5.072313e-1 / 1000; + c[4] = 1.305531e2 * 1000 * 0.018; + c[5] = -8.492403e1 * 1000 * 0.018; + c[6] = 4.128962e-3 / 1000; + + c_pdT[1] = sat_T_pdT.psat; + c_pdT[2] = Medium.bubbleDensity(sat=sat_T_pdT); + c_pdT[3] = 5.072313e-1 / 1000; + c_pdT[4] = 1.305531e2 * 1000 * 0.018; + c_pdT[5] = -8.492403e1 * 1000 * 0.018; + c_pdT[6] = 4.128962e-3 / 1000; + + c_mdT[1] = sat_T_mdT.psat; + c_mdT[2] = Medium.bubbleDensity(sat=sat_T_mdT); + c_mdT[3] = 5.072313e-1 / 1000; + c_mdT[4] = 1.305531e2 * 1000 * 0.018; + c_mdT[5] = -8.492403e1 * 1000 * 0.018; + c_mdT[6] = 4.128962e-3 / 1000; + + // + // Calculate partial derivatives of coefficients of the isotherm model w.r.t. + // temperature + // + dc_dT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T); + dc_dT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T) * dc_dT[1]; + dc_dT[3] = 0; + dc_dT[4] = 0; + dc_dT[5] = 0; + dc_dT[6] = 0; + + dc_dT_pdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_pdT); + dc_dT_pdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_pdT) * dc_dT_pdT[1]; + dc_dT_pdT[3] = 0; + dc_dT_pdT[4] = 0; + dc_dT_pdT[5] = 0; + dc_dT_pdT[6] = 0; + + dc_dT_mdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_mdT); + dc_dT_mdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_mdT) * dc_dT_mdT[1]; + dc_dT_mdT[3] = 0; + dc_dT_mdT[4] = 0; + dc_dT_mdT[5] = 0; + dc_dT_mdT[6] = 0; + + // + // Calculate second-order partial derivatives of coefficients of the isotherm + // model w.r.t. temperature + // + ddc_dT_dT[1] = (dc_dT_pdT[1] - dc_dT_mdT[1]) / (2*dT); + ddc_dT_dT[2] = (dc_dT_pdT[2] - dc_dT_mdT[2]) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = 0; + ddc_dT_dT[6] = 0; + + // + // Calculation of state properties + // + state_bubble_T_pdT = Medium.setBubbleState(sat=sat_T_pdT) + "State properties of bubble point at T_adsorpt: T + dT"; + state_bubble_T_mdT = Medium.setBubbleState(sat=sat_T_mdT) + "State properties of bubble point at T_adsorpt: T - dT"; + + // + // Calculate properties + // + x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Uptake"; + + dx_adsorpt_dp = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + h_adsorptiveToLiquid = state_adsorptive_pT.h - state_bubble_T.h + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + dh_adsorptiveToLiquid_dp = 1/state_adsorptive_pT.d * (1 - T_adsorpt * + Medium.isobaricExpansionCoefficient(state=state_adsorptive_pT)) - 0 + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + dh_adsorptiveToLiquid_dT = + Medium.specificHeatCapacityCp(state=state_adsorptive_pT) - + Medium.specificHeatCapacityCp(state=state_bubble_T) + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + beta_adsorpt = Medium.isobaricExpansionCoefficient(state=state_bubble_T) + "Isobaric expansion coefficient of the adsorpt phase"; + dbeta_adsorpt_dT = + (Medium.isobaricExpansionCoefficient(state=state_bubble_T_pdT) - + Medium.isobaricExpansionCoefficient(state=state_bubble_T_mdT)) /(2*dT) + "Partial derivative of the ssobaric expansion coefficient of the adsorpt phase + w.r.t. temperature at constant pressure"; + + A =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + dA_dp =SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + dA_dT =SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT[1]) + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + dW_dA = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dA = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddW_dA_dA( + A=A, + c=c) + "Second-order prtial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + and temperature at constant pressure"; + + h_ads = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + v_adsorpt=1/state_bubble_T.d, + beta_adsorpt=beta_adsorpt, + A=A, + dW_dA=dW_dA) + "Molar adsorption enthalpy"; + + dh_ads_dp_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dp=dh_adsorptiveToLiquid_dp, + v_adsorpt=1/state_bubble_T.d, + dv_adsorpt_dp=0, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dp=0, + dA_dp=dA_dp, + dW_dA=dW_dA, + ddW_dA_dA=ddW_dA_dA) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at + constant temperature"; + dh_ads_dT_p = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + dx_adsorpt_dT=dx_adsorpt_dT, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dT=dh_adsorptiveToLiquid_dT, + v_adsorpt=1/state_bubble_T.d, + dv_adsorpt_dT=-1/state_bubble_T.d^2 * dc_dT[2], + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dT=dbeta_adsorpt_dT, + dA_dT=dA_dT, + dW_dA=dW_dA, + ddW_dA_dT=ddW_dA_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at + constant pressure"; + + // + // Calculate loadings for numerical derivatives + // + x_adsorpt_pdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT( + p_adsorpt=p_adsorpt+dp, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Uptake: T_adsorpt and p + dp"; + x_adsorpt_mdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT( + p_adsorpt=p_adsorpt-dp, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Uptake: p_adsorpt and p - dp"; + + x_adsorpt_pdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt+dT, + c=c_pdT, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Uptake: p_adsorpt and T + dT"; + x_adsorpt_mdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt-dT, + c=c_mdT, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Uptake: p_adsorpt and T - dT"; + + // + // Calculate pressures for numerical derivatives + // + p_adsorpt_pdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt+dT, + c=c_pdT, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt and T_adsorpt + dT"; + p_adsorpt_mdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt-dT, + c=c_mdT, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt and T_adsorpt - dT"; + + p_adsorpt_pdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt+dx, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at T_adsorpt and x_adsorpt + dx"; + p_adsorpt_mdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt-dx, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at T_adsorpt and x_adsorpt - dx"; + + // + // Calculate further properties for numerical derivatives + // + h_adsorptiveToLiquid_pdp = state_adsorptive_pT_pdp.h - state_bubble_T.h + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): p + dp"; + h_adsorptiveToLiquid_mdp = state_adsorptive_pT_mdp.h - state_bubble_T.h + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): p - dp"; + + h_adsorptiveToLiquid_pdT = state_adsorptive_pT_pdT.h - state_bubble_T_pdT.h + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): T + dT"; + h_adsorptiveToLiquid_mdT = state_adsorptive_pT_mdT.h - state_bubble_T_mdT.h + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): T - dT"; + + h_adsorptiveToLiquid_pdT_x = Medium.specificEnthalpy_pT( + p=p_adsorpt_pdT_x, T=T_adsorpt+dT) - state_bubble_T_pdT.h + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): x_adsorpt and T + dT"; + h_adsorptiveToLiquid_mdT_x = Medium.specificEnthalpy_pT( + p=p_adsorpt_mdT_x, T=T_adsorpt-dT) - state_bubble_T_mdT.h + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): x_adsorpt and T - dT"; + + h_adsorptiveToLiquid_pdx_T = Medium.specificEnthalpy_pT( + p=p_adsorpt_pdx_T, T=T_adsorpt) - state_bubble_T.h + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): x_adsorpt + dx and T"; + h_adsorptiveToLiquid_mdx_T = Medium.specificEnthalpy_pT( + p=p_adsorpt_mdx_T, T=T_adsorpt) - state_bubble_T.h + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point): x_adsorpt - dx and T"; + + + A_pdp_T =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt+dp, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential: T_adsorpt p + dp"; + A_mdp_T =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt-dp, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential: T_adsorpt and p - dp"; + + A_pdT_p =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c_pdT[1], + T_adsorpt=T_adsorpt+dT) + "Molar adsorption potential: p_adsorpt and T + dT"; + A_mdT_p =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c_mdT[1], + T_adsorpt=T_adsorpt-dT) + "Molar adsorption potential: p_adsorpt and T - dT"; + + A_pdT_x =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt_pdT_x, + p_sat=c_pdT[1], + T_adsorpt=T_adsorpt+dT) + "Molar adsorption potential: x_adsorpt and T + dT"; + A_mdT_x =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt_mdT_x, + p_sat=c_mdT[1], + T_adsorpt=T_adsorpt-dT) + "Molar adsorption potential: x_adsorpt and T - dT"; + + A_pdx_T =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt_pdx_T, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential: T_adsorpt and x + dx"; + A_mdx_T =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt_mdx_T, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential: T_adsorpt and x - dx"; + + dW_dA_pdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A_pdp_T, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + T_adsorpt and p + dp"; + dW_dA_mdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A_mdp_T, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + T_adsorpt and p + dp"; + + dW_dA_pdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A_pdT_p, + c=c_pdT) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + p_adsorpt and T + dT"; + dW_dA_mdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A_mdT_p, + c=c_mdT) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + p_adsorpt and T + dT"; + + dW_dA_pdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A_pdT_x, + c=c_pdT) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + x_adsorpt and T + dT"; + dW_dA_mdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A_mdT_x, + c=c_mdT) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + x_adsorpt and T + dT"; + + dW_dA_pdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A_pdx_T, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + T_adsorpt and x + dx"; + dW_dA_mdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A_mdx_T, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential: + T_adsorpt and x + dx"; + + // + // Calculate molar adsorption potentials for numerical derivatives + // + h_ads_pdp_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt_pdp_T, + h_adsorptiveToLiquid=h_adsorptiveToLiquid_pdp, + v_adsorpt=1/state_bubble_T.d, + beta_adsorpt=Medium.isobaricExpansionCoefficient(state=state_bubble_T), + A=A_pdp_T, + dW_dA=dW_dA_pdp_T) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: p + dp"; + h_ads_mdp_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt_mdp_T, + h_adsorptiveToLiquid=h_adsorptiveToLiquid_mdp, + v_adsorpt=1/state_bubble_T.d, + beta_adsorpt=Medium.isobaricExpansionCoefficient(state=state_bubble_T), + A=A_mdp_T, + dW_dA=dW_dA_mdp_T) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: p - dp"; + + h_ads_pdT_p = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt+dT, + x_adsorpt=x_adsorpt_pdT_p, + h_adsorptiveToLiquid=h_adsorptiveToLiquid_pdT, + v_adsorpt=1/state_bubble_T_pdT.d, + beta_adsorpt=Medium.isobaricExpansionCoefficient(state=state_bubble_T_pdT), + A=A_pdT_p, + dW_dA=dW_dA_pdT_p) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: T + dT"; + h_ads_mdT_p = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt-dT, + x_adsorpt=x_adsorpt_mdT_p, + h_adsorptiveToLiquid=h_adsorptiveToLiquid_mdT, + v_adsorpt=1/state_bubble_T_mdT.d, + beta_adsorpt=Medium.isobaricExpansionCoefficient(state=state_bubble_T_mdT), + A=A_mdT_p, + dW_dA=dW_dA_mdT_p) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: T - dT"; + + h_ads_pdT_x = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt+dT, + x_adsorpt=x_adsorpt, + h_adsorptiveToLiquid=h_adsorptiveToLiquid_pdT_x, + v_adsorpt=1/state_bubble_T_pdT.d, + beta_adsorpt=Medium.isobaricExpansionCoefficient(state=state_bubble_T_pdT), + A=A_pdT_x, + dW_dA=dW_dA_pdT_x) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt, T+dT) and T_adsorpt: T + dT"; + h_ads_mdT_x = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt-dT, + x_adsorpt=x_adsorpt, + h_adsorptiveToLiquid=h_adsorptiveToLiquid_mdT_x, + v_adsorpt=1/state_bubble_T_mdT.d, + beta_adsorpt=Medium.isobaricExpansionCoefficient(state=state_bubble_T_mdT), + A=A_mdT_x, + dW_dA=dW_dA_mdT_x) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt, T-dT) and T_adsorpt: T - dT"; + + h_ads_pdx_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt+dx, + h_adsorptiveToLiquid=h_adsorptiveToLiquid_pdx_T, + v_adsorpt=1/state_bubble_T.d, + beta_adsorpt=Medium.isobaricExpansionCoefficient(state=state_bubble_T), + A=A_pdx_T, + dW_dA=dW_dA_pdx_T) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt+dx) and T_adsorpt"; + h_ads_mdx_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt-dx, + h_adsorptiveToLiquid=h_adsorptiveToLiquid_mdx_T, + v_adsorpt=1/state_bubble_T.d, + beta_adsorpt=Medium.isobaricExpansionCoefficient(state=state_bubble_T), + A=A_mdx_T, + dW_dA=dW_dA_mdx_T) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt-dx) and T_adsorpt"; + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'h_ads_Dubinin' function and its +partial derivative with resprect to temperature. +<br/><br/> +To see the function behavior, plot the variables <i>h_ads_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_h_ads_Dubinin; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/Test_h_ads_clausiusClapeyron.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/Test_h_ads_clausiusClapeyron.mo new file mode 100644 index 0000000000000000000000000000000000000000..374443fcc98a9fa743717512b148331de9b57286 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/Test_h_ads_clausiusClapeyron.mo @@ -0,0 +1,430 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.Testers; +model Test_h_ads_clausiusClapeyron + "Tester for the function 'h_ads_clausiusClapeyron' and all corresponding functions" + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialTestPure( + final no_coefficients = 6); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt_pdT_x + "Pressure at x_adsorpt and T_adsorpt + dT"; + Modelica.Units.SI.Pressure p_adsorpt_mdT_x + "Pressure at x_adsorpt and T_adsorpt - dT"; + + Modelica.Units.SI.Pressure p_adsorpt_pdx_T + "Pressure at T_adsorpt and x_adsorpt + xT"; + Modelica.Units.SI.Pressure p_adsorpt_mdx_T + "Pressure at T_adsorpt and x_adsorpt - xT"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_pdT_p + "Partial derivative of uptake w.r.t. pressure at constant temperature: T + dT"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_mdT_p + "Partial derivative of uptake w.r.t. pressure at constant temperature: T - dT"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_pdp_T + "Partial derivative of uptake w.r.t. pressure at constant temperature: p + dp"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_mdp_T + "Partial derivative of uptake w.r.t. pressure at constant temperature: p - dp"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_pdT_x + "Partial derivative of uptake w.r.t. pressure at constant temperature: x_adsorpt + and T + dT"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_mdT_x + "Partial derivative of uptake w.r.t. pressure at constant temperature: x_adsorpt + and T - dT"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_pdx_T + "Partial derivative of uptake w.r.t. pressure at constant temperature: x + dx"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_mdx_T + "Partial derivative of uptake w.r.t. pressure at constant temperature: x - dx"; + + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_pdT_p + "Partial derivative of uptake w.r.t. temperature at constant pressure: T + dT"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_mdT_p + "Partial derivative of uptake w.r.t. temperature at constant pressure: T - dT"; + + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_pdp_T + "Partial derivative of uptake w.r.t. temperature at constant pressure: p + dp"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_mdp_T + "Partial derivative of uptake w.r.t. temperature at constant pressure: p - dp"; + + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_pdT_x + "Partial derivative of uptake w.r.t. temperature at constant pressure: x_adsorpt + and T + dT"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_mdT_x + "Partial derivative of uptake w.r.t. temperature at constant pressure: x_adsorpt + and T - dT"; + + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_pdx_T + "Partial derivative of uptake w.r.t. temperature at constant pressure: x + dx"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_mdx_T + "Partial derivative of uptake w.r.t. temperature at constant pressure: x - dx"; + +equation + // + // Definition of derivatives + // + der(p_adsorpt) = 0.75 * dc_dT[1] + "Predecsriped slope of p_adsorpt"; + der(T_adsorpt) = 90/20 + "Predecsriped slope of T_adsorpt"; + + // + // Calculate coefficients of the isotherm model + // + c[1] = state_bubble_T.p; + c[2] = state_bubble_T.d; + c[3] = 5.072313e-1 / 1000; + c[4] = 1.305531e2 * 1000 * 0.018; + c[5] = -8.492403e1 * 1000 * 0.018; + c[6] = 4.128962e-3 / 1000; + + c_pdT[1] = sat_T_pdT.psat; + c_pdT[2] = Medium.bubbleDensity(sat=sat_T_pdT); + c_pdT[3] = 5.072313e-1 / 1000; + c_pdT[4] = 1.305531e2 * 1000 * 0.018; + c_pdT[5] = -8.492403e1 * 1000 * 0.018; + c_pdT[6] = 4.128962e-3 / 1000; + + c_mdT[1] = sat_T_mdT.psat; + c_mdT[2] = Medium.bubbleDensity(sat=sat_T_mdT); + c_mdT[3] = 5.072313e-1 / 1000; + c_mdT[4] = 1.305531e2 * 1000 * 0.018; + c_mdT[5] = -8.492403e1 * 1000 * 0.018; + c_mdT[6] = 4.128962e-3 / 1000; + + // + // Calculate partial derivatives of coefficients of the isotherm model w.r.t. + // temperature + // + dc_dT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T); + dc_dT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T) * dc_dT[1]; + dc_dT[3] = 0; + dc_dT[4] = 0; + dc_dT[5] = 0; + dc_dT[6] = 0; + + dc_dT_pdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_pdT); + dc_dT_pdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_pdT) * dc_dT_pdT[1]; + dc_dT_pdT[3] = 0; + dc_dT_pdT[4] = 0; + dc_dT_pdT[5] = 0; + dc_dT_pdT[6] = 0; + + dc_dT_mdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_mdT); + dc_dT_mdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_mdT) * dc_dT_mdT[1]; + dc_dT_mdT[3] = 0; + dc_dT_mdT[4] = 0; + dc_dT_mdT[5] = 0; + dc_dT_mdT[6] = 0; + + // + // Calculate second-order partial derivatives of coefficients of the isotherm + // model w.r.t. temperature + // + ddc_dT_dT[1] = (dc_dT_pdT[1] - dc_dT_mdT[1]) / (2*dT); + ddc_dT_dT[2] = (dc_dT_pdT[2] - dc_dT_mdT[2]) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = 0; + ddc_dT_dT[6] = 0; + + // + // Calculate properties + // + x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Uptake"; + + dx_adsorpt_dp = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + h_ads = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar adsorption enthalpy"; + + dh_ads_dp_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at + constant temperature"; + dh_ads_dT_p = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at + constant pressure"; + + // + // Calculate pressures for numerical derivatives + // + p_adsorpt_pdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt+dT, + c=c_pdT, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt and T_adsorpt + dT"; + p_adsorpt_mdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt-dT, + c=c_mdT, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt and T_adsorpt - dT"; + + p_adsorpt_pdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt+dx, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at T_adsorpt and x_adsorpt + dx"; + p_adsorpt_mdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT( + x_adsorpt=x_adsorpt-dx, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at T_adsorpt and x_adsorpt - dx"; + + // + // Calculate partial derivatives of uptake w.r.t. pressure at constant temperature + // for numerical derivatives + // + dx_adsorpt_dp_pdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt+dp, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature: p + dp"; + dx_adsorpt_dp_mdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt-dp, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature: p - dp"; + + dx_adsorpt_dp_pdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt+dT, + c=c_pdT) + "Partial derivative of uptake w.r.t. pressure at constant temperature: T + dT"; + dx_adsorpt_dp_mdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt-dT, + c=c_mdT) + "Partial derivative of uptake w.r.t. pressure at constant temperature: T - dT"; + + dx_adsorpt_dp_pdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt_pdT_x, + T_adsorpt=T_adsorpt+dT, + c=c_pdT) + "Partial derivative of uptake w.r.t. pressure at constant temperature: x_adsorpt + and T + dT"; + dx_adsorpt_dp_mdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt_mdT_x, + T_adsorpt=T_adsorpt-dT, + c=c_mdT) + "Partial derivative of uptake w.r.t. pressure at constant temperature: x_adsorpt + and T - dT"; + + dx_adsorpt_dp_pdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt_pdx_T, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature: T_adsorpt + and x + dx"; + dx_adsorpt_dp_mdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt_mdx_T, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature: T_adsorpt + and x - dx"; + + // + // Calculate partial derivatives of uptake w.r.t. temperature at constant pressure + // for numerical derivatives + // + dx_adsorpt_dT_pdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt+dp, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: p + dp"; + dx_adsorpt_dT_mdp_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt-dp, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: p - dp"; + + dx_adsorpt_dT_pdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt+dT, + c=c_pdT, + dc_dT_adsorpt=dc_dT_pdT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: T + dT"; + dx_adsorpt_dT_mdT_p = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt-dT, + c=c_mdT, + dc_dT_adsorpt=dc_dT_mdT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: T - dT"; + + dx_adsorpt_dT_pdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt_pdT_x, + T_adsorpt=T_adsorpt+dT, + c=c_pdT, + dc_dT_adsorpt=dc_dT_pdT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: x_adsorpt + and T + dT"; + dx_adsorpt_dT_mdT_x = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt_mdT_x, + T_adsorpt=T_adsorpt-dT, + c=c_mdT, + dc_dT_adsorpt=dc_dT_mdT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: x_adsorpt + and T - dT"; + + dx_adsorpt_dT_pdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt_pdx_T, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: T_adsorpt + and x + dx"; + dx_adsorpt_dT_mdx_T = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt_mdx_T, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure: T_adsorpt + and x - dx"; + + // + // Calculate molar adsorption potentials for numerical derivatives + // + h_ads_pdp_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt+dp, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp_pdp_T, + dx_adsorpt_dT=dx_adsorpt_dT_pdp_T) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: p + dp"; + h_ads_mdp_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt-dp, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp_mdp_T, + dx_adsorpt_dT=dx_adsorpt_dT_mdp_T) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: p - dp"; + + h_ads_pdT_p = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt+dT, + dx_adsorpt_dp=dx_adsorpt_dp_pdT_p, + dx_adsorpt_dT=dx_adsorpt_dT_pdT_p) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: T + dT"; + h_ads_mdT_p = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt-dT, + dx_adsorpt_dp=dx_adsorpt_dp_mdT_p, + dx_adsorpt_dT=dx_adsorpt_dT_mdT_p) + "Molar adsorption enthalpy at p_adsorpt and T_adsorpt: T - dT"; + + h_ads_pdT_x = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt_pdT_x, + T_adsorpt=T_adsorpt+dT, + dx_adsorpt_dp=dx_adsorpt_dp_pdT_x, + dx_adsorpt_dT=dx_adsorpt_dT_pdT_x) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt, T+dT) and T_adsorpt: T + dT"; + h_ads_mdT_x = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt_mdT_x, + T_adsorpt=T_adsorpt-dT, + dx_adsorpt_dp=dx_adsorpt_dp_mdT_x, + dx_adsorpt_dT=dx_adsorpt_dT_mdT_x) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt, T-dT) and T_adsorpt: T - dT"; + + h_ads_pdx_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt_pdx_T, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp_pdx_T, + dx_adsorpt_dT=dx_adsorpt_dT_pdx_T) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt+dx) and T_adsorpt"; + h_ads_mdx_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt_mdx_T, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp_mdx_T, + dx_adsorpt_dT=dx_adsorpt_dT_mdx_T) + "Molar adsorption enthalpy at p_adsorpt(x_adsorpt-dx) and T_adsorpt"; + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'h_ads_ClausiusClaperon' function and its +partial derivative with resprect to temperature. +<br/><br/> +To see the function behavior, plot the variables <i>h_ads_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_h_ads_clausiusClapeyron; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/package.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a8441be4ba0198457856719b323ca6803416b693 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents; +package Testers "Models to test and varify functions for sorption enthalpies for pure components" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions and models of the +'PureComponents' package. The test models check the implementation of the functions +and models and enable verification of their behavior. In addition, the test models +demonstrate the functions' and models' general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/package.order b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..037c8aec433721ffb9e5bcdfe4b43254d35229ba --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/Testers/package.order @@ -0,0 +1,3 @@ +Test_h_ads +Test_h_ads_clausiusClapeyron +Test_h_ads_Dubinin diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dT.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..f456727776ea0041cc55f5b51a33543ebb92c3b7 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dT.mo @@ -0,0 +1,79 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents; +function dh_ads_dT + "Partial derivative of molar adsorption w.r.t. temperature at constant pressure" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialPure_dh_ads_dT; + + input Modelica.Units.SI.SpecificVolume v_adsorptive + "Specific volume of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorptive_dT + "Partial derivative of specific volume of the adsorptive w.r.t. temperature + at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + dh_ads_dT := + (M_adsorptive * (v_adsorptive - v_adsorpt) * + (-dx_adsorpt_dT / dx_adsorpt_dp)) + + (T_adsorpt * M_adsorptive * + (-dx_adsorpt_dT / dx_adsorpt_dp)) * dv_adsorptive_dT + + (-T_adsorpt * M_adsorptive * + (-dx_adsorpt_dT / dx_adsorpt_dp)) * dv_adsorpt_dT + + (T_adsorpt * M_adsorptive * (v_adsorptive - v_adsorpt) * + (-1 / dx_adsorpt_dp)) * ddx_adsorpt_dT_dT + + (T_adsorpt * M_adsorptive * (v_adsorptive - v_adsorpt) * + (dx_adsorpt_dT / dx_adsorpt_dp^2)) * ddx_adsorpt_dp_dT + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'h_ads' with respect to +the temperature at constant pressure. For full details of the original function +'h_ads,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads\">SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_ads_dT; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dT_Dubinin.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dT_Dubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..986bfb4a31dbdf20d5d30a1fc9a04fdaaa9b8240 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dT_Dubinin.mo @@ -0,0 +1,92 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents; +function dh_ads_dT_Dubinin + "Partial derivative of molar adsorption enthalpy according to the model of Dubinin w.r.t. temperature at constant pressure" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialPure_dh_ads_dT; + + input SorpLib.Units.Uptake x_adsorpt + "Uptake" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.SpecificHeatCapacity dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Isobaric expansion coefficient of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerIsobaricExpansionCoefficientByTemperature dbeta_adsorpt_dT + "Partial derivative of isobaric expansion coefficient of the adsorpt phase + w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT + "Second-order partial derivative of filled pore volume w.r.t. molar + adsorption potential and temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + dh_ads_dT := + (M_adsorptive) * dh_adsorptiveToLiquid_dT + + (1) * dA_dT + + (-beta_adsorpt * v_adsorpt * x_adsorpt / dW_dA) * 1 + + (-T_adsorpt * v_adsorpt * x_adsorpt / dW_dA) * dbeta_adsorpt_dT + + (-beta_adsorpt * T_adsorpt * x_adsorpt / dW_dA) * dv_adsorpt_dT + + (-beta_adsorpt * T_adsorpt * v_adsorpt / dW_dA) * dx_adsorpt_dT + + (beta_adsorpt * T_adsorpt * v_adsorpt * x_adsorpt / dW_dA^2) * ddW_dA_dT + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at + constant pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'h_ads_Dubinin' +with respect to the temperature at constant pressure. For full details +of the original function 'h_ads_Dubinin,' check the documentation of the +function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin\">SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_ads_dT_Dubinin; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dT_clausiusClapeyron.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dT_clausiusClapeyron.mo new file mode 100644 index 0000000000000000000000000000000000000000..3fa57dc98fe1093924653606131838c0d6392a11 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dT_clausiusClapeyron.mo @@ -0,0 +1,59 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents; +function dh_ads_dT_clausiusClapeyron + "Partial derivative of molar adsorption enthalpy according to Clausius Clapeyron w.r.t. temperature at constant pressure" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialPure_dh_ads_dT; + + input SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + dh_ads_dT := + (2 * Modelica.Constants.R * T_adsorpt / p_adsorpt * + (-dx_adsorpt_dT / dx_adsorpt_dp)) + + (Modelica.Constants.R * T_adsorpt^2 / p_adsorpt * (-1 / dx_adsorpt_dp)) * + ddx_adsorpt_dT_dT + + (Modelica.Constants.R * T_adsorpt^2 / p_adsorpt * + (dx_adsorpt_dT / dx_adsorpt_dp^2)) * ddx_adsorpt_dp_dT + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at + constant pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'h_ads_clausiusClapeyron' +with respect to the temperature at constant pressure. For full details of the +original function 'h_ads_clausiusClapeyron,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron\">SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_ads_dT_clausiusClapeyron; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dp.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..7592fbef7fbf63519eab2e0d648b165f4981cc6b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dp.mo @@ -0,0 +1,77 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents; +function dh_ads_dp + "Partial derivative of molar adsorption w.r.t. pressure at constant temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialPure_dh_ads_dp; + + input Modelica.Units.SI.SpecificVolume v_adsorptive + "Specific volume of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerSpecificVolumeByPressure dv_adsorptive_dp + "Partial derivative of specific volume of the adsorptive w.r.t. pressure + at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + dh_ads_dp := + (T_adsorpt * M_adsorptive * + (-dx_adsorpt_dT / dx_adsorpt_dp)) * dv_adsorptive_dp + + (-T_adsorpt * M_adsorptive * + (-dx_adsorpt_dT / dx_adsorpt_dp)) * dv_adsorpt_dp + + (T_adsorpt * M_adsorptive * (v_adsorptive - v_adsorpt) * + (-1 / dx_adsorpt_dp)) * ddx_adsorpt_dp_dT + + (T_adsorpt * M_adsorptive * (v_adsorptive - v_adsorpt) * + (dx_adsorpt_dT / dx_adsorpt_dp^2)) * ddx_adsorpt_dp_dp + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'h_ads' with respect to +the pressure at constant temperature. For full details of the original function +'h_ads,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads\">SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_ads_dp; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dp_Dubinin.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dp_Dubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..39c0173038b0ecb79e8ba9aea94913ecf1a333b5 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dp_Dubinin.mo @@ -0,0 +1,91 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents; +function dh_ads_dp_Dubinin + "Partial derivative of molar adsorption enthalpy according to the model of Dubinin w.r.t. pressure at constant temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialPure_dh_ads_dp; + + input SorpLib.Units.Uptake x_adsorpt + "Uptake" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerSpecificEnthalpyByPressure dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Isobaric expansion coefficient of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerIsobaricExpansionCoefficientByPressure dbeta_adsorpt_dp + "Partial derivative of isobaric expansion coefficient of the adsorpt phase + w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA + "Second-order partial derivative of filled pore volume w.r.t. molar + adsorption potential and temperature at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + dh_ads_dp := + (M_adsorptive) * dh_adsorptiveToLiquid_dp + + (1) * dA_dp + + (-T_adsorpt * v_adsorpt * x_adsorpt / dW_dA) * dbeta_adsorpt_dp + + (-beta_adsorpt * T_adsorpt * x_adsorpt / dW_dA) * dv_adsorpt_dp + + (-beta_adsorpt * T_adsorpt * v_adsorpt / dW_dA) * dx_adsorpt_dp + + (beta_adsorpt * T_adsorpt * v_adsorpt * x_adsorpt / dW_dA^2) * ddW_dA_dA * dA_dp + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at + constant temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'h_ads_Dubinin' +with respect to the pressure at constant temperature. For full details +of the original function 'h_ads_Dubinin,' check the documentation of the +function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin\">SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_ads_dp_Dubinin; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dp_clausiusClapeyron.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dp_clausiusClapeyron.mo new file mode 100644 index 0000000000000000000000000000000000000000..a437b9c0c2fb85caf2b96798813121e8c29207ea --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/dh_ads_dp_clausiusClapeyron.mo @@ -0,0 +1,59 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents; +function dh_ads_dp_clausiusClapeyron + "Partial derivative of molar adsorption enthalpy according to Clausius Clapeyron w.r.t. pressure at constant temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialPure_dh_ads_dp; + + input SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + dh_ads_dp := + (-Modelica.Constants.R * T_adsorpt^2 / p_adsorpt^2 * + (-dx_adsorpt_dT / dx_adsorpt_dp)) + + (Modelica.Constants.R * T_adsorpt^2 / p_adsorpt * (-1 / dx_adsorpt_dp)) * + ddx_adsorpt_dp_dT + + (Modelica.Constants.R * T_adsorpt^2 / p_adsorpt * + (dx_adsorpt_dT / dx_adsorpt_dp^2)) * ddx_adsorpt_dp_dp + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at + constant temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'h_ads_clausiusClapeyron' +with respect to the pressure at constant temperature. For full details of the +original function 'h_ads_clausiusClapeyron,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron\">SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_ads_dp_clausiusClapeyron; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/h_ads.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/h_ads.mo new file mode 100644 index 0000000000000000000000000000000000000000..638744dc3a0e23e6e4440accecb72c81c021e62f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/h_ads.mo @@ -0,0 +1,93 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents; +function h_ads + "Molar adsorption enthalpy" + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialPure_h_ads; + + input Modelica.Units.SI.SpecificVolume v_adsorptive + "Specific volume of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + h_ads := T_adsorpt * M_adsorptive * (v_adsorptive - v_adsorpt) * + (-dx_adsorpt_dT / dx_adsorpt_dp) + "Molar adsorption enthalpy"; + + // + // Annotations + // + annotation (Inline=true, +Documentation(info="<html> +<p> +This function calculates the molar adsorption enthalpy. +</p> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads</sub></i> is defined as difference +of the specific enthalpy of the gas/vapor phase <i>h<sub>adsorptive</sub></i> and the +adsorpt phase <i>h<sub>adsorpt</sub></i>: +</p> +<pre> + Δh<sub>ads</sub> = h<sub>adsorptive</sub> - h<sub>adsorpt</sub> = T * M<sub>adsorptive</sub> * (v<sub>adsorptive</sub> - v<sub>adsorpt</sub>) (dp/dT) ≈ T * M<sub>adsorptive</sub> * (v<sub>adsorptive</sub> - v<sub>adsorpt</sub>) * (-(∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub>); +</pre> +<p> +Herein, <i>M<sub>adsorptive</sub></i> is the molar mass of the adsorptive, <i>T</i> +is the temperature, <i>v<sub>adsorptive</sub></i> ist the specific volume of the +adsorptive, <i>v<sub>adsorpt</sub></i> ist the specific volume of the adsorpt, +<i>dx/dp</i> is the partial derivative of the uptake with respect to the pressure +at constant temperature, and <i>dx/dT</i> is the partial derivative of the uptake +with respect to the temperature at constant pressure. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Inert sorbent. + </li> + <li> + Neglecting the term <i>(∂p/∂x)<sub>T</sub> * (dx/dp)</i> of term + <i>dp/dT = -(∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub> + + (∂p/∂x)<sub>T</sub> * + (dx/dp)</i>. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Chakraborty, A. and Saha, B.B. and Ng, K.C. and Koyama (2006). On the thermodynamic modeling of the isosteric heat of adsorption and comparison with experiments, Applied Physics Letters, 89:171901. DOI: http://doi.org/10.1063/1.2360925. + </li> + <li> + Chakraborty, A. and Saha, B.B. and Ng, K.C. and Koyama, S. and Srinivasan, K. (2009). Theoretical Insight of Physical Adsorption for a Single-Component Adsorbent + Adsorbate System: I. Thermodynamic Property Surfaces, Langmuir, 25:2204-221. DOI: http://doi.org/10.1021/la803289p. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end h_ads; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/h_ads_Dubinin.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/h_ads_Dubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..8afa6f7c4156728e79c9cb3987f3050e126e6958 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/h_ads_Dubinin.mo @@ -0,0 +1,93 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents; +function h_ads_Dubinin + "Molar adsorption enthalpy according to the model of Dubinin" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialPure_h_ads; + input SorpLib.Units.Uptake x_adsorpt + "Uptake" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Isobaric expansion coefficient of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.MolarAdsorptionPotential A + "Molar adsorption potential" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + h_ads := M_adsorptive * h_adsorptiveToLiquid + A - + beta_adsorpt * T_adsorpt * v_adsorpt * x_adsorpt / dW_dA + "Molar adsorption enthalpy"; + + // + // Annotations + // + annotation (Inline=true, +Documentation(info="<html> +<p> +This function calculates the molar adsorption enthalpy according to the model of +Dubinin. +</p> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads</sub></i> is defined as difference +of the specific enthalpy of the gas/vapor phase <i>h<sub>adsorptive</sub></i> and the +adsorpt phase <i>h<sub>adsorpt</sub></i>: +</p> +<pre> + Δh<sub>ads</sub> = h<sub>adsorptive</sub> - h<sub>adsorpt</sub> = M<sub>adsorptive</sub> * Δh<sub>adsorptiveToLiquid</sub> + A - β * T * v<sub>adsorpt</sub> * x * 1 / (∂W/∂A)<sub>p,T</sub>; +</pre> +<p> +Herein, <i>M<sub>adsorptive</sub></i> is the molar mass of the adsorptive, <i>T</i> +is the temperature, <i>x</i> is the uptake, <i>v<sub>adsorpt</sub></i> is the specific +volume of the adsorpt, <i>β</i> is the isobaric expansion coefficient of the +adsorpt, <i>Δh<sub>adsorptiveToLiquid</sub></i> is the specific enthalpy difference +between adsorptive phase and saturated liquid phase (i.e., bubble point), <i>A</i> is +the molar adsorption potential, and <i>(∂W/∂A)<sub>p,T</sub></i> is the partial +derivative of the filled pore volume with respect to the molar adsorption potential at +constant pressure and temperature. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Inert sorbent. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Schwamberger, V. (2016). Thermodynamic and numerical investigation of a novel sorption cycle for application in adsorption heat pumps and chillers (in German), PhD thesis, Karlsruhe. +</ul> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end h_ads_Dubinin; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/h_ads_clausiusClapeyron.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/h_ads_clausiusClapeyron.mo new file mode 100644 index 0000000000000000000000000000000000000000..844e3accfca3ff05885b69d174335192a0d71231 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/h_ads_clausiusClapeyron.mo @@ -0,0 +1,82 @@ +within SorpLib.Media.Functions.SorptionEnthalpies.PureComponents; +function h_ads_clausiusClapeyron + "Molar adsorption enthalpy according to Clausius Clapeyron" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SorptionEnthalpies.BasesClasses.PartialPure_h_ads; + + input SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + h_ads := Modelica.Constants.R * T_adsorpt^2 / p_adsorpt * + (-dx_adsorpt_dT / dx_adsorpt_dp) + "Molar adsorption enthalpy"; + + // + // Annotations + // + annotation (Inline=true, +Documentation(info="<html> +<p> +This function calculates the molar adsorption enthalpy according to Clausius +Clapeyron assumptions. +</p> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads</sub></i> is defined as difference +of the specific enthalpy of the gas/vapor phase <i>h<sub>adsorptive</sub></i> and the +adsorpt phase <i>h<sub>adsorpt</sub></i>: +</p> +<pre> + Δh<sub>ads</sub> = h<sub>adsorptive</sub> - h<sub>adsorpt</sub> = R * T<sup>2</sup> / p * (∂p/∂T)<sub>x</sub> = R * T<sup>2</sup> / p * (-(∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub>); +</pre> +<p> +Herein, <i>R</i> is the ideal gas constant, <i>p</i> is the pressure, <i>T</i> is +the temperature, <i>(∂x/∂p)<sub>T</sub></i> is the partial derivative of +the uptake with respect to the pressure at constant temperature, and +<i>(∂x/∂T)<sub>p</sub></i> is the partial derivative of the uptake with +respect to the temperature at constant pressure. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The specific volume of the adsorpt phase can be neglected compared to the specific + volume of the adsorptive phase. + </li> + <li> + The adsorptive can be treated as an ideal gas (i.e., p * V = n * R * T). + </li> + <li> + Inert sorbent. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 17, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end h_ads_clausiusClapeyron; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/package.mo b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..011f70beca07fe8d0c8d1427d5cdd4e428d130e0 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/package.mo @@ -0,0 +1,34 @@ +within SorpLib.Media.Functions.SorptionEnthalpies; +package PureComponents "Functions required to calculate sorption enthalpies for pure components" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains models to calculate sorption enthalpies for pure component +adsorption. +</p> + +<h4>Implemented functions for each sorption enthalpy model</h4> +<p> +The following functions are provided for each sorption enthalpy model: +</p> +<ul> + <li> + Sorption enthalpy. + </li> + <li> + Partial derivative of sorption enthalpy w.r.t. pressure at constant temperature. + </li> + <li> + Partial derivative of sorption enthalpy w.r.t. temperature at constant pressure. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PureComponents; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/package.order b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c16ccf94b51549564443750a7d4c9133a8d5d326 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/PureComponents/package.order @@ -0,0 +1,10 @@ +h_ads +dh_ads_dp +dh_ads_dT +h_ads_clausiusClapeyron +dh_ads_dp_clausiusClapeyron +dh_ads_dT_clausiusClapeyron +h_ads_Dubinin +dh_ads_dp_Dubinin +dh_ads_dT_Dubinin +Testers diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/package.mo b/SorpLib/Media/Functions/SorptionEnthalpies/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..037845ee310fd95fdd6cafdc0477a09954f11f08 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.Functions; +package SorptionEnthalpies "Functions required to calculate sorption enthalpies" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains sorption enthalpy models for pure component and multi-component +adsorption. Please check the documentation of the individual packages for more +details on the implemented sorption enthalpy models . +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end SorptionEnthalpies; diff --git a/SorpLib/Media/Functions/SorptionEnthalpies/package.order b/SorpLib/Media/Functions/SorptionEnthalpies/package.order new file mode 100644 index 0000000000000000000000000000000000000000..34e1288134a63c553830f5bb2adfd6b4da967156 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEnthalpies/package.order @@ -0,0 +1,3 @@ +BasesClasses +PureComponents +MultiComponents diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti.mo new file mode 100644 index 0000000000000000000000000000000000000000..b0b1ce04dee5d60e5fdb05db52f0b788bfba393d --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti.mo @@ -0,0 +1,52 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMulti + "Base function for isotherm models of multi components" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real[:,:] c + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_threshold_min = 0 + "Threshold for partial pressures of all components: If a partial pressure is + below the threshold, its value is set to the threshold" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of multi components. Such models can be extended pure component +isotherm models or specifically developed multi component isotherm models. +<br/><br/> +This partial function defines the equilibrium temperature <i>T_adsorpt</i> and the +coefficients of the isotherm model <i>c</i> as inputs. The coefficients of the +isotherm model <i>c</i> are a matrix: The columns contain the coefficients of the +different components. The rows contain the actual coefficients, i.e, the row size +depends on the selected isotherm model. Different components may require different +numbers of coefficients, which is why the row size depends on the component with +the most coefficients. The coefficients of the isotherm model <i>c</i> may depend +on the equilibrium temperature <i>T_adsorpt</i>. Optional input regarding numerics +is the threshold <i>p_threshold_min</i> to regulate the minimal values of all +partial pressures. +<br/><br/> +Functions that inherit properties from this partial function may have to +implement further inputs, the output, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialMulti; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST.mo new file mode 100644 index 0000000000000000000000000000000000000000..05001960caf77b27556025a851ae7ebb215c545b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST.mo @@ -0,0 +1,115 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMultiIAST + "Base function for isotherm models based on the ideal adsorbed solution theory" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.MolarMass[:] M_i + "Molar masses of the components" + annotation (Dialog(tab="General", group="Inputs - Components")); + input Real[:] c_1 + "Coefficients of the isotherm model of the first component" + annotation (Dialog(tab="General", group="Inputs - Components")); + input Real[:] c_2 + "Coefficients of the isotherm model of the second component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_1 + "Uptake of the first component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_1 + "Pressure of the first component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_1 + "Partial derivative of the uptake of the first component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_1 + "Reduced spreading pressure of the first component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_1 + "Pressure of the first component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_2 + "Uptake of the second component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_2 + "Pressure of the second component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_2 + "Partial derivative of the uptake of the second component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_2 + "Reduced spreading pressure of the second component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_2 + "Pressure of the second component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST num + "Record definining numerics of the IAST algorithms" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_1 + "Record definining numerics of the first component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_2 + "Record definining numerics of the second component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models based on +the ideal adsorbed solution theory (IAST) describing the adsorption of multi +components. +<br/><br/> +This partial function defines the equilibrium temperature <i>T_adsorpt</i>, the +molar masses <i>M_i</i>, and the coefficients of the isotherm model of the first +component <i>c_1</i> and second component <i>c_2</i> as inputs. The coefficients +of the isotherm model <i>c_i</i> may depend on the equilibrium temperature <i>T_adsorpt</i>. +Further inputs are functions describing the pure component isotherm models. These +functional arguments are <i>func_x_pT_1</i>, <i>func_p_xT_1</i>, <i>func_dx_dp_1</i>, +<i>func_pi_pT_1</i>, and <i>func_p_piT_1</i> for component 1 (i.e., <i>i = 1</i>) and +2 (i.e., <i>i = 2</i>). Optional input regarding numerics define the setup of the +IAST algorithm <i>num</i> and the pure component isotherm models <i>num_comp_i</i>. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs, the output, and the function algorithm. Further inputs are +particulary required when developing IAST functions for more than two components. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialMultiIAST; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_dx_dT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_dx_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..da669c1b850e04a6655f362c76e6b98341564998 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_dx_dT.mo @@ -0,0 +1,89 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMultiIAST_dx_dT + "Base function for isotherm models based on the ideal adsorbed solution theory: Partial derivative of uptakes w.r.t. temperature at contsant pressure and mole fractions" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Real[size(c_1,1)] c_pdT_1 + "Coefficients of the isotherm model of the first component: T + dT" + annotation (Dialog(tab="General", group="Inputs - Components")); + input Real[size(c_1,1)] c_mdT_1 + "Coefficients of the isotherm model of the first component: T - dT" + annotation (Dialog(tab="General", group="Inputs - Components")); + input Real[size(c_2,1)] c_pdT_2 + "Coefficients of the isotherm model of the second component: T + dT" + annotation (Dialog(tab="General", group="Inputs - Components")); + input Real[size(c_2,1)] c_mdT_2 + "Coefficients of the isotherm model of the second component: T - dT" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input Modelica.Units.SI.TemperatureDifference dT = 1e-4 + "Temperature difference used to calculate partial derivatives w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + + // + // Definition of outputs + // + output + SorpLib.Units.DerUptakeByMolarFraction[size(M_i,1)] dx_adsorpt_dT_adsorpt + "Partial derivatives of the uptakes w.r.t. the temperature at contsant pressure + and mole fractions" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models based on +the ideal adsorbed solution theory (IAST) describing the adsorption of multi +components. +<br/><br/> +This partial function is the basic function for calculating the partial derivative +in of the equilibrium uptakes w.r.t. the temperature at contsant pressure and mole +fractions <i>dx_adsorpt_dT</i> as a function of the equilibrium pressure <i>p_adsorpt</i>, +the mole fractions of the independent components in the gas or vapor phase <i>y_i</i>, +the equilibrium temperature <i>T_adsorpt</i>. Further inputs are the coefficients +of the isotherm model of the first component <i>c_1</i> and second component +<i>c_2</i>. The coefficients of the isotherm model <i>c_i</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Further inputs are functions describing +the pure component isotherm models. These functional arguments are <i>func_x_pT_1</i>, +<i>func_p_xT_1</i>, <i>func_dx_dp_1</i>, <i>func_pi_pT_1</i>, and <i>func_p_piT_1</i> +for component 1 (i.e., <i>i = 1</i>) and 2 (i.e., <i>i = 2</i>). Optional input +regarding numerics define the setup of the IAST algorithm <i>num</i>, the pure +component isotherm models <i>num_comp_i</i>, and the infinitesimal difference +<i>dT</i> to calculate the partial derivatives. +<br/><br/> +The partial derivatives of the equilibrium uptakes w.r.t. the temperature at contsant +pressure and mole fractions <i>dx_adsorpt_dT</i> are defined as the outputs. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. Further inputs are particulary required +when developing IAST functions for more than two components. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialMultiIAST_dx_dT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_dx_dp.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_dx_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..9284d04b5b69608ee8e940625a7d06c60945638e --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_dx_dp.mo @@ -0,0 +1,76 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMultiIAST_dx_dp + "Base function for isotherm models based on the ideal adsorbed solution theory: Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.PressureDifference dp = 1e-4 + "Pressure difference used to calculate partial derivatives w.r.t. pressure" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + + // + // Definition of outputs + // + output SorpLib.Units.DerUptakeByPressure[size(M_i,1)] dx_adsorpt_dp_adsorpt + "Partial derivatives of the uptakes w.r.t. pressure at constant mole fractions + and temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models based on +the ideal adsorbed solution theory (IAST) describing the adsorption of multi +components. +<br/><br/> +This partial function is the basic function for calculating the partial derivative +of the equilibrium uptakes w.r.t. the equilibrium uptake at constant mole fractions +and temperature <i>dx_adsorpt_dp_adsorpt</i> as a function of the equilibrium +pressure <i>p_adsorpt</i>, the mole fractions of the independent components in +the gas or vapor phase <i>y_i</i>, the equilibrium temperature <i>T_adsorpt</i>. +Further inputs are the coefficients of the isotherm model of the first component +<i>c_1</i> and second component <i>c_2</i>. The coefficients of the isotherm model +<i>c_i</i> may depend on the equilibrium temperature <i>T_adsorpt</i>. Further +inputs are functions describing the pure component isotherm models. These functional +arguments are <i>func_x_pT_1</i>, <i>func_p_xT_1</i>, <i>func_dx_dp_1</i>, +<i>func_pi_pT_1</i>, and <i>func_p_piT_1</i> for component 1 (i.e., <i>i = 1</i>) +and 2 (i.e., <i>i = 2</i>). Optional input regarding numerics define the setup of +the IAST algorithm <i>num</i>, the pure component isotherm models <i>num_comp_i</i>, +and the infinitesimal difference <i>dp</i> to calculate the partial derivatives. +<br/><br/> +The partial derivatives of the equilibrium uptakes w.r.t. the equilibrium pressure +at constant mole fractions and temperature <i>dx_adsorpt_dp_adsorpt</i> are defined +as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. Further inputs are particulary required +when developing IAST functions for more than two components. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialMultiIAST_dx_dp; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_dx_dy.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_dx_dy.mo new file mode 100644 index 0000000000000000000000000000000000000000..30399ae67f43fcc7e57e8763f624d9dfad6b358c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_dx_dy.mo @@ -0,0 +1,79 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMultiIAST_dx_dy + "Base function for isotherm models based on the ideal adsorbed solution theory: Partial derivative of uptakes w.r.t. molar fractions of independent gas phase components at constant temperature and pressure" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Real dy = 1e-4 + "Mole fraction difference used to calculate partial derivatives w.r.t. independent + mole fractions" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + + // + // Definition of outputs + // + output + SorpLib.Units.DerUptakeByMolarFraction[size(M_i,1),size(M_i,1)-1] dx_adsorpt_dy_i + "Partial derivatives of the uptakes w.r.t. the molar fractions of independent + gas phase components at constant temperature and pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models based on +the ideal adsorbed solution theory (IAST) describing the adsorption of multi +components. +<br/><br/> +This partial function is the basic function for calculating the partial derivative +in of the equilibrium uptakes w.r.t. the molar fractions of the independent components +the gas or vapor phase at constant temperature and pressure <i>dx_adsorpt_dy_i</i> +as a function of the equilibrium pressure <i>p_adsorpt</i>, the mole fractions of +the independent components in the gas or vapor phase <i>y_i</i>, the equilibrium +temperature <i>T_adsorpt</i>. Further inputs are the coefficients of the isotherm +model of the first component <i>c_1</i> and second component <i>c_2</i>. The +coefficients of the isotherm model <i>c_i</i> may depend on the equilibrium temperature +<i>T_adsorpt</i>. Further inputs are functions describing the pure component isotherm +models. These functional arguments are <i>func_x_pT_1</i>, <i>func_p_xT_1</i>, +<i>func_dx_dp_1</i>, <i>func_pi_pT_1</i>, and <i>func_p_piT_1</i> for component 1 +(i.e., <i>i = 1</i>) and 2 (i.e., <i>i = 2</i>). Optional input regarding numerics +define the setup of the IAST algorithm <i>num</i>, the pure component isotherm models +<i>num_comp_i</i>, and the infinitesimal difference <i>dy</i> to calculate the +partial derivatives. +<br/><br/> +The partial derivatives of the equilibrium uptakes w.r.t. the molar fractions of +the independent components the gas or vapor phase at constant temperature and pressure +<i>dx_adsorpt_dy_i</i> are defined as the outputs. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. Further inputs are particulary required +when developing IAST functions for more than two components. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialMultiIAST_dx_dy; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_p_xyT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_p_xyT.mo new file mode 100644 index 0000000000000000000000000000000000000000..c4d747f5baf80b2ef9bf99368ee03e63c871a972 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_p_xyT.mo @@ -0,0 +1,60 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMultiIAST_p_xyT + "Base function for isotherm models based on the ideal adsorbed solution theory: Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models based on +the ideal adsorbed solution theory (IAST) describing the adsorption of multi +components. +<br/><br/> +This partial function is the basic function for calculating the equilibrium uptakes +<i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>, the +mole fractions of the independent components in the gas or vapor phase <i>y_i</i>, +the equilibrium temperature <i>T_adsorpt</i>. Further inputs are the coefficients +of the isotherm model of the first component <i>c_1</i> and second component +<i>c_2</i>. The coefficients of the isotherm model <i>c_i</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Further inputs are functions describing +the pure component isotherm models. These functional arguments are <i>func_x_pT_1</i>, +<i>func_p_xT_1</i>, <i>func_dx_dp_1</i>, <i>func_pi_pT_1</i>, and <i>func_p_piT_1</i> +for component 1 (i.e., <i>i = 1</i>) and 2 (i.e., <i>i = 2</i>). Optional input +regarding numerics define the setup of the IAST algorithm <i>num</i> and the pure +component isotherm models <i>num_comp_i</i>. +<br/><br/> +The equilibrium pressure <i>p_adsorpt</i> is defined as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. Further inputs are particulary required +when developing IAST functions for more than two components. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialMultiIAST_p_xyT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_py_xT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_py_xT.mo new file mode 100644 index 0000000000000000000000000000000000000000..0d3bf5beda01e2b51d0e2ff02d99b89be2488f04 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_py_xT.mo @@ -0,0 +1,61 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMultiIAST_py_xT + "Base function for isotherm models based on the ideal adsorbed solution theory: Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models based on +the ideal adsorbed solution theory (IAST) describing the adsorption of multi +components. +<br/><br/> +This partial function is the basic function for calculating the equilibrium uptakes +<i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>, the +mole fractions of the independent components in the gas or vapor phase <i>y_i</i>, +the equilibrium temperature <i>T_adsorpt</i>. Further inputs are the coefficients +of the isotherm model of the first component <i>c_1</i> and second component +<i>c_2</i>. The coefficients of the isotherm model <i>c_i</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Further inputs are functions describing +the pure component isotherm models. These functional arguments are <i>func_x_pT_1</i>, +<i>func_p_xT_1</i>, <i>func_dx_dp_1</i>, <i>func_pi_pT_1</i>, and <i>func_p_piT_1</i> +for component 1 (i.e., <i>i = 1</i>) and 2 (i.e., <i>i = 2</i>). Optional input +regarding numerics define the setup of the IAST algorithm <i>num</i> and the pure +component isotherm models <i>num_comp_i</i>. +<br/><br/> +The equilibrium pressure <i>p_adsorpt</i> and the mole fractions of the independent +components in the gas or vapor phase <i>y_i</i> are defined as the outputs. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. Further inputs are particulary required +when developing IAST functions for more than two components. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialMultiIAST_py_xT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_x_pyT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_x_pyT.mo new file mode 100644 index 0000000000000000000000000000000000000000..02ece7b9855c615c9843933f3ff64abfd43c31f3 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_x_pyT.mo @@ -0,0 +1,60 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMultiIAST_x_pyT + "Base function for isotherm models based on the ideal adsorbed solution theory: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models based on +the ideal adsorbed solution theory (IAST) describing the adsorption of multi +components. +<br/><br/> +This partial function is the basic function for calculating the equilibrium uptakes +<i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>, the +mole fractions of the independent components in the gas or vapor phase <i>y_i</i>, +the equilibrium temperature <i>T_adsorpt</i>. Further inputs are the coefficients +of the isotherm model of the first component <i>c_1</i> and second component +<i>c_2</i>. The coefficients of the isotherm model <i>c_i</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Further inputs are functions describing +the pure component isotherm models. These functional arguments are <i>func_x_pT_1</i>, +<i>func_p_xT_1</i>, <i>func_dx_dp_1</i>, <i>func_pi_pT_1</i>, and <i>func_p_piT_1</i> +for component 1 (i.e., <i>i = 1</i>) and 2 (i.e., <i>i = 2</i>). Optional input +regarding numerics define the setup of the IAST algorithm <i>num</i> and the pure +component isotherm models <i>num_comp_i</i>. +<br/><br/> +The equilibrium uptakes <i>x_adsorpt</i> are defined as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. Further inputs are particulary required +when developing IAST functions for more than two components. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialMultiIAST_x_pyT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_y_pxT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_y_pxT.mo new file mode 100644 index 0000000000000000000000000000000000000000..f09174c9e3f4e07402143b287253fcc493edfaf3 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMultiIAST_y_pxT.mo @@ -0,0 +1,61 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMultiIAST_y_pxT + "Base function for isotherm models based on the ideal adsorbed solution theory: Mole fractions of independent gas phase components as function of pressure, uptakes, and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.MoleFraction[size(M_i,1)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models based on +the ideal adsorbed solution theory (IAST) describing the adsorption of multi +components. +<br/><br/> +This partial function is the basic function for calculating the equilibrium uptakes +<i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>, the +mole fractions of the independent components in the gas or vapor phase <i>y_i</i>, +the equilibrium temperature <i>T_adsorpt</i>. Further inputs are the coefficients +of the isotherm model of the first component <i>c_1</i> and second component +<i>c_2</i>. The coefficients of the isotherm model <i>c_i</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Further inputs are functions describing +the pure component isotherm models. These functional arguments are <i>func_x_pT_1</i>, +<i>func_p_xT_1</i>, <i>func_dx_dp_1</i>, <i>func_pi_pT_1</i>, and <i>func_p_piT_1</i> +for component 1 (i.e., <i>i = 1</i>) and 2 (i.e., <i>i = 2</i>). Optional input +regarding numerics define the setup of the IAST algorithm <i>num</i> and the pure +component isotherm models <i>num_comp_i</i>. +<br/><br/> +The mole fractions of the independent components in the gas or vapor phase +<i>y_i</i> are defined as the outputs. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. Further inputs are particulary required +when developing IAST functions for more than two components. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialMultiIAST_y_pxT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_dx_dT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_dx_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..fa09e6c1828d4af4c9361930df0014c059568396 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_dx_dT.mo @@ -0,0 +1,74 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMulti_dx_dT + "Base function for isotherm models of multi components: Partial derivative of uptakes w.r.t. temperature at contsant pressure and mole fractions" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(c,2)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + input Real[size(c,1), size(c,2)] dc_dT_adsorpt + "Partial derivatives of coefficients of isotherm model w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output + SorpLib.Units.DerUptakeByMolarFraction[size(c,2)] dx_adsorpt_dT_adsorpt + "Partial derivatives of the uptakes w.r.t. the temperature at contsant + pressure and mole fractions" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(c,2)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + Modelica.Units.SI.Pressure[size(c,2)] p_i = p_adsorpt .* y_i_ + "Partial pressures of all components"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of multi components. Such models can be extended pure component +isotherm models or specifically developed multi component isotherm models. +<br/><br/> +This partial function is the basic function for calculating the partial derivative +in of the equilibrium uptakes w.r.t. the temperature at contsant pressure and mole +fractions <i>dx_adsorpt_dT</i> as a function of the equilibrium pressure <i>p_adsorpt</i>, +the mole fractions of the independent components in the gas or vapor phase <i>y_i</i>, +the equilibrium temperature <i>T_adsorpt</i>. Further inputs are the coefficients of +the isotherm model <i>c</i>. The coefficients of the isotherm model <i>c</i> may +depend on the equilibrium temperature <i>T_adsorpt</i>. The coefficients of the +isotherm model <i>c</i> are a matrix: The columns contain the coefficients of the +different components. The rows contain the actual coefficients, i.e, the row size +depends on the selected isotherm model. Different components may require different +numbers of coefficients, which is why the row size depends on the component with +the most coefficients. Optional input regarding numerics is the threshold +<i>p_threshold_min</i> to regulate the minimal values of all partial pressures. +<br/><br/> +The partial derivatives of the equilibrium uptakes w.r.t. the temperature at contsant +pressure and mole fractions <i>dx_adsorpt_dT</i> are defined as the outputs. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialMulti_dx_dT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_dx_dp.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_dx_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..ecc4f57415d044ea8e1930228da1b6d987ba051c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_dx_dp.mo @@ -0,0 +1,72 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMulti_dx_dp + "Base function for isotherm models of multi components: Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(c,2)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerUptakeByPressure[size(c,2)] dx_adsorpt_dp_adsorpt + "Partial derivatives of the uptakes w.r.t. pressure at constant mole fractions + and temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(c,2)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + Modelica.Units.SI.Pressure[size(c,2)] p_i = p_adsorpt .* y_i_ + "Partial pressures of all components"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of multi components. Such models can be extended pure component +isotherm models or specifically developed multi component isotherm models. +<br/><br/> +This partial function is the basic function for calculating the partial derivative +of the equilibrium uptakes w.r.t. the equilibrium uptake at constant mole fractions +and temperature <i>dx_adsorpt_dp_adsorpt</i> as a function of the equilibrium +pressure <i>p_adsorpt</i>, the mole fractions of the independent components in +the gas or vapor phase <i>y_i</i>, the equilibrium temperature <i>T_adsorpt</i>. +Further inputs are the coefficients of the isotherm model <i>c</i>. The coefficients +of the isotherm model <i>c</i> may depend on the equilibrium temperature <i>T_adsorpt</i>. +The coefficients of the isotherm model <i>c</i> are a matrix: The columns contain +the coefficients of the different components. The rows contain the actual +coefficients, i.e, the row size depends on the selected isotherm model. Different +components may require different numbers of coefficients, which is why the row +size depends on the component with the most coefficients. Optional input regarding +numerics is the threshold <i>p_threshold_min</i> to regulate the minimal values +of all partial pressures. +<br/><br/> +The partial derivatives of the equilibrium uptakes w.r.t. the equilibrium pressure +at constant mole fractions and temperature <i>dx_adsorpt_dp_adsorpt</i> are +defined as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialMulti_dx_dp; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_dx_dy.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_dx_dy.mo new file mode 100644 index 0000000000000000000000000000000000000000..055f3542b42cd609de0887d13e25dfe56f5bc139 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_dx_dy.mo @@ -0,0 +1,73 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMulti_dx_dy + "Base function for isotherm models of multi components: Partial derivative of uptakes w.r.t. molar fractions of independent gas phase components at constant temperature and pressure" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(c,2)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output + SorpLib.Units.DerUptakeByMolarFraction[size(c,2),size(c,2)-1] dx_adsorpt_dy_i + "Partial derivatives of the uptakes w.r.t. the molar fractions of independent + gas phase components at constant temperature and pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(c,2)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + Modelica.Units.SI.Pressure[size(c,2)] p_i = p_adsorpt .* y_i_ + "Partial pressures of all components"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of multi components. Such models can be extended pure component +isotherm models or specifically developed multi component isotherm models. +<br/><br/> +This partial function is the basic function for calculating the partial derivative +in of the equilibrium uptakes w.r.t. the molar fractions of the independent components +the gas or vapor phase at constant temperature and pressure <i>dx_adsorpt_dy_i</i> +as a function of the equilibrium pressure <i>p_adsorpt</i>, the mole fractions of +the independent components in the gas or vapor phase <i>y_i</i>, the equilibrium +temperature <i>T_adsorpt</i>. Further inputs are the coefficients of the isotherm +model <i>c</i>. The coefficients of the isotherm model <i>c</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. The coefficients of the isotherm model +<i>c</i> are a matrix: The columns contain the coefficients of the different components. +The rows contain the actual coefficients, i.e, the row size depends on the selected +isotherm model. Different components may require different numbers of coefficients, +which is why the row size depends on the component with the most coefficients. +Optional input regarding numerics is the threshold <i>p_threshold_min</i> to +regulate the minimal values of all partial pressures. +<br/><br/> +The partial derivatives of the equilibrium uptakes w.r.t. the molar fractions of +the independent components the gas or vapor phase at constant temperature and pressure +<i>dx_adsorpt_dy_i</i> are defined as the outputs. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialMulti_dx_dy; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_p_xyT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_p_xyT.mo new file mode 100644 index 0000000000000000000000000000000000000000..559bc6455b4cb177e4146aeb013f1a0eb5cea6d5 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_p_xyT.mo @@ -0,0 +1,82 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMulti_p_xyT + "Base function for isotherm models of multi components: Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(c,2)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt_lb_start = 1 + "Lower bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Modelica.Units.SI.Pressure p_adsorpt_ub_start = 10 + "Upper bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for numerical calculation (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure[size(c,2)] p_i + "Partial pressures of all components"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of multi components. Such models can be extended pure component +isotherm models or specifically developed multi component isotherm models. +<br/><br/> +This partial function is the basic function for calculating the equilibrium +pressure <i>p_adsorpt</i> as function of the equilibrium uptakes <i>x_adsorpt</i>, +the mole fractions of the independent components in the gas or vapor phase +<i>y_i</i>, and the equilibrium temperature <i>T_adsorpt</i>. Further inputs are the +coefficients of the isotherm model <i>c</i>. The coefficients of the isotherm +model <i>c</i> may depend on the equilibrium temperature <i>T_adsorpt</i>. The +coefficients of the isotherm model <i>c</i> are a matrix: The columns contain the +coefficients of the different components. The rows contain the actual coefficients, +i.e, the row size depends on the selected isotherm model. Different components may +require different numbers of coefficients, which is why the row size depends on +the component with the most coefficients. Optional input regarding numerics is +the threshold <i>p_threshold_min</i> to regulate the minimal values of all partial +pressures. Further optional inputs regarding numerics are the lower bound +(<i>p_adsorpt_lb_start</i>) and upper bound (<i>p_adsorpt_ub_start</i>) of the +equilibrium pressure and the tolerance (<i>tolerance</i>), only required if this +function cannot be solved analytically. +<br/><br/> +The equilibrium pressure <i>p_adsorpt</i> is defined as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialMulti_p_xyT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_py_xT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_py_xT.mo new file mode 100644 index 0000000000000000000000000000000000000000..cba24e46e83c97215fb7ea5b57a8b2a319777d5f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_py_xT.mo @@ -0,0 +1,83 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMulti_py_xT + "Base function for isotherm models of multi components: Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt_lb_start = 1 + "Lower bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Modelica.Units.SI.Pressure p_adsorpt_ub_start = 10 + "Upper bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for numerical calculation (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.MoleFraction[size(c,2)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure[size(c,2)] p_i + "Partial pressures of all components"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of multi components. Such models can be extended pure component +isotherm models or specifically developed multi component isotherm models. +<br/><br/> +This partial function is the basic function for calculating the equilibrium +pressure <i>p_adsorpt</i> and the mole fractions of the independent components in +the gas or vapor phase <i>y_i</i> as function of the equilibrium uptakes <i>x_adsorpt</i> +and the equilibrium temperature <i>T_adsorpt</i>. Further inputs are the coefficients of +the isotherm model <i>c</i>. The coefficients of the isotherm model <i>c</i> may +depend on the equilibrium temperature <i>T_adsorpt</i>. The coefficients of the +isotherm model <i>c</i> are a matrix: The columns contain the coefficients of the +different components. The rows contain the actual coefficients, i.e, the row size +depends on the selected isotherm model. Different components may require different +numbers of coefficients, which is why the row size depends on the component with +the most coefficients. Optional input regarding numerics is the threshold +<i>p_threshold_min</i> to regulate the minimal values of all partial pressures. +Further optional inputs regarding numerics are the lower bound (<i>p_adsorpt_lb_start</i>) +and upper bound (<i>p_adsorpt_ub_start</i>) of the equilibrium pressure and the +tolerance (<i>tolerance</i>), only required if this function cannot be solved +analytically. +<br/><br/> +The equilibrium pressure <i>p_adsorpt</i> and the mole fractions of the independent +components in the gas or vapor phase <i>y_i</i> are defined as the outputs. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialMulti_py_xT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_x_pyT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_x_pyT.mo new file mode 100644 index 0000000000000000000000000000000000000000..d6e8d778e50905f9c11ae681a00cbf909ca70f96 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_x_pyT.mo @@ -0,0 +1,84 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMulti_x_pyT + "Base function for isotherm models of multi components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[size(c,2)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt_lb_start = 1 + "Lower bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Modelica.Units.SI.Pressure p_adsorpt_ub_start = 10 + "Upper bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for numerical calculation (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(c,2)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + Modelica.Units.SI.Pressure[size(c,2)] p_i = p_adsorpt .* y_i_ + "Partial pressures of all components"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of multi components. Such models can be extended pure component +isotherm models or specifically developed multi component isotherm models. +<br/><br/> +This partial function is the basic function for calculating the equilibrium uptakes +<i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>, the +mole fractions of the independent components in the gas or vapor phase <i>y_i</i>, +the equilibrium temperature <i>T_adsorpt</i>. Further inputs are the coefficients of +the isotherm model <i>c</i>. The coefficients of the isotherm model <i>c</i> may +depend on the equilibrium temperature <i>T_adsorpt</i>. The coefficients of the +isotherm model <i>c</i> are a matrix: The columns contain the coefficients of the +different components. The rows contain the actual coefficients, i.e, the row size +depends on the selected isotherm model. Different components may require different +numbers of coefficients, which is why the row size depends on the component with +the most coefficients. Optional input regarding numerics is the threshold +<i>p_threshold_min</i> to regulate the minimal values of all partial pressures. +Further optional inputs regarding numerics are the lower bound (<i>p_adsorpt_lb_start</i>) +and upper bound (<i>p_adsorpt_ub_start</i>) of the equilibrium pressure and the +tolerance (<i>tolerance</i>), only required if the inverse of this function cannot +be solved analytically. +<br/><br/> +The equilibrium uptakes <i>x_adsorpt</i> are defined as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialMulti_x_pyT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_y_pxT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_y_pxT.mo new file mode 100644 index 0000000000000000000000000000000000000000..4c297c12278fa53707ded427174ffa857842ca39 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialMulti_y_pxT.mo @@ -0,0 +1,83 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialMulti_y_pxT + "Base function for isotherm models of multi components: Mole fractions of independent gas phase components as function of pressure, uptakes, and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt_lb_start = 1 + "Lower bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Modelica.Units.SI.Pressure p_adsorpt_ub_start = 10 + "Upper bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for numerical calculation (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.MoleFraction[size(c,2)-1] y_i + "Mole fractions of independent components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure[size(c,2)] p_i + "Partial pressures of all components"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of multi components. Such models can be extended pure component +isotherm models or specifically developed multi component isotherm models. +<br/><br/> +This partial function is the basic function for calculating the mole fractions of +the independent components in the gas or vapor phase <i>y_i</i> as function of the +equilibrium pressure <i>p_adsorpt</i>, equilibrium uptakes <i>x_adsorpt</i>, and +the equilibrium temperature <i>T_adsorpt</i>. Further inputs are the coefficients of +the isotherm model <i>c</i>. The coefficients of the isotherm model <i>c</i> may +depend on the equilibrium temperature <i>T_adsorpt</i>. The coefficients of the +isotherm model <i>c</i> are a matrix: The columns contain the coefficients of the +different components. The rows contain the actual coefficients, i.e, the row size +depends on the selected isotherm model. Different components may require different +numbers of coefficients, which is why the row size depends on the component with +the most coefficients. Optional input regarding numerics is the threshold +<i>p_threshold_min</i> to regulate the minimal values of all partial pressures. +Further optional inputs regarding numerics are the lower bound (<i>p_adsorpt_lb_start</i>) +and upper bound (<i>p_adsorpt_ub_start</i>) of the equilibrium pressure and the +tolerance (<i>tolerance</i>), only required if this function cannot be solved +analytically. +<br/><br/> +The mole fractions of the independent components in the gas or vapor phase +<i>y_i</i> are defined as the outputs. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialMulti_y_pxT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure.mo new file mode 100644 index 0000000000000000000000000000000000000000..600a7d0d6307445d52cb31f7aacf37a5a14e9813 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure + "Base function for isotherm models of pure components" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Real[:] c + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function defines the equilibrium temperature <i>T_adsorpt</i> and +the coefficients of the isotherm model <i>c</i> as inputs. The coefficients of +the isotherm model <i>c</i> may depend on the equilibrium temperature +<i>T_adsorpt</i>. +<br/><br/> +Functions that inherit properties from this partial function may have to +implement further inputs, the output, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_A_W.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_A_W.mo new file mode 100644 index 0000000000000000000000000000000000000000..23acdad9d3e34bd0d901d1834c1d33592c069945 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_A_W.mo @@ -0,0 +1,68 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_A_W + "Base function for isotherm models of pure components: Molar adsorption potential as function of filled pore volume" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input SorpLib.Units.FilledPoreVolume W + "Filled pore volume" + annotation (Dialog(tab="General", group="Inputs")); + input Real[:] c + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.MolarAdsorptionPotential A_lb_start=10 + "Lower bound of molar adsorption potential (required if molar adsorption potential + is calculated numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input SorpLib.Units.MolarAdsorptionPotential A_ub_start=100 + "Upper bound of molar adsorption potential ((required if molar adsorption potential + is calculated numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for numerical calculation (required if molar adsorption potential + is calculated numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.MolarAdsorptionPotential A "Molar adsorption potential" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models must be based on filled pores +(i.e., Dubinin theory). +<br/><br/> +This partial function is the basic function for calculating the molar adsorption +potential <i>A</i> as a function of the filled pore volume <i>W</i>. Defined inputs +are the filled pore volume <i>W</i> and the coefficients of the isotherm model <i>c</i>. +The coefficients of the isotherm model <i>c</i> may depend on the equilibrium +temperature <i>T_adsorpt</i>. Optional inputs regarding numerics are the lower +bound (<i>A_lb_start</i>) and upper bound (<i>A_ub_start</i>) of the molar +adsorption potential and the tolerance (<i>tolerance</i>), only required if this +function cannot be solved analytically. The defined output is the molar adsorption +potential <i>A</i>. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_A_W; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_A_W_num.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_A_W_num.mo new file mode 100644 index 0000000000000000000000000000000000000000..5e4991dd51c83b633127d334cf71df05798c63ad --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_A_W_num.mo @@ -0,0 +1,151 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_A_W_num + "Base function for isotherm models of pure components: Molar adsorption potential as function of filled pore volume (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_A_W; + + // + // Definition of protected replacable functions + // +protected + replaceable function func_W_A = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.W_A + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_W_A + "Filled pore volume as function of molar adsorption potential" + annotation (Dialog(tab="General", group="Functions")); + + // + // Definition of functions + // +protected + function func_A_num + "Function used to find root (i.e., A) numerically" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input SorpLib.Units.FilledPoreVolume W + "Filled pore volume"; + input Real c[:] + "Coefficients of isotherm model"; + algorithm + y := func_W_A(A=u, c=c) - W + "Function '0 = W(A, c) - W' used to find root (i.e., A) numerically"; + end func_A_num; + + // + // Definition of variables + // + Boolean bound_ok = false + "= true, if bounds are found such that func_A_num(lb) > 0 and func_A_num(ub) < 0"; + + SorpLib.Units.MolarAdsorptionPotential A_lb=A_lb_start + "Current best lower bound of molar adsorption potential"; + SorpLib.Units.MolarAdsorptionPotential A_ub=A_ub_start + "Current best upper bound of molar adsorption potential"; + + SorpLib.Units.FilledPoreVolume W_lb = func_W_A(A=A_lb, c=c) + "Filled pore volume at current best lower bound of molar adsorption potential"; + SorpLib.Units.FilledPoreVolume W_ub = func_W_A(A=A_ub, c=c) + "Filled pore volume at current best upper bound of molar adsorption potential"; + +algorithm + // + // Find start values such that func_A_num(lb) > 0 and func_A_num(ub) < 0 + // + // Reducing A increases W -> func_A_num(W) can become > 0 + // Increasing A reduces W -> func_A_num(W) can become < 0 + // + while not bound_ok loop + if Modelica.Math.isEqual(s1=W_lb, s2=W, eps=tolerance) then + A := A_lb; + bound_ok := true; + return; + + elseif Modelica.Math.isEqual(s1=W_ub, s2=W, eps=tolerance) then + A := A_ub; + bound_ok := true; + return; + + elseif W_lb-W < 0 and W_ub-W < 0 then + A_ub := A_lb; + W_ub := W_lb; + + A_lb := if A_lb > Modelica.Constants.small then A_lb*0.1 else 0; + W_lb := func_W_A(A=A_lb, c=c); + + elseif W_lb-W > 0 and W_ub-W > 0 then + A_lb := A_ub; + W_lb := W_ub; + + A_ub := A_ub*10; + W_ub := func_W_A(A=A_ub, c=c); + + else + bound_ok := true; + + end if; + + // + // Check if func_W_A is not strictly monotonic with A (i.e., unfavourable + // parameterisation or function approach selected) + // + if Modelica.Math.isEqual(s1=A_lb, s2=A_ub, eps=tolerance) or A_lb > 1e15 then + A := if A_lb > 1e15 then 1e15 else 0 + "Set A to bound"; + Modelica.Utilities.Streams.print("Characteristic curbe W(A) is not strictly monotonic with A: Inverse A(W) cannot be found!"); + return; + end if; + end while; + + // + // Find root in the interval lb <= root <= up + // + A := Modelica.Math.Nonlinear.solveOneNonlinearEquation( + f = function func_A_num(W=W, c=c), + u_min = A_lb, + u_max = A_ub, + tolerance = tolerance) + "Calculation of the molar adsorption potential"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models must be based on filled pores +(i.e., Dubinin theory). +<br/><br/> +This partial function is the basic function for calculating the molar adsorption +potential <i>A</i> as a function of the filled pore volume <i>W</i>. Defined +inputs are the filled pore volume <i>W</i> and the coefficients of the isotherm +model <i>c</i>. The coefficients of the isotherm model <i>c</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Inputs regarding numerics are the lower +bound (<i>A_lb_start</i>) and upper bound (<i>A_ub_start</i>) of the molar +adsorption potential and the tolerance (<i>tolerance</i>). The defined output is +molar the adsorption potential <i>A</i>. +<br/><br/> +With this function, the eadsorption potential <i>A</i> is determined numerically +by solving a zero problem. The zero problem is as follows: +</p> +<pre> + f(A) = 0 => 0 = func_W_A(A=A, c=c) - W; +</pre> +<p> +The zero problem is solved using the numerically very efficient function +<a href=\"Modelica://Modelica.Math.Nonlinear.solveOneNonlinearEquation\">Modelica.Math.Nonlinear.solveOneNonlinearEquation</a>. +For the application of this function, it must be ensured that <i>f(A)</i> +has a different sign for the upper and lower limits of <i>A</i>. To ensure +the different signs, the upper and lower limits are determined in an upstream loop. +<br/><br/> +Functions that inherit properties from this partial function have to redeclare +the function <i>func_W_A</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_A_W_num; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_W_A.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_W_A.mo new file mode 100644 index 0000000000000000000000000000000000000000..e43f9ca1d86a62cddd1cf6f605aae3fe5b74f1bb --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_W_A.mo @@ -0,0 +1,65 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_W_A + "Base function for isotherm models of pure components: Filled pore volume as function of molar adsorption potential" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input SorpLib.Units.MolarAdsorptionPotential A "Molar adsorption potential" + annotation (Dialog(tab="General", group="Inputs")); + input Real[:] c + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Units.MolarAdsorptionPotential A_lb_start=0 + "Lower bound of molar adsorption potential (required if inverse is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input SorpLib.Units.MolarAdsorptionPotential A_ub_start=10 + "Upper bound of molar adsorption potential (required if inverse is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for numerical calculation (required if inverse is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.FilledPoreVolume W + "Filled pore volume" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models must be based on filled pores +(i.e., Dubinin theory). +<br/><br/> +This partial function is the basic function for calculating the filled pore volume +<i>W</i> as a function of the molar adsorption potential <i>A</i>. Defined inputs +are the molar adsorption potential <i>A</i> and the coefficients of the isotherm +model <i>c</i>. The coefficients of the isotherm model <i>c</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Optional inputs regarding numerics are +the lower bound (<i>A_lb_start</i>) and upper bound (<i>A_ub_start</i>) of the +molar adsorption potential and the tolerance (<i>tolerance</i>), only required if +the inverse of this function cannot be solved analytically. The defined output is +the filled pore volume <i>W</i>. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_W_A; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_dW_dA.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_dW_dA.mo new file mode 100644 index 0000000000000000000000000000000000000000..09addce2ceb27e2354c9eb8c34887bd2b4b62a05 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_dW_dA.mo @@ -0,0 +1,56 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_dW_dA + "Base function for isotherm models of pure components: Partial derivative of filled pore volume w.r.t. molar adsorption potential at constant pressure and temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input SorpLib.Units.MolarAdsorptionPotential A + "Molar adsorption potential" + annotation (Dialog(tab="General", group="Inputs")); + input Real[:] c + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models must be based on filled pores +(i.e., Dubinin theory). +<br/><br/> +This partial function is the basic function for calculating the partial derivative +of the filled pore volume with respect to the molar adsorption potential at constant +pressure and temperature <i>dW_dA</i> as a function of the molar adsorption potential +<i>A</i>. Defined inputs are the molar adsorption potential <i>A</i> and the +coefficients of the isotherm model <i>c</i>. The coefficients of the isotherm model +<i>c</i> may depend on the equilibrium temperature <i>T_adsorpt</i>. The defined +output is the partial derivative of the filled pore volume with respect to the molar +adsorption potential at constant pressure and temperature <i>dW_dA</i>. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_dW_dA; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddW_dA_dA.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddW_dA_dA.mo new file mode 100644 index 0000000000000000000000000000000000000000..990b041bc74c854c9ec592269aaee3e99dd82277 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddW_dA_dA.mo @@ -0,0 +1,58 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_ddW_dA_dA + "Base function for isotherm models of pure components: Second-order partial derivative of filled pore volume w.r.t. molar adsorption potential at constant pressure and temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input SorpLib.Units.MolarAdsorptionPotential A + "Molar adsorption potential" + annotation (Dialog(tab="General", group="Inputs")); + input Real[:] c + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential at constant pressure and temperature" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models must be based on filled pores +(i.e., Dubinin theory). +<br/><br/> +This partial function is the basic function for calculating the second-order partial +derivative of the filled pore volume with respect to the molar adsorption potential +at constant pressure and temperature <i>ddW_dA_dA</i> as a function of the molar +adsorption potential <i>A</i>. Defined inputs are the molar adsorption potential +<i>A</i> and the coefficients of the isotherm model <i>c</i>. The coefficients of +the isotherm model <i>c</i> may depend on the equilibrium temperature <i>T_adsorpt</i>. +The defined output is the second-order partial derivative of the filled pore volume +with respect to the molar adsorption potential at constant pressure and temperature +<i>ddW_dA_dA</i>. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPure_ddW_dA_dA; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddW_dA_dT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddW_dA_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..c5c57482c80466e9df857fb2d105d8aa9cce32c4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddW_dA_dT.mo @@ -0,0 +1,68 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_ddW_dA_dT + "Base function for isotherm models of pure components: Second-order partial derivative of filled pore volume w.r.t. molar adsorption potential and temperature at constant pressure" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.MolarAdsorptionPotential A + "Molar adsorption potential" + annotation (Dialog(tab="General", group="Inputs")); + input Real[:] c + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real[:] dc_dT_adsorpt + "Partial derivatives of coefficients of isotherm model w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models must be based on filled pores +(i.e., Dubinin theory). +<br/><br/> +This partial function is the basic function for calculating the second-order partial +derivative of the filled pore volume with respect to the molar adsorption potential +and temperature at constant pressure <i>ddW_dA_dT</i> as a function of the molar +adsorption potential <i>A</i>. Defined inputs are the equilibrium pressure <i>p_adsorpt</i>, +equilibrium temperature <i>T_adsorpt</i>, molar adsorption potential <i>A</i>, the +coefficients of the isotherm model <i>c</i>, and the partial derivatives ot the +coefficients with respect to the equilibrium temperatre <i>dc_dT_adsorpt</i>. The +coefficients of the isotherm model <i>c</i> may depend on the equilibrium temperature +<i>T_adsorpt</i>. The defined output is the second-order partial derivative of the +filled pore volume with respect to the molar adsorption potential and temperature +at constant pressure and temperature <i>ddW_dA_dT</i>. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPure_ddW_dA_dT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddx_dT_dT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddx_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..6f9c5e37d9b7c24c1023baeeafe5388549e21f6c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddx_dT_dT.mo @@ -0,0 +1,62 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_ddx_dT_dT + "Base function for isotherm models of pure components: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure; + input Real[:] dc_dT_adsorpt + "Partial derivatives of coefficients of isotherm model w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real[:] ddc_dT_adsorpt_dT_adsorpt + "Second-order partial derivatives of coefficients of isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerUptakeByTemperatureTemperature + ddx_adsorpt_dT_adsorpt_dT_adsorpt + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the second-order +partial derivative of the equilibrium uptake with respect to the equilibrium +temperature at constant pressure <i>ddx_adsorpt_dT_adsorpt_dT_adsorpt</i> as a +function of the equilibrium pressure <i>p_adsorpt</i> and equilibrium temperature +<i>T_adsorpt</i>. Defined inputs are the equilibrium pressure <i>p_adsorpt</i>, the +equilibrium temperature <i>T_adsorpt</i>, the coefficients of the isotherm model +<i>c</i>, the partial derivatives ot the coefficients with respect to the equilibrium +temperatre <i>dc_dT_adsorpt</i>, and the second-order partial derivatives ot the +coefficients with respect to the equilibrium temperatre <i>ddc_dT_adsorpt_dT_adsorpt</i>. +The coefficients of the isotherm model <i>c</i> may depend on the equilibrium +temperature <i>T_adsorpt</i>. Besides, this partial function defines the second- +order partial derivative of the equilibrium uptake with respect to the equilibrium +temperature at constant pressure <i>ddx_adsorpt_dT_adsorpt_dT_adsorpt</i> as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPure_ddx_dT_dT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddx_dp_dT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddx_dp_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..2831f83f646c21dc5f44160b0ab0de151700d130 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddx_dp_dT.mo @@ -0,0 +1,57 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_ddx_dp_dT + "Base function for isotherm models of pure components: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure; + input Real[:] dc_dT_adsorpt + "Partial derivatives of coefficients of isotherm model w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerUptakeByPressureTemperature + ddx_adsorpt_dp_adsorpt_dT_adsorpt + "Second-order partial derivative of uptake w.r.t. pressure and temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the second-order +partial derivative of the equilibrium uptake with respect to the equilibrium +pressure and temperature <i>ddx_adsorpt_dp_adsorpt_dT_adsorpt</i> as a function +of the equilibrium pressure <i>p_adsorpt</i> and equilibrium temperature +<i>T_adsorpt</i>. Defined inputs are the equilibrium pressure <i>p_adsorpt</i>, +the equilibrium temperature <i>T_adsorpt</i>, the coefficients of the isotherm +model <i>c</i>, and the partial derivatives ot the coefficients with respect to +the equilibrium temperatre <i>dc_dT_adsorpt</i>. The coefficients of the isotherm +model <i>c</i> may depend on the equilibrium temperature <i>T_adsorpt</i>. The +second-order partial derivative of the equilibrium uptake with respect to the +equilibrium pressure and temperature <i>ddx_adsorpt_dp_adsorpt_dT_adsorpt</i> is +defined as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPure_ddx_dp_dT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddx_dp_dp.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddx_dp_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..9b7803b59f45afeefa23a4f69cbe60c35b71ccda --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_ddx_dp_dp.mo @@ -0,0 +1,52 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_ddx_dp_dp + "Base function for isotherm models of pure components: Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure; + + // + // Definition of outputs + // + output SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_adsorpt_dp_adsorpt + "Second-order partial derivative of the uptake w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the second-order partial +derivative of the equilibrium uptake with respect to the equilibrium pressure at +constant temperature <i>ddx_adsorpt_dp_adsorpt_dp_adsorpt</i> as a function of +the equilibrium pressure <i>p_adsorpt</i> and equilibrium temperature <i>T_adsorpt</i>. +Defined inputs are the equilibrium pressure <i>p_adsorpt</i>, the equilibrium +temperature <i>T_adsorpt</i>, and the coefficients of the isotherm model <i>c</i>. +The coefficients of the isotherm model <i>c</i> may depend on the equilibrium +temperature <i>T_adsorpt</i>. The second-order partial derivative of the +equilibrium uptake with respect to the equilibrium pressure +<i>ddx_adsorpt_dp_adsorpt_dp_adsorpt</i> is defined as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPure_ddx_dp_dp; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_dx_dT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_dx_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..9bb6a55087e0af036d1fcbd9afa884a5d5fe1c74 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_dx_dT.mo @@ -0,0 +1,55 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_dx_dT + "Base function for isotherm models of pure components: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure; + input Real[:] dc_dT_adsorpt + "Partial derivatives of coefficients of isotherm model w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_adsorpt + "Partial derivative of the uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the partial derivative +of the equilibrium uptake with respect to the equilibrium temperature at constant +pressure <i>dx_adsorpt_dT_adsorpt</i> as a function of the equilibrium pressure +<i>p_adsorpt</i> and equilibrium temperature <i>T_adsorpt</i>. Defined inputs are +the equilibrium pressure <i>p_adsorpt</i>, the equilibrium temperature <i>T_adsorpt</i>, +the coefficients of the isotherm model <i>c</i>, and the partial derivatives ot the +coefficients with respect to the equilibrium temperatre <i>dc_dT_adsorpt</i>. The +coefficients of the isotherm model <i>c</i> may depend on the equilibrium temperature +<i>T_adsorpt</i>. Besides, this partial function defines the partial derivative of +the equilibrium uptake with respect to the equilibrium temperature at constant pressure +<i>dx_adsorpt_dT_adsorpt</i> as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_dx_dT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_dx_dp.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_dx_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..b39d4cb69e5697cab19d5691b2f09b9ed663e3b1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_dx_dp.mo @@ -0,0 +1,50 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_dx_dp + "Base function for isotherm models of pure components: Partial derivative of uptake w.r.t. pressure at constant temperature" + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure; + + // + // Definition of outputs + // + output SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_adsorpt + "Partial derivative of the uptake w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the partial derivative +of the equilibrium uptake with respect to the equilibrium pressure at constant temperature +<i>dx_adsorpt_dp_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i> +and equilibrium temperature <i>T_adsorpt</i>. Defined inputs are the equilibrium +pressure <i>p_adsorpt</i>, the equilibrium temperature <i>T_adsorpt</i>, and the +coefficients of the isotherm model <i>c</i>. The coefficients of the isotherm model +<i>c</i> may depend on the equilibrium temperature <i>T_adsorpt</i>. The partial +derivative of the equilibrium uptake with respect to the equilibrium pressure at +constant temperature<i>dx_adsorpt_dp_adsorpt</i> is defined as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_dx_dp; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_piT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_piT.mo new file mode 100644 index 0000000000000000000000000000000000000000..2b88185a479128ec7ecaeea12f2dbd5b5ddc18ea --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_piT.mo @@ -0,0 +1,85 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_p_piT + "Base function for isotherm models of pure components: Pressure as function of reduced spreading pressure and temperature" + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.ReducedSpreadingPressure pi "Reduced spreading pressure" + annotation (Dialog(tab="General", group="Inputs")); + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure; + + input Modelica.Units.SI.Pressure p_adsorpt_lb_start + "Lower bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Modelica.Units.SI.Pressure p_adsorpt_ub_start + "Upper bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + input Modelica.Units.SI.Pressure integral_pi_lb + "Lower limit of integral when calculating the reduced spreading pressure + numerically (should be 0)" + annotation (Dialog(tab="General", group="Numerical inputs")); + + input Real tolerance_p_adsorpt + "Tolerance for numerical calculation of equilibrium pressure (required if + pressure is calculated numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance_pi + "Tolerance for numerical calculation of reduced spreading pressure (required + if reduced spreading pressure is calculated numerically (i.e., integral))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + /* Note that optional numerical inputs do not have default values as this + function is used as functional input argument within the "Ideal Adsorbed + Solution Theory," a multi-component adsorption isotherm model. Using default + values resulted in translation errors. */ + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the equilibrium pressure +<i>p_adsorpt</i> as a function of the reduced spreading pressure <i>pi</i> and +equilibrium temperature <i>T_adsorpt</i>. Defined inputs are the molar mass of +the adsorptive <i>M_adsorptive</i>, the reduced spreading pressure <i>pi</i>, +the equilibrium temperature <i>T_adsorpt</i>, and the coefficients of the isotherm +model <i>c</i>. The coefficients of the isotherm model <i>c</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Optional inputs regarding numerics are +the lower bound (<i>p_adsorpt_lb_start</i>) and upper bound (<i>p_adsorpt_ub_start</i>) +of the equilibrium pressure and the tolerance (<i>tolerance_p_adsorpt</i>), only +required if this function cannot be solved analytically. Further optional inputs +regarding numerics are the lower integral bound (<i>integral_pi_lb</i>) and the +tolerance (<i>integral_pi_lb</i>), only required if the reduced spreading pressure +cannot be solved analytically. Besides, this partial function defines the equilibrium +pressure <i>p_adsorpt</i> as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_p_piT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_piT_num.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_piT_num.mo new file mode 100644 index 0000000000000000000000000000000000000000..d2d8dd231f33af5debcb0881808220c4902e812e --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_piT_num.mo @@ -0,0 +1,181 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_p_piT_num + "Base function for isotherm models of pure components: Pressure as function of reduced spreading pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT; + + // + // Definition of protected replacable functions + // +protected + replaceable function func_pi_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.pi_pT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT + "Reduced spreading pressure as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions")); + + // + // Definition of functions + // +protected + function func_p_num + "Function used to find root (i.e., p_adsorpt) numerically" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input SorpLib.Units.ReducedSpreadingPressure pi + "Reduced spreading pressure"; + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of adsorptive"; + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature"; + input Real c[:] + "Coefficients of isotherm model"; + input Modelica.Units.SI.Pressure integral_pi_lb + "Lower limit of integral when calculating the reduced spreading pressure + numerically (should be 0)"; + input Real tolerance + "Tolerance for numerical calculation (required if reduced spreading pressure + is calculated numerically"; + algorithm + y := func_pi_pT(M_adsorptive=M_adsorptive, p_adsorpt=u, T_adsorpt=T_adsorpt, + c=c, integral_pi_lb=integral_pi_lb, tolerance=tolerance) - pi + "Function '0 = pi(M_adsorptive, p_adsorpt, T_adsorpt, c) - pi' used to find + root (i.e., p_adsorpt) numerically"; + end func_p_num; + + // + // Definition of variables + // + Boolean bound_ok = false + "= true, if bounds are found such that func_p_num(lb) < 0 and func_p_num(ub) > 0"; + + Modelica.Units.SI.Pressure p_adsorpt_lb = p_adsorpt_lb_start + "Current best lower bound of equilibrium pressure"; + Modelica.Units.SI.Pressure p_adsorpt_ub = p_adsorpt_ub_start + "Current best upper bound of equilibrium pressure"; + + SorpLib.Units.ReducedSpreadingPressure pi_lb=func_pi_pT( + M_adsorptive=M_adsorptive, + p_adsorpt=p_adsorpt_lb, + T_adsorpt=T_adsorpt, + c=c, + integral_pi_lb=integral_pi_lb, + tolerance=tolerance_pi) + "Reduced spreading pressure at current best lower bound of equilibrium pressure"; + SorpLib.Units.ReducedSpreadingPressure pi_ub=func_pi_pT( + M_adsorptive=M_adsorptive, + p_adsorpt=p_adsorpt_ub, + T_adsorpt=T_adsorpt, + c=c, + integral_pi_lb=integral_pi_lb, + tolerance=tolerance_pi) + "Reduced spreading pressure at current best upper bound of equilibrium pressure"; + +algorithm + // + // Find start values such that func_p_num(lb) < 0 and func_p_num(ub) > 0 + // + // Reducing p_adsorpt reduces pi -> func_p_num(p_adsorpt) can become < 0 + // Increasing p_adsorpt increases pi -> func_p_num(p_adsorpt) can become > 0 + // + while not bound_ok loop + if Modelica.Math.isEqual(s1=pi_lb, s2=pi, eps=tolerance_p_adsorpt) then + p_adsorpt := p_adsorpt_lb; + bound_ok := true; + return; + + elseif Modelica.Math.isEqual(s1=pi_ub, s2=pi, eps=tolerance_p_adsorpt) then + p_adsorpt := p_adsorpt_ub; + bound_ok := true; + return; + + elseif pi_lb-pi < 0 and pi_ub-pi < 0 then + p_adsorpt_lb := p_adsorpt_ub; + pi_lb := pi_ub; + + p_adsorpt_ub := p_adsorpt_ub*10; + pi_ub := func_pi_pT(M_adsorptive=M_adsorptive, + p_adsorpt=p_adsorpt_ub, T_adsorpt=T_adsorpt, c=c, + integral_pi_lb=integral_pi_lb, tolerance=tolerance_pi); + + elseif pi_lb-pi > 0 and pi_ub-pi > 0 then + p_adsorpt_ub := p_adsorpt_lb; + pi_ub := pi_lb; + + p_adsorpt_lb := if p_adsorpt_lb > Modelica.Constants.small then + p_adsorpt_lb*0.1 else 0; + pi_lb := func_pi_pT(M_adsorptive=M_adsorptive, + p_adsorpt=p_adsorpt_lb, T_adsorpt=T_adsorpt, c=c, + integral_pi_lb=integral_pi_lb, tolerance=tolerance_pi); + + else + bound_ok := true; + + end if; + end while; + + // + // Find root in the interval lb <= root <= up + // + p_adsorpt := Modelica.Math.Nonlinear.solveOneNonlinearEquation( + f = function func_p_num( + pi=pi, + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + c=c, + integral_pi_lb=integral_pi_lb, + tolerance=tolerance_pi), + u_min=p_adsorpt_lb, + u_max=p_adsorpt_ub, + tolerance=tolerance_p_adsorpt) + "Calculation of the equilibrium pressure of the adsorpt phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the equilibrium pressure +<i>p_adsorpt</i> as a function of the reduced spreading pressure <i>pi</i> and +equilibrium temperature <i>T_adsorpt</i>. Defined inputs are the molar mass of +the adsorptive <i>M_adsorptive</i>, the reduced spreading pressure <i>pi</i>, +the equilibrium temperature <i>T_adsorpt</i>, and the coefficients of the isotherm +model <i>c</i>. The coefficients of the isotherm model <i>c</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Optional inputs regarding numerics are +the lower bound (<i>p_adsorpt_lb_start</i>) and upper bound (<i>p_adsorpt_ub_start</i>) +of the equilibrium pressure and the tolerance (<i>tolerance_p_adsorpt</i>), only +required if this function cannot be solved analytically. Further optional inputs +regarding numerics are the lower integral bound (<i>integral_pi_lb</i>) and the +tolerance (<i>integral_pi_lb</i>), only required if the reduced spreading pressure +cannot be solved analytically. Besides, this partial function defines the equilibrium +pressure <i>p_adsorpt</i> as the output. +<br/><br/> +With this function, the equilibrium pressure <i>p_adsorpt</i> is determined +numerically by solving a zero problem. The zero problem is as follows: +</p> +<pre> + f(p_adsorpt) = 0 => 0 = func_pi_pT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt, c=c) - pi; +</pre> +<p> +The zero problem is solved using the numerically very efficient function +<a href=\"Modelica://Modelica.Math.Nonlinear.solveOneNonlinearEquation\">Modelica.Math.Nonlinear.solveOneNonlinearEquation</a>. +For the application of this function, it must be ensured that <i>f(p_adsorpt)</i> +has a different sign for the upper and lower limits of <i>p_adsorpt</i>. To ensure +the different signs, the upper and lower limits are determined in an upstream loop. +<br/><br/> +Functions that inherit properties from this partial function have to redeclare +the function <i>func_pi_pT</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_p_piT_num; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_xT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_xT.mo new file mode 100644 index 0000000000000000000000000000000000000000..ba4471264b4aee758dd528d791e423ff55b52aa4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_xT.mo @@ -0,0 +1,70 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_p_xT + "Base function for isotherm models of pure components: Pressure as function of uptake and temperature" + + // + // Definition of inputs + // + input SorpLib.Units.Uptake x_adsorpt + "Equilibrium uptake of adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure; + + input Modelica.Units.SI.Pressure p_adsorpt_lb_start + "Lower bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Modelica.Units.SI.Pressure p_adsorpt_ub_start + "Upper bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance + "Tolerance for numerical calculation (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + /* Note that optional numerical inputs do not have default values as this + function is used as functional input argument within the "Ideal Adsorbed + Solution Theory," a multi-component adsorption isotherm model. Using default + values resulted in translation errors. */ + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the equilibrium +pressure <i>p_adsorpt</i> as a function of the equilibrium uptake <i>x_adsorpt</i> +and equilibrium temperature <i>T_adsorpt</i>. Defined inputs are the equilibrium +uptake <i>x_adsorpt</i>, the equilibrium temperature <i>T_adsorpt</i>, and the +coefficients of the isotherm model <i>c</i> as inputs. The coefficients of the +isotherm model <i>c</i> may depend on the equilibrium temperature <i>T_adsorpt</i>. +Optional inputs regarding numerics are the lower bound (<i>p_adsorpt_lb_start</i>) +and upper bound (<i>p_adsorpt_ub_start</i>) of the equilibrium pressure and the +tolerance (<i>tolerance</i>), only required if this function cannot be solved +analytically. Besides, the equilibrium pressure <i>p_adsorpt</i> is defined as +the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_p_xT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_xT_num.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_xT_num.mo new file mode 100644 index 0000000000000000000000000000000000000000..d329a163462c4cd9b991ae4b91bdfd7127e5707b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_p_xT_num.mo @@ -0,0 +1,161 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_p_xT_num + "Base function for isotherm models of pure components: Pressure as function of uptake and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT; + + // + // Definition of protected replacable functions + // +protected + replaceable function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.x_pT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT + "Calculates uptake as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions")); + + // + // Definition of functions + // +protected + function func_p_num + "Function used to find root (i.e., p_adsorpt) numerically" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input SorpLib.Units.Uptake x_adsorpt + "Equilibrium uptake"; + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature"; + input Real c[:] + "Coefficients of isotherm model"; + algorithm + y := func_x_pT(p_adsorpt=u, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) - x_adsorpt + "Function '0 = x(p_adsorpt, T_adsorpt, c) - x_adsorpt' used to find root + (i.e., p_adsorpt) numerically"; + end func_p_num; + + // + // Definition of variables + // + Boolean bound_ok = false + "= true, if bounds are found such that func_p_num(lb) < 0 and func_p_num(ub) > 0"; + + Modelica.Units.SI.Pressure p_adsorpt_lb = p_adsorpt_lb_start + "Current best lower bound of equilibrium pressure"; + Modelica.Units.SI.Pressure p_adsorpt_ub = p_adsorpt_ub_start + "Current best upper bound of equilibrium pressure"; + + SorpLib.Units.Uptake x_adsorpt_lb = func_x_pT( + p_adsorpt=p_adsorpt_lb, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Equilibrium uptake at current best lower bound of equilibrium pressure"; + SorpLib.Units.Uptake x_adsorpt_ub = func_x_pT( + p_adsorpt=p_adsorpt_ub, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Equilibrium uptake at current best upper bound of equilibrium pressure"; + +algorithm + // + // Find start values such that func_p_num(lb) < 0 and func_p_num(ub) > 0 + // + // Reducing p_adsorpt reduces x_adsorpt -> func_p_num(p_adsorpt) can become < 0 + // Increasing p_adsorpt increases x_adsorpt -> func_p_num(p_adsorpt) can become > 0 + // + while not bound_ok loop + if Modelica.Math.isEqual(s1=x_adsorpt_lb, s2=x_adsorpt, eps=tolerance) then + p_adsorpt := p_adsorpt_lb; + bound_ok := true; + return; + + elseif Modelica.Math.isEqual(s1=x_adsorpt_ub, s2=x_adsorpt, eps=tolerance) then + p_adsorpt := p_adsorpt_ub; + bound_ok := true; + return; + + elseif x_adsorpt_lb-x_adsorpt < 0 and x_adsorpt_ub-x_adsorpt < 0 then + p_adsorpt_lb := p_adsorpt_ub; + x_adsorpt_lb := x_adsorpt_ub; + + p_adsorpt_ub := p_adsorpt_ub*10; + x_adsorpt_ub := func_x_pT(p_adsorpt=p_adsorpt_ub, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps); + + elseif x_adsorpt_lb-x_adsorpt > 0 and x_adsorpt_ub-x_adsorpt > 0 then + p_adsorpt_ub := p_adsorpt_lb; + x_adsorpt_ub := x_adsorpt_lb; + + p_adsorpt_lb := if p_adsorpt_lb > Modelica.Constants.small then + p_adsorpt_lb*0.1 else 0; + x_adsorpt_lb := func_x_pT(p_adsorpt=p_adsorpt_lb, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps); + + else + bound_ok := true; + + end if; + end while; + + // + // Find root in the interval lb <= root <= up + // + p_adsorpt := Modelica.Math.Nonlinear.solveOneNonlinearEquation( + f = function func_p_num( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=c), + u_min=p_adsorpt_lb, + u_max=p_adsorpt_ub, + tolerance=tolerance) + "Calculation of the equilibrium pressure of the adsorpt phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the equilibrium +pressure <i>p_adsorpt</i> as a function of the equilibrium uptake <i>x_adsorpt</i> +and equilibrium temperature <i>T_adsorpt</i>. Defined inputs are the equilibrium +uptake <i>x_adsorpt</i>, the equilibrium temperature <i>T_adsorpt</i>, and the +coefficients of the isotherm model <i>c</i> as inputs. The coefficients of the +isotherm model <i>c</i> may depend on the equilibrium temperature <i>T_adsorpt</i>. +Optional inputs regarding numerics are the lower bound (<i>p_adsorpt_lb_start</i>) +and upper bound (<i>p_adsorpt_ub_start</i>) of the equilibrium pressure and the +tolerance (<i>tolerance</i>). Besides, the equilibrium pressure <i>p_adsorpt</i> +is defined as the output. +<br/><br/> +With this function, the equilibrium pressure <i>p_adsorpt</i> is determined +numerically by solving a zero problem. The zero problem is as follows: +</p> +<pre> + f(p_adsorpt) = 0 => 0 = func_x_pT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt, c=c) - x_adsorpt; +</pre> +<p> +The zero problem is solved using the numerically very efficient function +<a href=\"Modelica://Modelica.Math.Nonlinear.solveOneNonlinearEquation\">Modelica.Math.Nonlinear.solveOneNonlinearEquation</a>. +For the application of this function, it must be ensured that <i>f(p_adsorpt)</i> +has a different sign for the upper and lower limits of <i>p_adsorpt</i>. To ensure +the different signs, the upper and lower limits are determined in an upstream loop. +<br/><br/> +Functions that inherit properties from this partial function have to redeclare +the function <i>func_x_pT</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_p_xT_num; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_pi_pT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_pi_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..57376ca810399eeb4b26030c259f6d19b683b589 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_pi_pT.mo @@ -0,0 +1,68 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_pi_pT + "Base function for isotherm models of pure components: Reduced spreading pressure as function of pressure and temperature" + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure; + + input Modelica.Units.SI.Pressure integral_pi_lb + "Lower limit of integral when calculating the reduced spreading pressure + numerically (should be 0)" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance + "Tolerance for numerical calculation (required if reduced spreading pressure + is calculated numerically (i.e., integral))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + /* Note that optional numerical inputs do not have default values as this + function is used as functional input argument within the "Ideal Adsorbed + Solution Theory," a multi-component adsorption isotherm model. Using default + values resulted in translation errors. */ + + // + // Definition of outputs + // + output SorpLib.Units.ReducedSpreadingPressure pi + "Reduced spreading pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the reduced spreading +pressure <i>pi</i> as a function of the equilibrium pressure <i>p_adsorpt</i> and +equilibrium temperature <i>T_adsorpt</i>. Defined inputs are the molar mass of +the adsorptive <i>M_adsorptive</i>, the equilibrium pressure <i>p_adsorpt</i>, +the equilibrium temperature <i>T_adsorpt</i>, and the coefficients of the isotherm +model <i>c</i>. The coefficients of the isotherm model <i>c</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Optional inputs regarding numerics are +the lower integral bound (<i>integral_pi_lb</i>) and the tolerance (<i>tolerance</i>), +only required if this function cannot be solved analytically. Besides, this partial +function defines the reduced spreading pressure <i>pi</i> as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_pi_pT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_pi_pT_num.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_pi_pT_num.mo new file mode 100644 index 0000000000000000000000000000000000000000..8cbc0b13e1b05b841e780cf841576e8e6cb82a73 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_pi_pT_num.mo @@ -0,0 +1,82 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_pi_pT_num + "Base function for isotherm models of pure components: Reduced spreading pressure as function of pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT; + + // + // Definition of protected replacable functions + // +protected + replaceable function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.x_pT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT + "Calculates uptake as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions")); + + // + // Definition of protected functions + // +protected + function func_pi_num + "Integrand required for calculating the reduced spreading pressure numerically" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature"; + input Real c[:] + "Coefficients of isotherm model"; + algorithm + y := func_x_pT(p_adsorpt=u, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) / + max(u, Modelica.Constants.small) + "Integrand 'x(p,T,c) / p' required for calculating the reduced spreading + pressure"; + end func_pi_num; + +algorithm + pi := 1/M_adsorptive * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function func_pi_num(T_adsorpt=T_adsorpt, c=c), + a=integral_pi_lb, + b=p_adsorpt, + tolerance=tolerance) + "Calculation of the reduced spreading pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the reduced spreading +pressure <i>pi</i> as a function of the equilibrium pressure <i>p_adsorpt</i> and +equilibrium temperature <i>T_adsorpt</i>. Defined inputs are the molar mass of +the adsorptive <i>M_adsorptive</i>, the equilibrium pressure <i>p_adsorpt</i>, +the equilibrium temperature <i>T_adsorpt</i>, and the coefficients of the isotherm +model <i>c</i>. The coefficients of the isotherm model <i>c</i> may depend on the +equilibrium temperature <i>T_adsorpt</i>. Optional inputs regarding numerics are +the lower integral bound (<i>integral_pi_lb</i>) and the tolerance (<i>tolerance</i>). +Besides, this partial function defines the reduced spreading pressure <i>pi</i> as +the output. +<br/><br/> +With this function, the reduced spreading pressure <i>pi</i> is determined +numerically by using the numerically very efficient function +<a href=\"Modelica://Modelica.Math.Nonlinear.quadratureLobatto\">Modelica.Math.Nonlinear.quadratureLobatto</a>. +<br/><br/> +Functions that inherit properties from this partial function have to redeclare +the function <i>func_x_pT</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_pi_pT_num; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_x_pT.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_x_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..6983de39d0a07c5de8b4fbdaa7d57f3b3e9474f3 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialPure_x_pT.mo @@ -0,0 +1,70 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial function PartialPure_x_pT + "Base function for isotherm models of pure components: Uptake as function of pressure and temperature" + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure; + + input Modelica.Units.SI.Pressure p_adsorpt_lb_start + "Lower bound of equilibrium pressure (required if inverse is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Modelica.Units.SI.Pressure p_adsorpt_ub_start + "Upper bound of equilibrium pressure (required if inverse is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance + "Tolerance for numerical calculation (required if inverse is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + /* Note that optional numerical inputs do not have default values as this + function is used as functional input argument within the "Ideal Adsorbed + Solution Theory," a multi-component adsorption isotherm model. Using default + values resulted in translation errors. */ + + // + // Definition of outputs + // + output SorpLib.Units.Uptake x_adsorpt + "Equilibrium uptake of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial function is the basic function for calculating the equilibrium uptake +<i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i> and +equilibrium temperature <i>T_adsorpt</i>. Defined inputs are the equilibrium pressure +<i>p_adsorpt</i>, the equilibrium temperature <i>T_adsorpt</i>, and the coefficients +of the isotherm model <i>c</i>. The coefficients of the isotherm model <i>c</i> +may depend on the equilibrium temperature <i>T_adsorpt</i>. Optional inputs regarding +numerics are the lower bound (<i>p_adsorpt_lb_start</i>) and upper bound +(<i>p_adsorpt_ub_start</i>) of the equilibrium pressure and the tolerance +(<i>tolerance</i>), only required if the inverse of this function cannot be +solved analytically. Besides, the equilibrium uptake <i>x_adsorpt</i> is defined +as the output. +<br/><br/> +Functions that inherit properties from this partial function may have to implement +further inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPure_x_pT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMulti.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMulti.mo new file mode 100644 index 0000000000000000000000000000000000000000..afd39e330097f88ee2788d203bf10bc9796c9ac6 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMulti.mo @@ -0,0 +1,489 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial model PartialTestMulti + "Base model for testers of isotherm models describing multi component adsorption" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real p_adsorpt_der(unit="Pa/s") = 1 + "Prescriped sloped of equilibrium pressure to test isotherm model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Real T_adsorpt_der(unit="K/s") = 0 + "Prescriped sloped of equilibrium temperature to test isotherm model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Real[no_components-1] y_i_der(each unit="mol/(mol.s)")= + fill(0, no_components-1) + "Prescriped sloped of mole fractions of independent components in the gas or + vapor phase to test isotherm model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Pressure p_adsorpt_start = 0 + "Start value of equilibrium pressure" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.MoleFraction[no_components-1] y_i_start= + fill(1/no_components, no_components-1) + "Start value of mole fractions of independent components in the gas or vapor + phase (sum must <= 1)" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Temperature T_adsorpt_start = 298.15 + "Start value of equilibrium temperature" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + + parameter Boolean print_asserts = true + "= true, if assertations shall be printed; otherwise, no assertations are printed" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_p_xyT = true + "= true, if function 'func_p_xyT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_y_pxT = true + "= true, if function 'func_y_pxT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_py_xT = true + "= true, if function 'func_py_xT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_dx_dp = true + "= true, if function 'func_dx_dp' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_dx_dy = true + "= true, if function 'func_dx_dy' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_dx_dT = true + "= true, if function 'func_dx_dT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + + replaceable package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponents + "Package providing all functions of the isotherm model" + annotation (Dialog(tab="General", group="Isotherm Model"), + choicesAllMatching=true); + parameter Integer no_components = 1 + "Number of components of the isotherm model" + annotation (Dialog(tab="General", group="Isotherm Model"), + Evaluate=true, + HideResult=true); + parameter Integer no_coefficients = 1 + "Number of coefficients of the isotherm model (i.e., highest number among + different components)" + annotation (Dialog(tab="General", group="Isotherm Model"), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.Pressure p_threshold_min = 0 + "Threshold for partial pressures of all components: If a partial pressure is + below the threshold, its value is set to the threshold" + annotation (Dialog(tab="Numerics", group="Limiter"), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.PressureDifference dp = 1e-6 + "Pressure difference used to calculate partial derivatives numerically" + annotation (Dialog(tab="Numerics", group="Derivatives"), + Evaluate=true, + HideResult=true); + parameter Real dy = 1e-6 + "Mole fraction difference used to calculate partial derivatives numerically" + annotation (Dialog(tab="Numerics", group="Derivatives"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-6 + "Temperature difference used to calculate partial derivatives numerically" + annotation (Dialog(tab="Numerics", group="Derivatives"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_adsorpt(start=p_adsorpt_start, fixed=true) + "Equilibrium pressure"; + Modelica.Units.SI.MoleFraction[no_components-1] y_i(start=y_i_start, each fixed=true) + "Independent mole fractions"; + Modelica.Units.SI.Temperature T_adsorpt(start=T_adsorpt_start, fixed=true) + "Equilibrium temperature"; + + Modelica.Units.SI.Pressure p_adsorpt_inv_xyT + "Equilibrium pressure calculated via inverse function 'p_xyT'"; + Modelica.Units.SI.Pressure p_adsorpt_inv_xT + "Equilibrium pressure calculated via inverse function 'p_xT'"; + + Modelica.Units.SI.MoleFraction[no_components-1] y_i_inv_pxT(each min=-1) + "Independent mole fractions calculated via inverse function 'p_pxT'"; + Modelica.Units.SI.MoleFraction[no_components-1] y_i_inv_xT(each min=-1) + "Independent mole fractions calculated via inverse function 'p_xT'"; + + SorpLib.Units.Uptake[no_components] x_adsorpt + "Equilibrium uptakes"; + + SorpLib.Units.DerUptakeByPressure[no_components] dx_adsorpt_dp_adsorpt + "Partial derivative of the uptakes w.r.t. pressure at constant mole fractions + and temperature"; + SorpLib.Units.DerUptakeByPressure[no_components] dx_adsorpt_dp_adsorpt_num + "Partial derivative of the uptakes w.r.t. pressure at constant mole fractions + and temperature calculated numerically"; + + SorpLib.Units.DerUptakeByMolarFraction[no_components,no_components-1] dx_adsorpt_dy_i + "Partial derivatives of the uptakes w.r.t. the molar fractions of independent + gas phase components at constant pressure and temperature"; + SorpLib.Units.DerUptakeByMolarFraction[no_components,no_components-1] dx_adsorpt_dy_i_num + "Partial derivatives of the uptakes w.r.t. the molar fractions of independent + gas phase components at constant pressure and temperature calculated numerically"; + + SorpLib.Units.DerUptakeByTemperature[no_components] dx_adsorpt_dT_adsorpt + "Partial derivatives of the uptakes w.r.t. temperature at constant pressure + and mole fractions"; + SorpLib.Units.DerUptakeByTemperature[no_components] dx_adsorpt_dT_adsorpt_num + "Partial derivatives of the uptakes w.r.t. temperature at constant pressure + and mole fractions calculated numerically"; + + Real[no_coefficients,no_components] c + "Coefficients of isotherm model"; + Real[no_coefficients,no_components] dc_dT + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + +protected + Real[no_coefficients,no_components] c_pdT + "Coefficients of isotherm model: T + 1e-6 K"; + Real[no_coefficients,no_components] c_mdT + "Coefficients of isotherm model: T - 1e-6 K"; + + function dx_dy_num + "Calculates partial derivatives of equilibrium uptakes w.r.t. independent mole + fractions numericalls at constant pressure and temperature" + + // + // Note that this function is a workaround for OpenModelica because OpenModelica + // apparently cannot handle the assignment of a vector to the column of a + // matrix. + // + + // + // Definition of inputs + // + input Real[:,:] c + "Coefficients of isotherm model"; + input Real p_adsorpt + "Equilibrium pressure"; + input Real[size(c,2)-1] y_i + "Independent mole fractions"; + input Real T_adsorpt + "Equilibrium temperature"; + input Real p_threshold_min + "Threshold for partial pressures of all components: If a partial pressure is + below the threshold, its value is set to the threshold"; + input Real dy + "Mole fraction difference used to calculate partial derivatives numerically"; + + // + // Definition of outputs + // + output SorpLib.Units.DerUptakeByMolarFraction[size(c,2),size(c,2)-1] dx_adsorpt_dy_i_num + "Partial derivatives of the uptakes w.r.t. the molar fractions of independent + gas phase components calculated numerically"; + + // + // Definition of variables + // + protected + SorpLib.Units.DerUptakeByMolarFraction[size(c,2)] dx_adsorpt_dy_i_num_tmp + "Temporary partial derivatives of the uptakes w.r.t. the molar fraction + of independent gas phase component at constant pressure and temperature + calculated numerically"; + + algorithm + for ind_y_i in 1:size(c,2)-1 loop + // + // Calculate partial darivatives for each independent mole fraction + // + dx_adsorpt_dy_i_num_tmp :=(IsothermModel.x_pyT( + p_adsorpt=p_adsorpt, + y_i=cat(1, y_i[1:ind_y_i - 1], {y_i[ind_y_i] + dy}, y_i[ind_y_i + 1:size(c,2) - 1]), + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) .- + IsothermModel.x_pyT( + p_adsorpt=p_adsorpt, + y_i=cat(1, y_i[1:ind_y_i - 1], {y_i[ind_y_i] - dy}, y_i[ind_y_i + 1:size(c,2) - 1]), + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min)) ./ (2*dy) + "Temporary partial derivative of the uptake w.r.t. independent molar + fraction at constant pressure and temeprature calculated numerically"; + + // + // Assign temporary results to output matrix + // + for ind_com in 1:size(c,2) loop + dx_adsorpt_dy_i_num[ind_com,ind_y_i] := dx_adsorpt_dy_i_num_tmp[ind_com] + "Partial derivatives of the uptakes w.r.t. the molar fractions of + independent gas phase components at contant pressure and temperature + calculated numerically"; + end for; + end for; + end dx_dy_num; + +equation + der(p_adsorpt) = p_adsorpt_der + "Predecsriped slope of p_adsorpt to demonstrate the isotherm model"; + der(y_i) = y_i_der + "Predecsriped slope of y_i to demonstrate the isotherm model"; + der(T_adsorpt) = T_adsorpt_der + "Predecsriped slope of T_adsorpt to demonstrate the isotherm model"; + + if check_func_p_xyT then + p_adsorpt_inv_xyT = IsothermModel.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, + c=c, p_threshold_min=p_threshold_min) + "Equilibrium pressure calculated via the inverse function 'p_xyT'"; + else + p_adsorpt_inv_xyT = -1 + "Equilibrium pressure calculated via the inverse function 'p_xyT'"; + end if; + + if check_func_y_pxT then + y_i_inv_pxT = IsothermModel.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, + c=c, p_threshold_min=p_threshold_min) + "Independent mole fractions calculated via the inverse function 'y_pxT'"; + else + y_i_inv_pxT = fill(-1, no_components-1) + "Independent mole fractions calculated via the inverse function 'y_pxT'"; + end if; + + if check_func_py_xT then + (p_adsorpt_inv_xT, y_i_inv_xT) = + IsothermModel.py_xT(x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, + c=c, p_threshold_min=p_threshold_min) + "Independent mole fractions calculated via the inverse function 'y_xT'"; + else + p_adsorpt_inv_xT = -1 + "Equilibrium pressure calculated via the inverse function 'p_xT'"; + y_i_inv_xT = fill(-1, no_components-1) + "Independent mole fractions calculated via the inverse function 'y_xT'"; + end if; + + x_adsorpt = IsothermModel.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, + c=c, p_threshold_min=p_threshold_min) + "Equilibrium uptakes"; + + if check_func_dx_dp then + dx_adsorpt_dp_adsorpt = IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, + c=c, p_threshold_min=p_threshold_min) + "Partial derivative of the uptake w.r.t. pressure at constant mole fractions + and temeprature"; + dx_adsorpt_dp_adsorpt_num = ( + IsothermModel.x_pyT(p_adsorpt=p_adsorpt+dp, y_i=y_i, T_adsorpt=T_adsorpt, + c=c, p_threshold_min=p_threshold_min) .- + IsothermModel.x_pyT(p_adsorpt=p_adsorpt-dp, y_i=y_i, T_adsorpt=T_adsorpt, + c=c, p_threshold_min=p_threshold_min)) ./ + (2*dp) + "Partial derivative of the uptake w.r.t. pressure at constant mole fractions + and temeprature calculated numerically"; + else + dx_adsorpt_dp_adsorpt = fill(-1, no_components) + "Partial derivative of the uptake w.r.t. pressure at constant mole fractions + and temeprature"; + dx_adsorpt_dp_adsorpt_num = fill(-1, no_components) + "Partial derivative of the uptake w.r.t. pressure at constant mole fractions + and temeprature calculated numerically"; + end if; + + if check_func_dx_dy then + dx_adsorpt_dy_i = IsothermModel.dx_dy( + p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, + c=c, p_threshold_min=p_threshold_min) + "Partial derivative of the uptake w.r.t. independent molar fractions at + constant pressure and temperature"; + + dx_adsorpt_dy_i_num = dx_dy_num( + p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, + p_threshold_min=p_threshold_min,dy=dy) + "Partial derivative of the uptake w.r.t. temperature at constant pressure + and temperature calculated numerically"; + else + dx_adsorpt_dy_i = fill(-1, no_components, no_components-1) + "Partial derivative of the uptake w.r.t. independent molar fractions at + constant pressure and temperature"; + dx_adsorpt_dy_i_num = fill(-1, no_components, no_components-1) + "Partial derivative of the uptake w.r.t. independent molar fractions at + constant pressure and temperature calculated numerically"; + end if; + + if check_func_dx_dT then + dx_adsorpt_dT_adsorpt = IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, + c=c, dc_dT_adsorpt=dc_dT, + p_threshold_min=p_threshold_min) + "Partial derivative of the uptake w.r.t. temperature at constant pressure + and mole fractions"; + dx_adsorpt_dT_adsorpt_num = ( + IsothermModel.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt+dT, + c=c_pdT, p_threshold_min=p_threshold_min) .- + IsothermModel.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt-dT, + c=c_mdT, p_threshold_min=p_threshold_min)) ./ + (2*dT) + "Partial derivative of the uptake w.r.t. temperature at constant pressure + and mole fractions calculated numerically"; + else + dx_adsorpt_dT_adsorpt = fill(-1, no_components) + "Partial derivative of the uptake w.r.t. temperature at constant pressure + and mole fractions"; + dx_adsorpt_dT_adsorpt_num = fill(-1, no_components) + "Partial derivative of the uptake w.r.t. temperature at constant pressure + and mole fractions calculated numerically"; + end if; + + // + // Definition of assertions: Check thermodynamics and numerical implementation + // of isotherm model + // + assert(1-sum(y_i) >= 0 and 1-sum(y_i) <= 1, + "Sum of mole fractions must be 1 mol/mol!", + level = AssertionLevel.error); + + if print_asserts then + if check_func_p_xyT then + assert(abs(p_adsorpt-p_adsorpt_inv_xyT) < 1e-6, + "Inverse function of isotherm model is not valid: Deviation (|" + + String(abs(p_adsorpt-p_adsorpt_inv_xyT)) + + "|) is greater than 1e-6 Pa!", + level = AssertionLevel.warning); + end if; + + if check_func_y_pxT then + for ind_comp in 1:no_components-1 loop + assert(abs(y_i[ind_comp]-y_i_inv_pxT[ind_comp]) < 1e-6, + "Inverse function of isotherm model is not valid: For component " + + String(ind_comp) + + ", deviation (|" + + String(abs(y_i[ind_comp]-y_i_inv_pxT[ind_comp])) + + "|) is greater than 1e-6 mol/mol!", + level = AssertionLevel.warning); + end for; + end if; + + if check_func_py_xT then + assert(abs(p_adsorpt-p_adsorpt_inv_xT) < 1e-6, + "Inverse function of isotherm model is not valid: Deviation (|" + + String(abs(p_adsorpt-p_adsorpt_inv_xT)) + + "|) is greater than 1e-6 Pa!", + level = AssertionLevel.warning); + + for ind_comp in 1:no_components-1 loop + assert(abs(y_i[ind_comp]-y_i_inv_xT[ind_comp]) < 1e-6, + "Inverse function of isotherm model is not valid: For component " + + String(ind_comp) + + ", deviation (|" + + String(abs(y_i[ind_comp]-y_i_inv_xT[ind_comp])) + + "|) is greater than 1e-6 mol/mol!", + level = AssertionLevel.warning); + end for; + end if; + + if check_func_dx_dp then + for ind_comp in 1:no_components loop + assert(abs(dx_adsorpt_dp_adsorpt[ind_comp]-dx_adsorpt_dp_adsorpt_num[ind_comp]) < 1e-6, + "Partial derivative of isotherm model w.r.t. pressure at constant " + + "mole fractions and temperature is not valid: For component " + + String(ind_comp) + + ", deviation (|" + + String(abs(dx_adsorpt_dp_adsorpt[ind_comp]-dx_adsorpt_dp_adsorpt_num[ind_comp])) + + "|) is greater than 1e-6 kg/(kg.Pa)!", + level = AssertionLevel.warning); + end for; + end if; + + if check_func_dx_dy then + for ind_comp in 1:no_components loop + for ind_y_i in 1:no_components-1 loop + assert(abs(dx_adsorpt_dy_i[ind_comp,ind_y_i]-dx_adsorpt_dy_i_num[ind_comp,ind_y_i]) < 1e-6, + "Partial derivative of isotherm model w.r.t. pressure at constant " + + "pressure and temperature is not valid: For component " + + String(ind_comp) + + " and independent mole fraction " + + String(ind_y_i) + + ", deviation (|" + + String(abs(dx_adsorpt_dy_i[ind_comp,ind_y_i]-dx_adsorpt_dy_i_num[ind_comp,ind_y_i])) + + "|) is greater than 1e-6 kg.mol/(kg.mol)!", + level = AssertionLevel.warning); + end for; + end for; + end if; + + if check_func_dx_dT then + for ind_comp in 1:no_components loop + assert(abs(dx_adsorpt_dT_adsorpt[ind_comp]-dx_adsorpt_dT_adsorpt_num[ind_comp]) < 1e-6, + "Partial derivative of isotherm model w.r.t. temperature at " + + "constant pressure and mole fractions is not valid: For component " + + String(ind_comp) + + ", deviation (|" + + String(abs(dx_adsorpt_dT_adsorpt[ind_comp]-dx_adsorpt_dT_adsorpt_num[ind_comp])) + + "|) is greater than 1e-6 kg/(kg.K)!", + level = AssertionLevel.warning); + end for; + end if; + end if; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the basic model for all testers of isotherm models describing +adsorption of multi components. +<br/><br/> +This partial model defines all relevant parameters, variables, and equations to +check (1) the classical form of isotherm models, (2) the inverse forms of isotherm +models, (3) the partial derivatives of the uptakes w.r.t. to pressure, (4) the +partial derivatives of the uptakes w.r.t. mole fractions of independent components +in the gas or vapor phase, and (5) the partial derivatives of the uptake w.r.t. +temperature. All partial derivatives are also implemented as central finite +differences to check for the analytical implementation of the partial derivatives. +<br/><br/> +Models that inherit properties from this partial model have to specify the number +of components and coefficients of the isotherm model <i>no_components</i> and +<i>no_coefficients</i>, respectively, and have to redeclare the seven functions +of the isotherm model <i>func_x_pyT</i>, <i>func_p_xyT</i>, <i>func_y_pxT</i>, +<i>func_py_xT</i>, <i>func_dx_dp</i>, <i>func_dx_dy</i>, and <i>func_dx_dT</i>. +Besides, the coefficients of the isotherm model (i.e., <i>c</i>, <i>c_pdT</i>, +and <i>c_mdT</i>) and their partial derivatives with respect to temperature +(i.e., <i>dc_dT</i>) have to be implemented. Additionally, it has to be specified +whether the equilibrium pressure (<i>p_adsorpt_der</i>), the mole fractions of +independent components in the gas or vapor phase (<i>y_i_der</i>), or the +equilibrium temperature (<i>T_adsorpt_der</i>) changes with time. +</p> +</html>")); +end PartialTestMulti; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMultiIAST.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMultiIAST.mo new file mode 100644 index 0000000000000000000000000000000000000000..f8df5e2f3e200599aec8d0e9de28624461e5904a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMultiIAST.mo @@ -0,0 +1,290 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial model PartialTestMultiIAST + "Base model for testers of isotherm models describing multi component adsorption based on the ideal adsorbed solution theory" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real p_adsorpt_der(unit="Pa/s") = 1 + "Prescriped sloped of equilibrium pressure to test isotherm model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Real T_adsorpt_der(unit="K/s") = 0 + "Prescriped sloped of equilibrium temperature to test isotherm model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Real[no_components-1] y_i_der(each unit="mol/(mol.s)")= + fill(0, no_components-1) + "Prescriped sloped of mole fractions of independent components in the gas or + vapor phase to test isotherm model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Pressure p_adsorpt_start = 0 + "Start value of equilibrium pressure" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.MoleFraction[no_components-1] y_i_start= + fill(1/no_components, no_components-1) + "Start value of mole fractions of independent components in the gas or vapor + phase (sum must <= 1)" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Temperature T_adsorpt_start = 298.15 + "Start value of equilibrium temperature" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + + parameter Boolean print_asserts = true + "= true, if assertations shall be printed; otherwise, no assertations are printed" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_p_xyT = true + "= true, if function 'func_p_xyT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_y_pxT = true + "= true, if function 'func_y_pxT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_py_xT = true + "= true, if function 'func_py_xT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_dx_dp = true + "= true, if function 'func_dx_dp' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_dx_dy = true + "= true, if function 'func_dx_dy' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_dx_dT = true + "= true, if function 'func_dx_dT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + + replaceable package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2 + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponentsIAST + "Package providing all functions of the IAST isotherm model" + annotation (Dialog(tab="General", group="Isotherm Model"), + choicesAllMatching=true); + parameter Integer no_components = 1 + "Number of components of the isotherm model" + annotation (Dialog(tab="General", group="Isotherm Model"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.MolarMass[no_components] M_i = fill(1, no_components) + "Molar masses of the components" + annotation (Dialog(tab="General", group="Isotherm Model"), + Evaluate=true, + HideResult=true); + + replaceable package IsothermModelComponent1 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Henry + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents + "Package providing all functions of the isotherm model of component 1" + annotation (Dialog(tab="General", group="Isotherm Model"), + choicesAllMatching=true); + parameter Integer no_coefficients_1 = 1 + "Number of coefficients of the first isotherm model" + annotation (Dialog(tab="General", group="Isotherm Model"), + Evaluate=true, + HideResult=true); + + replaceable package IsothermModelComponent2 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Henry + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents + "Package providing all functions of the isotherm model of component 2" + annotation (Dialog(tab="General", group="Isotherm Model"), + choicesAllMatching=true); + parameter Integer no_coefficients_2 = 1 + "Number of coefficients of the second isotherm model" + annotation (Dialog(tab="General", group="Isotherm Model"), + Evaluate=true, + HideResult=true); + + parameter SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST num + "Record definining numerics of the IAST algorithms" + annotation (Dialog(tab="Numerics", group="IAST"), + choicesAllMatching=true); + parameter Modelica.Units.SI.PressureDifference dp = 1e-4 + "Pressure difference used to calculate partial derivatives w.r.t. pressure" + annotation (Dialog(tab="Numerics", group="IAST")); + parameter Real dy = 1e-4 + "Mole fraction difference used to calculate partial derivatives w.r.t. independent + mole fractions" + annotation (Dialog(tab="Numerics", group="IAST")); + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-4 + "Temperature difference used to calculate partial derivatives w.r.t. temperature" + annotation (Dialog(tab="Numerics", group="IAST")); + parameter SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_1 + "Record definining numerics of the first component's isotherm model" + annotation (Dialog(tab="Numerics", group="Components"), + choicesAllMatching=true); + parameter SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_2 + "Record definining numerics of the second component's isotherm model" + annotation (Dialog(tab="Numerics", group="Components"), + choicesAllMatching=true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_adsorpt(start=p_adsorpt_start, fixed=true) + "Equilibrium pressure"; + Modelica.Units.SI.MoleFraction[no_components-1] y_i(start=y_i_start, each fixed=true) + "Independent mole fractions"; + Modelica.Units.SI.Temperature T_adsorpt(start=T_adsorpt_start, fixed=true) + "Equilibrium temperature"; + + Modelica.Units.SI.Pressure p_adsorpt_inv_xyT + "Equilibrium pressure calculated via inverse function 'p_xyT'"; + Modelica.Units.SI.Pressure p_adsorpt_inv_xT + "Equilibrium pressure calculated via inverse function 'p_xT'"; + + Modelica.Units.SI.MoleFraction[no_components-1] y_i_inv_pxT(each min=-1) + "Independent mole fractions calculated via inverse function 'p_pxT'"; + Modelica.Units.SI.MoleFraction[no_components-1] y_i_inv_xT(each min=-1) + "Independent mole fractions calculated via inverse function 'p_xT'"; + + SorpLib.Units.Uptake[no_components] x_adsorpt + "Equilibrium uptakes"; + + SorpLib.Units.DerUptakeByPressure[no_components] dx_adsorpt_dp_adsorpt + "Partial derivative of the uptakes w.r.t. pressure"; + SorpLib.Units.DerUptakeByMolarFraction[no_components,no_components-1] dx_adsorpt_dy_i + "Partial derivatives of the uptakes w.r.t. the molar fractions of independent + gas phase components"; + SorpLib.Units.DerUptakeByTemperature[no_components] dx_adsorpt_dT_adsorpt + "Partial derivatives of the uptakes w.r.t. temperature"; + + Real[no_coefficients_1] c_1 + "Coefficients of the first isotherm model"; + Real[no_coefficients_2] c_2 + "Coefficients of the second isotherm model"; + +protected + Real[no_coefficients_1] c_pdT_1 + "Coefficients of the first isotherm model: T + 1e-6 K"; + Real[no_coefficients_1] c_mdT_1 + "Coefficients of the first isotherm model: T - 1e-6 K"; + + Real[no_coefficients_2] c_pdT_2 + "Coefficients of the second isotherm model: T + 1e-6 K"; + Real[no_coefficients_2] c_mdT_2 + "Coefficients of the second isotherm model: T - 1e-6 K"; + +equation + der(p_adsorpt) = p_adsorpt_der + "Predecsriped slope of p_adsorpt to demonstrate the isotherm model"; + der(y_i) = y_i_der + "Predecsriped slope of y_i to demonstrate the isotherm model"; + der(T_adsorpt) = T_adsorpt_der + "Predecsriped slope of T_adsorpt to demonstrate the isotherm model"; + + // + // Definition of assertions: Check thermodynamics and numerical implementation + // of isotherm model + // + assert(1-sum(y_i) >= 0 and 1-sum(y_i) <= 1, + "Sum of mole fractions must be 1 mol/mol!", + level = AssertionLevel.error); + + if print_asserts then + if check_func_p_xyT then + assert(abs(p_adsorpt-p_adsorpt_inv_xyT) < 1e-6, + "Inverse function of isotherm model is not valid: Deviation (|" + + String(abs(p_adsorpt-p_adsorpt_inv_xyT)) + + "|) is greater than 1e-6 Pa!", + level = AssertionLevel.warning); + end if; + + if check_func_y_pxT then + for ind_comp in 1:no_components-1 loop + assert(abs(y_i[ind_comp]-y_i_inv_pxT[ind_comp]) < 1e-6, + "Inverse function of isotherm model is not valid: For component " + + String(ind_comp) + + ", deviation (|" + + String(abs(y_i[ind_comp]-y_i_inv_pxT[ind_comp])) + + "|) is greater than 1e-6 mol/mol!", + level = AssertionLevel.warning); + end for; + end if; + + if check_func_py_xT then + assert(abs(p_adsorpt-p_adsorpt_inv_xT) < 1e-6, + "Inverse function of isotherm model is not valid: Deviation (|" + + String(abs(p_adsorpt-p_adsorpt_inv_xT)) + + "|) is greater than 1e-6 Pa!", + level = AssertionLevel.warning); + + for ind_comp in 1:no_components-1 loop + assert(abs(y_i[ind_comp]-y_i_inv_xT[ind_comp]) < 1e-6, + "Inverse function of isotherm model is not valid: For component " + + String(ind_comp) + + ", deviation (|" + + String(abs(y_i[ind_comp]-y_i_inv_xT[ind_comp])) + + "|) is greater than 1e-6 mol/mol!", + level = AssertionLevel.warning); + end for; + end if; + end if; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the basic model for all testers of isotherm models +based on the ideal adsorbed solution theory (IAST) describing the adsorption +of multi components. +<br/><br/> +This partial model defines all relevant parameters, variables, and equations to +check (1) the classical form of isotherm models, (2) the inverse forms of isotherm +models, (3) the partial derivatives of the uptakes w.r.t. to pressure, (4) the +partial derivatives of the uptakes w.r.t. mole fractions of independent components +in the gas or vapor phase, and (5) the partial derivatives of the uptake w.r.t. +temperature. +<br/><br/> +Models that inherit properties from this partial model have to specify the number +of components <i>no_components</i> and number of coefficients for each pure +component isotherm model <i>no_coefficients_i</i>, respectively, and have to redeclare +all functions of the multi and pure component isotherm models <i>func_i</i>. +Besides, the coefficients of each isotherm model (i.e., <i>c_i</i>, <i>c_pdT_i</i>, +and <i>c_mdT_i</i>) have to be implemented. Additionally, it has to be specified +whether the equilibrium pressure (<i>p_adsorpt_der</i>), the mole fractions of +independent components in the gas or vapor phase (<i>y_i_der</i>), or the +equilibrium temperature (<i>T_adsorpt_der</i>) changes with time. Finally, the +algorithm has to be complemented such that the functions of the multi component +isotherm model <i>func_i</i> are used. +<br/><br/> +Note that the parameters of this model only allow to check the IAST for two +components. To check the IAST for more than two components, further paramters +have to be added. +</p> +</html>")); +end PartialTestMultiIAST; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMultiIAST_N2.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMultiIAST_N2.mo new file mode 100644 index 0000000000000000000000000000000000000000..1b8810455a387445e80bca97d8abcba5b4cdcf4f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMultiIAST_N2.mo @@ -0,0 +1,242 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial model PartialTestMultiIAST_N2 + "Base model for testers of isotherm models describing two-component adsorption based on the ideal adsorbed solution theory" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMultiIAST( + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2); + +equation + if check_func_p_xyT then + p_adsorpt_inv_xyT = IsothermModel.p_xyT( + x_adsorpt=x_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) + "Equilibrium pressure calculated via the inverse function 'p_xyT'"; + else + p_adsorpt_inv_xyT = -1 + "Equilibrium pressure calculated via the inverse function 'p_xyT'"; + end if; + + if check_func_y_pxT then + y_i_inv_pxT = IsothermModel.y_pxT( + p_adsorpt=p_adsorpt, + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) + "Independent mole fractions calculated via the inverse function 'y_pxT'"; + else + y_i_inv_pxT = fill(-1, no_components-1) + "Independent mole fractions calculated via the inverse function 'y_pxT'"; + end if; + + if check_func_py_xT then + (p_adsorpt_inv_xT, y_i_inv_xT) = IsothermModel.py_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) + "Independent mole fractions calculated via the inverse function 'y_xT'"; + else + p_adsorpt_inv_xT = -1 + "Equilibrium pressure calculated via the inverse function 'p_xT'"; + y_i_inv_xT = fill(-1, no_components-1) + "Independent mole fractions calculated via the inverse function 'y_xT'"; + end if; + + x_adsorpt = IsothermModel.x_pyT( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) + "Equilibrium uptakes"; + + if check_func_dx_dp then + dx_adsorpt_dp_adsorpt = IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + dp=dp) + "Partial derivative of the uptake w.r.t. pressure at constant mole fractions + and temperature"; + else + dx_adsorpt_dp_adsorpt = fill(-1, no_components) + "Partial derivative of the uptake w.r.t. pressure at constant mole fractions + and temperature"; + end if; + + if check_func_dx_dy then + dx_adsorpt_dy_i = IsothermModel.dx_dy( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + dy=dy) + "Partial derivative of the uptake w.r.t. independent molar fractions at + constant pressure and temperature"; + else + dx_adsorpt_dy_i = fill(-1, no_components, no_components-1) + "Partial derivative of the uptake w.r.t. independent molar fractions at + constant pressure and temperature"; + end if; + + if check_func_dx_dT then + dx_adsorpt_dT_adsorpt = IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_pdT_1=c_pdT_1, + c_mdT_1=c_mdT_1, + c_pdT_2=c_pdT_2, + c_mdT_2=c_mdT_2, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + dT=dT) + "Partial derivative of the uptake w.r.t. temperature at constant pressure + and mole fractions"; + else + dx_adsorpt_dT_adsorpt = fill(-1, no_components) + "Partial derivative of the uptake w.r.t. temperature at constant pressure + and mole fractions"; + end if; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the basic model for all testers of isotherm models +based on the ideal adsorbed solution theory (IAST) describing the adsorption +of two components. +<br/><br/> +This partial model defines all relevant parameters, variables, and equations to +check (1) the classical form of isotherm models, (2) the inverse forms of isotherm +models, (3) the partial derivatives of the uptakes w.r.t. to pressure, (4) the +partial derivatives of the uptakes w.r.t. mole fractions of independent components +in the gas or vapor phase, and (5) the partial derivatives of the uptake w.r.t. +temperature. +<br/><br/> +Models that inherit properties from this partial model have to specify the number +of components <i>no_components</i> and number of coefficients for each pure +component isotherm model <i>no_coefficients_i</i>, respectively, and have to redeclare +all functions of the multi and pure component isotherm models <i>func_i</i>. +Besides, the coefficients of each isotherm model (i.e., <i>c_i</i>, <i>c_pdT_i</i>, +and <i>c_mdT_i</i>) have to be implemented. Additionally, it has to be specified +whether the equilibrium pressure (<i>p_adsorpt_der</i>), the mole fractions of +independent components in the gas or vapor phase (<i>y_i_der</i>), or the +equilibrium temperature (<i>T_adsorpt_der</i>) changes with time. +</p> +</html>")); +end PartialTestMultiIAST_N2; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMultiIAST_N3.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMultiIAST_N3.mo new file mode 100644 index 0000000000000000000000000000000000000000..b868b5c4dc7e5039d7da3bace02604da8af14981 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestMultiIAST_N3.mo @@ -0,0 +1,326 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial model PartialTestMultiIAST_N3 + "Base model for testers of isotherm models describing three-component adsorption based on the ideal adsorbed solution theory" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMultiIAST( + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3); + + // + // Definition of parameters + // + replaceable package IsothermModelComponent3 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Henry + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents + "Package providing all functions of the isotherm model of component 3" + annotation (Dialog(tab="General", group="Isotherm Model"), + choicesAllMatching=true); + parameter Integer no_coefficients_3 = 1 + "Number of coefficients of the third isotherm model" + annotation (Dialog(tab="General", group="Isotherm Model"), + Evaluate=true, + HideResult=true); + + parameter SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="Numerics", group="Components"), + choicesAllMatching=true); + + // + // Definition of variables + // + Real[no_coefficients_3] c_3 + "Coefficients of the third isotherm model"; + +protected + Real[no_coefficients_3] c_pdT_3 + "Coefficients of the third isotherm model: T + 1e-6 K"; + Real[no_coefficients_3] c_mdT_3 + "Coefficients of the third isotherm model: T - 1e-6 K"; + +equation + if check_func_p_xyT then + p_adsorpt_inv_xyT = IsothermModel.p_xyT( + x_adsorpt=x_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + func_x_pT_3=IsothermModelComponent3.x_pT, + func_p_xT_3=IsothermModelComponent3.p_xT, + func_dx_dp_3=IsothermModelComponent3.dx_dp, + func_pi_pT_3=IsothermModelComponent3.pi_pT, + func_p_piT_3=IsothermModelComponent3.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Equilibrium pressure calculated via the inverse function 'p_xyT'"; + else + p_adsorpt_inv_xyT = -1 + "Equilibrium pressure calculated via the inverse function 'p_xyT'"; + end if; + + if check_func_y_pxT then + y_i_inv_pxT = IsothermModel.y_pxT( + p_adsorpt=p_adsorpt, + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + func_x_pT_3=IsothermModelComponent3.x_pT, + func_p_xT_3=IsothermModelComponent3.p_xT, + func_dx_dp_3=IsothermModelComponent3.dx_dp, + func_pi_pT_3=IsothermModelComponent3.pi_pT, + func_p_piT_3=IsothermModelComponent3.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Independent mole fractions calculated via the inverse function 'y_pxT'"; + else + y_i_inv_pxT = fill(-1, no_components-1) + "Independent mole fractions calculated via the inverse function 'y_pxT'"; + end if; + + if check_func_py_xT then + (p_adsorpt_inv_xT, y_i_inv_xT) = IsothermModel.py_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + func_x_pT_3=IsothermModelComponent3.x_pT, + func_p_xT_3=IsothermModelComponent3.p_xT, + func_dx_dp_3=IsothermModelComponent3.dx_dp, + func_pi_pT_3=IsothermModelComponent3.pi_pT, + func_p_piT_3=IsothermModelComponent3.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Independent mole fractions calculated via the inverse function 'y_xT'"; + else + p_adsorpt_inv_xT = -1 + "Equilibrium pressure calculated via the inverse function 'p_xT'"; + y_i_inv_xT = fill(-1, no_components-1) + "Independent mole fractions calculated via the inverse function 'y_xT'"; + end if; + + x_adsorpt = IsothermModel.x_pyT( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + func_x_pT_3=IsothermModelComponent3.x_pT, + func_p_xT_3=IsothermModelComponent3.p_xT, + func_dx_dp_3=IsothermModelComponent3.dx_dp, + func_pi_pT_3=IsothermModelComponent3.pi_pT, + func_p_piT_3=IsothermModelComponent3.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Equilibrium uptakes"; + + if check_func_dx_dp then + dx_adsorpt_dp_adsorpt = IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + func_x_pT_3=IsothermModelComponent3.x_pT, + func_p_xT_3=IsothermModelComponent3.p_xT, + func_dx_dp_3=IsothermModelComponent3.dx_dp, + func_pi_pT_3=IsothermModelComponent3.pi_pT, + func_p_piT_3=IsothermModelComponent3.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3, + dp=dp) + "Partial derivative of the uptake w.r.t. pressure at constant mole fractions + and temperature"; + else + dx_adsorpt_dp_adsorpt = fill(-1, no_components) + "Partial derivative of the uptake w.r.t. pressure at constant mole fractions + and temperature"; + end if; + + if check_func_dx_dy then + dx_adsorpt_dy_i = IsothermModel.dx_dy( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + func_x_pT_3=IsothermModelComponent3.x_pT, + func_p_xT_3=IsothermModelComponent3.p_xT, + func_dx_dp_3=IsothermModelComponent3.dx_dp, + func_pi_pT_3=IsothermModelComponent3.pi_pT, + func_p_piT_3=IsothermModelComponent3.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3, + dy=dy) + "Partial derivative of the uptake w.r.t. independent molar fractions at + constant pressure and temperature"; + else + dx_adsorpt_dy_i = fill(-1, no_components, no_components-1) + "Partial derivative of the uptake w.r.t. independent molar fractions at + constant pressure and temperature"; + end if; + + if check_func_dx_dT then + dx_adsorpt_dT_adsorpt = IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + c_pdT_1=c_pdT_1, + c_mdT_1=c_mdT_1, + c_pdT_2=c_pdT_2, + c_mdT_2=c_mdT_2, + c_pdT_3=c_pdT_3, + c_mdT_3=c_mdT_3, + func_x_pT_1=IsothermModelComponent1.x_pT, + func_p_xT_1=IsothermModelComponent1.p_xT, + func_dx_dp_1=IsothermModelComponent1.dx_dp, + func_pi_pT_1=IsothermModelComponent1.pi_pT, + func_p_piT_1=IsothermModelComponent1.p_piT, + func_x_pT_2=IsothermModelComponent2.x_pT, + func_p_xT_2=IsothermModelComponent2.p_xT, + func_dx_dp_2=IsothermModelComponent2.dx_dp, + func_pi_pT_2=IsothermModelComponent2.pi_pT, + func_p_piT_2=IsothermModelComponent2.p_piT, + func_x_pT_3=IsothermModelComponent3.x_pT, + func_p_xT_3=IsothermModelComponent3.p_xT, + func_dx_dp_3=IsothermModelComponent3.dx_dp, + func_pi_pT_3=IsothermModelComponent3.pi_pT, + func_p_piT_3=IsothermModelComponent3.p_piT, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3, + dT=dT) + "Partial derivative of the uptake w.r.t. temperature at constant pressure + and mole fractions"; + else + dx_adsorpt_dT_adsorpt = fill(-1, no_components) + "Partial derivative of the uptake w.r.t. temperature at constant pressure + and mole fractions"; + end if; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the basic model for all testers of isotherm models +based on the ideal adsorbed solution theory (IAST) describing the adsorption +of three components. +<br/><br/> +This partial model defines all relevant parameters, variables, and equations to +check (1) the classical form of isotherm models, (2) the inverse forms of isotherm +models, (3) the partial derivatives of the uptakes w.r.t. to pressure, (4) the +partial derivatives of the uptakes w.r.t. mole fractions of independent components +in the gas or vapor phase, and (5) the partial derivatives of the uptake w.r.t. +temperature. +<br/><br/> +Models that inherit properties from this partial model have to specify the number +of components <i>no_components</i> and number of coefficients for each pure +component isotherm model <i>no_coefficients_i</i>, respectively, and have to redeclare +all functions of the multi and pure component isotherm models <i>func_i</i>. +Besides, the coefficients of each isotherm model (i.e., <i>c_i</i>, <i>c_pdT_i</i>, +and <i>c_mdT_i</i>) have to be implemented. Additionally, it has to be specified +whether the equilibrium pressure (<i>p_adsorpt_der</i>), the mole fractions of +independent components in the gas or vapor phase (<i>y_i_der</i>), or the +equilibrium temperature (<i>T_adsorpt_der</i>) changes with time. +</p> +</html>")); +end PartialTestMultiIAST_N3; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestPure.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestPure.mo new file mode 100644 index 0000000000000000000000000000000000000000..dc4ea9ff0bb1a54c2302587708f5d2d21ad110e5 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestPure.mo @@ -0,0 +1,491 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial model PartialTestPure + "Base model for testers of isotherm models describing pure component adsorption" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real p_adsorpt_der(unit="Pa/s") = 1 + "Prescriped sloped of equilibrium pressure to test isotherm model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Real T_adsorpt_der(unit="K/s") = 0 + "Prescriped sloped of equilibrium temperature to test isotherm model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Pressure p_adsorpt_start = 0 + "Start value of equilibrium pressure" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Temperature T_adsorpt_start = 298.15 + "Start value of equilibrium temperature" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.MolarMass M_adsorptive = 0.018 + "Molar mass of adsorptive" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=true, + HideResult=true); + + parameter Boolean print_asserts = true + "= true, if assertations shall be printed; otherwise, no assertations are printed" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_p_xT = true + "= true, if function 'func_p_xT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_dx_dp = true + "= true, if function 'func_dx_dp' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_dx_dT = true + "= true, if function 'func_dx_dT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_ddx_dp_dp = true + "= true, if function 'func_ddx_dp_dp' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_ddx_dT_dT = true + "= true, if function 'func_ddx_dT_dT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_ddx_dp_dT = true + "= true, if function 'ddx_dp_dT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_pi_pT = true + "= true, if function 'func_pi_pT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_p_piT = true + "= true, if function 'func_p_piT' is checked; otherwise, function is not checked" + annotation (Dialog(tab="General", group="Checks", enable=check_func_pi_pT), + Evaluate=true, + HideResult=true); + + replaceable package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Henry + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents + "Package providing all functions of the isotherm model" + annotation (Dialog(tab="General", group="Isotherm Model"), + choicesAllMatching=true); + parameter Integer no_coefficients = 1 + "Number of coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Isotherm Model"), + Evaluate=true, + HideResult=true); + + parameter Real tolerance_p_inv = 100*Modelica.Constants.eps + "Tolerance for numerical calculation of equilibrium pressure via function 'p_xT' + (only used if required)" + annotation (Dialog(tab="Numerics", group="Tolerances"), + Evaluate=true, + HideResult=true); + parameter Real tolerance_p_pi = 100*Modelica.Constants.eps + "Tolerance for numerical calculation of equilibrium pressure via function 'p_piT' + (only used if required)" + annotation (Dialog(tab="Numerics", group="Tolerances"), + Evaluate=true, + HideResult=true); + parameter Real tolerance_pi = 100*Modelica.Constants.eps + "Tolerance for numerical calculation of reduced spreading pressure (only used + if required)" + annotation (Dialog(tab="Numerics", group="Tolerances"), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.Pressure p_lb_pi= 0 + "Lower bound to calculate reduced spreading pressure (should be 0)" + annotation (Dialog(tab="Numerics", group="Reduced spreading pressure"), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.PressureDifference dp = 1e-6 + "Pressure difference used to calculate partial derivatives numerically" + annotation (Dialog(tab="Numerics", group="Derivatives"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-6 + "Temperature difference used to calculate partial derivatives numerically" + annotation (Dialog(tab="Numerics", group="Derivatives"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_adsorpt(start=p_adsorpt_start, fixed=true) + "Equilibrium pressure"; + Modelica.Units.SI.Temperature T_adsorpt(start=T_adsorpt_start, fixed=true) + "Equilibrium temperature"; + SorpLib.Units.Uptake x_adsorpt + "Equilibrium uptake"; + + Modelica.Units.SI.Pressure p_adsorpt_inv + "Equilibrium pressure calculated via inverse function of the isotherm model"; + Modelica.Units.SI.Pressure p_adsorpt_pi + "Equilibrium pressure calculated via reduced spreading pressure"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_adsorpt + "Partial derivative of the uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp_adsorpt_num + "Partial derivative of the uptake w.r.t. pressure at constant temperature + calculated numerically"; + + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_adsorpt + "Partial derivative of the uptake w.r.t. temperature at constant pressure"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT_adsorpt_num + "Partial derivative of the uptake w.r.t. temperature at constant pressure + calculated numerically"; + + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_adsorpt_dp_adsorpt + "Second-order partial derivative of the uptake w.r.t. pressure at constant + temperature"; + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_adsorpt_dp_adsorpt_num + "Second-order partial derivative of the uptake w.r.t. pressure at constant + temperature calculated numerically"; + + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_adsorpt_dT_adsorpt + "Second-order partial derivative of the uptake w.r.t. temperature at constant + pressure"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_adsorpt_dT_adsorpt_num + "Second-order partial derivative of the uptake w.r.t. temperature at constant + pressure calculated numerically"; + + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_adsorpt_dT_adsorpt + "Second-order partial derivative of the uptake w.r.t. pressure and temperature"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_adsorpt_dT_adsorpt_num + "Second-order partial derivative of the uptake w.r.t. pressure and temperature + calculated numerically"; + + SorpLib.Units.ReducedSpreadingPressure red_spreading_pressure + "Reduced spreading pressure"; + SorpLib.Units.ReducedSpreadingPressure red_spreading_pressure_num + "Reduced spreading pressure calculated numerically"; + + Real[no_coefficients] c + "Coefficients of isotherm model"; + + Real[no_coefficients] dc_dT + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + Real[no_coefficients] dc_dT_num = (c_pdT .- c_mdT) ./ (2 * dT) + "Partial derivative of coefficients of isotherm model w.r.t. temperature + calculated numerically"; + + Real[no_coefficients] ddc_dT_dT + "Second-order partial derivative of coefficients of isotherm model w.r.t. + temperature"; + Real[no_coefficients] ddc_dT_dT_num = (c_pdT .- 2 .* c .+ c_mdT) ./ (dT ^ 2) + "Second-order partial derivative of coefficients of isotherm model w.r.t. + temperature calculated numerically"; + +protected + Real[no_coefficients] c_pdT + "Coefficients of isotherm model: T + 1e-6 K"; + Real[no_coefficients] c_mdT + "Coefficients of isotherm model: T - 1e-6 K"; + + function func_pi_num + "Integrand required for calculating the reduced spreading pressure numerically" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input Real T_adsorpt + "Equilibrium temperature"; + input Real c[:] + "Coefficients of isotherm model"; + algorithm + y := IsothermModel.x_pT(p_adsorpt=u, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) / + max(u, Modelica.Constants.small) + "Integrand 'x(p,T,c) / p' required for calculating the reduced spreading + pressure"; + end func_pi_num; + +equation + der(p_adsorpt) = p_adsorpt_der + "Predecsriped slope of p_adsorpt to demonstrate the isotherm model"; + der(T_adsorpt) = T_adsorpt_der + "Predecsriped slope of T_adsorpt to demonstrate the isotherm model"; + + if check_func_p_xT then + p_adsorpt_inv = IsothermModel.p_xT(x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) + "Equilibrium pressure calculated via the inverse function of the isotherm model"; + else + p_adsorpt_inv = -1 + "Equilibrium pressure calculated via the inverse function of the isotherm model"; + end if; + + if check_func_pi_pT and check_func_p_piT then + p_adsorpt_pi = IsothermModel.p_piT(M_adsorptive=M_adsorptive, pi=red_spreading_pressure, + T_adsorpt=T_adsorpt, c=c, p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, + integral_pi_lb=p_lb_pi, tolerance_p_adsorpt=tolerance_p_pi, + tolerance_pi=tolerance_pi) + "Equilibrium pressure calculated via reduced spreading pressure"; + else + p_adsorpt_pi = -1 + "Equilibrium pressure calculated via reduced spreading pressure"; + end if; + + x_adsorpt = IsothermModel.x_pT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) + "Equilibrium uptake"; + + if check_func_dx_dp then + dx_adsorpt_dp_adsorpt = IsothermModel.dx_dp(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of the uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dp_adsorpt_num = ( + IsothermModel.x_pT(p_adsorpt=p_adsorpt+dp, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) - + IsothermModel.x_pT(p_adsorpt=p_adsorpt-dp, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv)) / + (2*dp) + "Partial derivative of the uptake w.r.t. pressure at constant temperature + calculated numerically"; + else + dx_adsorpt_dp_adsorpt = -1 + "Partial derivative of the uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dp_adsorpt_num = -1 + "Partial derivative of the uptake w.r.t. pressure at constant temperature + calculated numerically"; + end if; + + if check_func_dx_dT then + dx_adsorpt_dT_adsorpt = IsothermModel.dx_dT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt, + c=c, dc_dT_adsorpt=dc_dT) + "Partial derivative of the uptake w.r.t. temperature at constant pressure"; + dx_adsorpt_dT_adsorpt_num = ( + IsothermModel.x_pT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt+dT, c=c_pdT, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) - + IsothermModel.x_pT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt-dT, c=c_mdT, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv)) / + (2*dT) + "Partial derivative of the uptake w.r.t. temperature at constant pressure + calculated numerically"; + else + dx_adsorpt_dT_adsorpt = -1 + "Partial derivative of the uptake w.r.t. temperature at constant pressure"; + dx_adsorpt_dT_adsorpt_num = -1 + "Partial derivative of the uptake w.r.t. temperature at constant pressure + calculated numerically"; + end if; + + if check_func_ddx_dp_dp then + ddx_adsorpt_dp_adsorpt_dp_adsorpt = IsothermModel.ddx_dp_dp(p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, c=c) + "Second-order partial derivative of the uptake w.r.t. pressure at constant + temperature"; + ddx_adsorpt_dp_adsorpt_dp_adsorpt_num = ( + IsothermModel.x_pT(p_adsorpt=p_adsorpt+dp, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) - + 2 * IsothermModel.x_pT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) + + IsothermModel.x_pT(p_adsorpt=p_adsorpt-dp, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv)) / + (dp^2) + "Second-order partial derivative of the uptake w.r.t. pressure at constant + temperature numerically"; + else + ddx_adsorpt_dp_adsorpt_dp_adsorpt = -1 + "Second-order partial derivative of the uptake w.r.t. temperature at constant + temperature"; + ddx_adsorpt_dp_adsorpt_dp_adsorpt_num = -1 + "Second-order partial derivative of the uptake w.r.t. temperature at constant + temperature numerically"; + end if; + + if check_func_ddx_dT_dT then + ddx_adsorpt_dT_adsorpt_dT_adsorpt = IsothermModel.ddx_dT_dT(p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, c=c, dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of the uptake w.r.t. temperature at constant + pressure"; + ddx_adsorpt_dT_adsorpt_dT_adsorpt_num = ( + IsothermModel.x_pT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt+dT, c=c_pdT, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) - + 2 * IsothermModel.x_pT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt, c=c, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) + + IsothermModel.x_pT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt-dT, c=c_mdT, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv)) / + (dT^2) + "Second-order partial derivative of the uptake w.r.t. temperature at constant + pressure numerically"; + else + ddx_adsorpt_dT_adsorpt_dT_adsorpt = -1 + "Second-order partial derivative of the uptake w.r.t. temperature at constant + pressure"; + ddx_adsorpt_dT_adsorpt_dT_adsorpt_num = -1 + "Second-order partial derivative of the uptake w.r.t. temperature at constant + pressure numerically"; + end if; + + if check_func_ddx_dp_dT then + ddx_adsorpt_dp_adsorpt_dT_adsorpt = IsothermModel.ddx_dp_dT(p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, c=c, dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of the uptake w.r.t. pressure and temperature"; + ddx_adsorpt_dp_adsorpt_dT_adsorpt_num = ( + IsothermModel.x_pT(p_adsorpt=p_adsorpt+dp, T_adsorpt=T_adsorpt+dT, c=c_pdT, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) - + IsothermModel.x_pT(p_adsorpt=p_adsorpt+dp, T_adsorpt=T_adsorpt-dT, c=c_mdT, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) - + IsothermModel.x_pT(p_adsorpt=p_adsorpt-dp, T_adsorpt=T_adsorpt+dT, c=c_pdT, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv) + + IsothermModel.x_pT(p_adsorpt=p_adsorpt-dp, T_adsorpt=T_adsorpt-dT, c=c_mdT, + p_adsorpt_lb_start=1, p_adsorpt_ub_start=10, tolerance=tolerance_p_inv)) / + (2*dp*2*dT) + "Second-order partial derivative of the uptake w.r.t. pressure and temperature + calculated numerically"; + else + ddx_adsorpt_dp_adsorpt_dT_adsorpt = -1 + "Second-order partial derivative of the uptake w.r.t. pressure and temperature"; + ddx_adsorpt_dp_adsorpt_dT_adsorpt_num = -1 + "Second-order partial derivative of the uptake w.r.t. pressure and temperature + calculated numerically"; + end if; + + if check_func_pi_pT then + red_spreading_pressure = IsothermModel.pi_pT(M_adsorptive=M_adsorptive, p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, c=c, integral_pi_lb=p_lb_pi, tolerance=tolerance_pi) + "Reduced spreading pressure"; + red_spreading_pressure_num = Modelica.Math.Nonlinear.quadratureLobatto( + f=function func_pi_num(T_adsorpt=T_adsorpt, c=c), + a=p_lb_pi, + b=p_adsorpt, + tolerance=tolerance_pi) / M_adsorptive + "Reduced spreading pressure calculated numerically"; + else + red_spreading_pressure = -1 + "Reduced spreading pressure"; + red_spreading_pressure_num = -1 + "Reduced spreading pressure calculated numerically"; + + end if; + + // + // Definition of assertions: Check numerical implementation of isotherm model + // + if print_asserts then + if check_func_p_xT then + assert(abs(p_adsorpt-p_adsorpt_inv) < 1e-6, + "Inverse function of isotherm model is not valid: Deviation (|" + + String(abs(p_adsorpt-p_adsorpt_inv)) + + "|) is greater than 1e-6 Pa!", + level = AssertionLevel.warning); + end if; + + if check_func_pi_pT and check_func_p_piT then + assert(abs(p_adsorpt-p_adsorpt_pi) < 1e-6, + "Inverse function of reduced spreading pressure is not valid: Deviation (|" + + String(abs(p_adsorpt-p_adsorpt_pi)) +"|) is greater " + + "than 1e-6 Pa!", + level = AssertionLevel.warning); + end if; + + if check_func_pi_pT then + assert(abs(red_spreading_pressure-red_spreading_pressure_num) < 1e-6, + "Reduced spreading pressure is not valid: Deviation (|" + + String(abs(red_spreading_pressure-red_spreading_pressure_num)) + + "|) is greater than 1e-6 mol/kg!", + level = AssertionLevel.warning); + end if; + + if check_func_dx_dp then + assert(abs(dx_adsorpt_dp_adsorpt-dx_adsorpt_dp_adsorpt_num) < 1e-6, + "Partial derivative of isotherm model w.r.t. pressure at constant " + + "temperature is not valid: Deviation (|" + + String(abs(dx_adsorpt_dp_adsorpt-dx_adsorpt_dp_adsorpt_num)) + + "|) is greater than 1e-6 kg/(kg.Pa)!", + level = AssertionLevel.warning); + end if; + + if check_func_dx_dT then + assert(abs(dx_adsorpt_dT_adsorpt-dx_adsorpt_dT_adsorpt_num) < 1e-6, + "Partial derivative of isotherm model w.r.t. temperature at contant " + + "pressure is not valid: Deviation (|" + + String(abs(dx_adsorpt_dT_adsorpt-dx_adsorpt_dT_adsorpt_num)) + + "|) is greater than 1e-6 kg/(kg.K)!", + level = AssertionLevel.warning); + end if; + + if check_func_ddx_dp_dp then + assert(abs(ddx_adsorpt_dp_adsorpt_dp_adsorpt-ddx_adsorpt_dp_adsorpt_dp_adsorpt_num) < 1e-6, + "Second-order partial derivative of isotherm model w.r.t. pressure " + + "at constant temperature is not valid: Deviation (|" + + String(abs(ddx_adsorpt_dp_adsorpt_dp_adsorpt-ddx_adsorpt_dp_adsorpt_dp_adsorpt_num)) + + "|) is greater than 1e-6 kg/(kg.Pa2)!", + level = AssertionLevel.warning); + end if; + + if check_func_ddx_dT_dT then + assert(abs(ddx_adsorpt_dT_adsorpt_dT_adsorpt-ddx_adsorpt_dT_adsorpt_dT_adsorpt_num) < 1e-6, + "Second-order partial derivative of isotherm model w.r.t. temperature " + + "at constant pressure is not valid: Deviation (|" + + String(abs(ddx_adsorpt_dT_adsorpt_dT_adsorpt-ddx_adsorpt_dT_adsorpt_dT_adsorpt_num)) + + "|) is greater than 1e-6 kg/(kg.K2)!", + level = AssertionLevel.warning); + end if; + + if check_func_ddx_dp_dT then + assert(abs(ddx_adsorpt_dp_adsorpt_dT_adsorpt-ddx_adsorpt_dp_adsorpt_dT_adsorpt_num) < 1e-6, + "Second-order partial derivative of isotherm model w.r.t. pressure " + + "and temperature is not valid: Deviation (|" + + String(abs(ddx_adsorpt_dp_adsorpt_dT_adsorpt-ddx_adsorpt_dp_adsorpt_dT_adsorpt_num)) + + "|) is greater than 1e-6 kg/(kg.Pa.K)!", + level = AssertionLevel.warning); + end if; + end if; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the basic model for all testers of isotherm models describing +adsorption of pure components. Such isotherm models must be classical isotherm models, +which are based on the assumption of a (plain) boundary surface. +<br/><br/> +This partial model defines all relevant parameters, variables, and equations to +check (1) the classical form of isotherm models, (2) the inverse form of isotherm +models, (3) the partial derivative of the uptake w.r.t. to pressure, (4) the +partial derivative of the uptake w.r.t. pressure, (5) the partial derivative of the +uptake w.r.t. temperature, (6) the second-order partial derivative of the uptake w.r.t. +to pressure and temperature, (7) the second-order partial derivative of the uptake w.r.t. +to temperature, and (8) the reduced spreading pressure. All partial derivatives are also +implemented as central finite differences to check for the analytical implementation +of the partial derivatives. Additionally, the reduced spreading pressure is also calculated +numerically to check the numerical implementation of the reduced spreading pressure. +<br/><br/> +Models that inherit properties from this partial model have to specify the number +of coefficients of the isotherm model <i>no_coefficients</i> and have to redeclare +the <i>IsotherModel</i> package. Besides, the coefficients of the isotherm model (i.e., +<i>c</i>, <i>c_pdT</i>, and <i>c_mdT</i>) and their partial derivatives with respect to +temperature (i.e., <i>dc_dT</i> and <i>ddc_dT_dT</i>) have to be implemented. Additionally, +it has to be specified whether the equilibrium pressure (<i>p_adsorpt_der</i>) or the +equilibrium temperature (<i>T_adsorpt_der</i>) changes with time. +</p> +</html>")); +end PartialTestPure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestPureDubinin.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestPureDubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..b3078ecd01552ece88fc490013895736b077e173 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/PartialTestPureDubinin.mo @@ -0,0 +1,239 @@ +within SorpLib.Media.Functions.SorptionEquilibria.BaseClasses; +partial model PartialTestPureDubinin + "Base model for testers of isotherm models describing pure component adsorption based on the Dubinin model" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + redeclare replaceable package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponentsDubinin); + + // + // Definition of parameters + // + parameter Boolean check_func_A_W = true + "= true, if function 'func_A_W' is checked; otherwise, function is not + checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_dW_dA = true + "= true, if function 'func_dW_dA' is checked; otherwise, function is not + checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_ddW_dA_dA = true + "= true, if function 'func_ddW_dA_dA' is checked; otherwise, function is not + checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + parameter Boolean check_func_ddW_dA_dT = true + "= true, if function 'func_ddW_dA_dT' is checked; otherwise, function is not + checked" + annotation (Dialog(tab="General", group="Checks"), + Evaluate=true, + HideResult=true); + + parameter SorpLib.Units.MolarAdsorptionPotential dA=1e-6 + "Molar adsorption potential difference used to calculate partial derivatives + numerically" annotation ( + Dialog(tab="Numerics", group="Derivatives"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + SorpLib.Units.MolarAdsorptionPotential A "Molar adsorption potential"; + SorpLib.Units.MolarAdsorptionPotential A_inv(min=-1) + "Molar adsorption potential calculated via inverse form of characteristic curve"; + SorpLib.Units.AdsorptionPotential A_mass "Adsorption potential"; + + SorpLib.Units.FilledPoreVolume W + "Filled pore volume"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_num + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + calculated at constant pressure and temperature numerically"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA_num + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential at constant pressure and temperature calculated numerically"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT_num + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure calculated numerically"; + +protected + SorpLib.Units.MolarAdsorptionPotential A_pdT= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, p_sat=c_pdT[1], T_adsorpt=T_adsorpt+dT) + "Molar adsorption potential_ T + dT"; + SorpLib.Units.MolarAdsorptionPotential A_mdT= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, p_sat=c_mdT[1], T_adsorpt=T_adsorpt-dT) + "Molar adsorption potential: T - dT"; + +equation + A =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + + if check_func_A_W then + A_inv = IsothermModel.A_W(W=W, c=c) + "Molar adsorption potential calculated via inverse form of characteristic curve"; + else + A_inv = -1 + "Molar adsorption potential calculated via inverse form of characteristic curve"; + end if; + + A_mass = A / M_adsorptive + "Adsorption potential"; + + W = IsothermModel.W_A(A=A, c=c) + "Filled pore volume"; + + if check_func_dW_dA then + dW_dA = IsothermModel.dW_dA(A=A, c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + dW_dA_num = (IsothermModel.W_A(A=A+dA, c=c) - IsothermModel.W_A(A=A-dA, c=c)) / (2*dA) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature calculated numerically"; + else + dW_dA = -1 + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + dW_dA_num = -1 + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature calculated numerically"; + end if; + + if check_func_ddW_dA_dA then + ddW_dA_dA = IsothermModel.ddW_dA_dA(A=A, c=c) + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential at constant pressure and temperature"; + ddW_dA_dA_num = (IsothermModel.W_A(A=A+dA, c=c) - + 2 * IsothermModel.W_A(A=A, c=c) + IsothermModel.W_A(A=A-dA, c=c)) / (dA^2) + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential at constant pressure and temperature calculated numerically"; + else + ddW_dA_dA = -1 + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential at constant pressure and temperature"; + ddW_dA_dA_num = -1 + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential at constant pressure and temperature calculated numerically"; + end if; + + if check_func_ddW_dA_dT then + ddW_dA_dT = IsothermModel.ddW_dA_dT(p_adsorpt=p_adsorpt, T_adsorpt=T_adsorpt, A=A, + c=c, dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + ddW_dA_dT_num = (IsothermModel.dW_dA(A=A_pdT, c=c_pdT) - IsothermModel.dW_dA(A=A_mdT, c=c_mdT)) / + (2*dT) + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure calculated numerically"; + else + ddW_dA_dT = -1 + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + ddW_dA_dT_num = -1 + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure calculated numerically"; + end if; + + // + // Definition of assertions: Check numerical implementation of isotherm model + // + if print_asserts then + if check_func_A_W then + assert(abs(A-A_inv) < 1e-6, + "Inverse function of characteristic curve is not valid: Deviation (|" + + String(abs(A-A_inv)) + + "|) is greater than 1e-6 J/mol!", + level = AssertionLevel.warning); + end if; + + if check_func_dW_dA then + assert(abs(dW_dA-dW_dA_num) < 1e-6, + "Partial derivative of filled pore volume wrt. adsorption potential " + + "at constant pressure and temperature is not valid: Deviation (|" + + String(abs(dW_dA-dW_dA_num)) + + "|) is greater than 1e-6 m3.mol/(kg.J)!", + level = AssertionLevel.warning); + end if; + + if check_func_ddW_dA_dA then + assert(abs(ddW_dA_dA-ddW_dA_dA_num) < 1e-6, + "Second-order partial derivative of filled pore volume wrt. adsorption " + + "potential at constant pressure and temperature is not valid: Deviation (|" + + String(abs(ddW_dA_dA-ddW_dA_dA_num)) + + "|) is greater than 1e-6 m3.mol2/(kg.J2)!", + level = AssertionLevel.warning); + end if; + + if check_func_ddW_dA_dT then + assert(abs(ddW_dA_dT-ddW_dA_dT_num) < 1e-6, + "Second-order partial derivative of filled pore volume wrt. adsorption " + + "potential and temperature at constant pressure is not valid: Deviation (|" + + String(abs(ddW_dA_dT-ddW_dA_dT_num)) + + "|) is greater than 1e-6 m3.mol/(kg.J.K)!", + level = AssertionLevel.warning); + end if; + end if; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This partial model is the basic model for all testers of isotherm models describing +adsorption of pure components. Such isotherm models must be isotherm models, which +are based on the assumpation of filled pores. +<br/><br/> +This partial model defines all relevant parameters, variables, and equations to +check (1) the classical form of isotherm models, (2) the inverse form of isotherm +models, (3) the partial derivative of the uptake w.r.t. to pressure, (4) the +partial derivative of the uptake w.r.t. pressure, (5) the partial derivative of the +uptake w.r.t. temperature, (6) the second-order partial derivative of the uptake w.r.t. +to pressure and temperature, (7) the second-order partial derivative of the uptake w.r.t. +to temperature, (8) the reduced spreading pressure, (9) the characteristic curve, (10) +the inverse form of the characteristic curve, and (11) partial derivative of the +characteristic curve w.r.t. molar adsorption potential. All partial derivatives are +also implemented as central finite differences to check for the analytical implementation +of the partial derivatives. Additionally, the reduced spreading pressure is also +calculated numerically to check the numerical implementation of the reduced spreading +pressure. +<br/><br/> +Models that inherit properties from this partial model have to specify the number +of coefficients of the isotherm model <i>no_coefficients</i> and have to redeclare +the <i>IsotherModel</i> package. Besides, the coefficients of the isotherm +model (i.e., <i>c</i>, <i>c_pdT</i>, and <i>c_mdT</i>) and their partial derivatives +with respect to temperature (i.e., <i>dc_dT</i>) have to be implemented. Additionally, +it has to specify whether the equilibrium pressure (<i>p_adsorpt_der</i>) or the +equilibrium temperature (<i>T_adsorpt_der</i>) changes with time. +</p> +</html>")); +end PartialTestPureDubinin; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..ecb0da5b5b81964d5884b4dbba96e6aa8272ed39 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.Functions.SorptionEquilibria; +package BaseClasses "Base classes used to build new functions calculating sorption equlibria" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial basic functions and models. These partial functions +and models contain fundamental definitions of all isotherm models and corresponding +test models, covering pure and multi-component adsorption. The content of this package +is only of interest when adding new isotherm models to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/package.order b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..085367e0998b3aac9c0ef65f11d44ccb2f236b1e --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/BaseClasses/package.order @@ -0,0 +1,41 @@ +PartialPure +PartialPure_x_pT +PartialPure_p_xT +PartialPure_p_xT_num +PartialPure_dx_dp +PartialPure_dx_dT +PartialPure_ddx_dp_dp +PartialPure_ddx_dT_dT +PartialPure_ddx_dp_dT +PartialPure_pi_pT +PartialPure_pi_pT_num +PartialPure_p_piT +PartialPure_p_piT_num +PartialPure_W_A +PartialPure_A_W +PartialPure_A_W_num +PartialPure_dW_dA +PartialPure_ddW_dA_dA +PartialPure_ddW_dA_dT +PartialMulti +PartialMulti_x_pyT +PartialMulti_p_xyT +PartialMulti_y_pxT +PartialMulti_py_xT +PartialMulti_dx_dp +PartialMulti_dx_dy +PartialMulti_dx_dT +PartialMultiIAST +PartialMultiIAST_x_pyT +PartialMultiIAST_p_xyT +PartialMultiIAST_y_pxT +PartialMultiIAST_py_xT +PartialMultiIAST_dx_dp +PartialMultiIAST_dx_dy +PartialMultiIAST_dx_dT +PartialTestPure +PartialTestPureDubinin +PartialTestMulti +PartialTestMultiIAST +PartialTestMultiIAST_N2 +PartialTestMultiIAST_N3 diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponents/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5bbde568fb56c79521c5d063d0a634c1ede36cf2 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponents/package.mo @@ -0,0 +1,99 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Interfaces; +partial package PartialMultiComponents "Base package for all isotherm models of multi components" + extends Modelica.Icons.FunctionsPackage; + + // + // Basic isotherm equations + // + replaceable partial function x_pyT + "Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti_x_pyT; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end x_pyT; + + replaceable partial function p_xyT + "Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti_p_xyT; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end p_xyT; + + replaceable partial function y_pxT + "Mole fractions of independent gas phase components as function of pressure, uptakes, and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti_y_pxT; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end y_pxT; + + replaceable partial function py_xT + "Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti_py_xT; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + replaceable partial function dx_dp + "Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti_dx_dp; + end dx_dp; + + replaceable partial function dx_dy + "Partial derivative of uptakes w.r.t. molar fractions of independent gas phase components at constant temperature and pressure" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti_dx_dy; + end dx_dy; + + replaceable partial function dx_dT + "Partial derivative of uptakes w.r.t. temperature at contsant pressure and mole fractions" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti_dx_dT; + end dx_dT; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package is the basic package for all isotherm models describing +the adsorption of multi components. +<br/><br/> +This partial package contains all declarations for a multi-component isotherm +model. This means that functions are defined that every multi-component isotherm +model must support. A multi-component isotherm model inherits from this partial +package and must provide the isotherm equations by redeclaring all partial +functions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialMultiComponents; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponents/package.order b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..9591cabf17ee4dd7f796baa2bc4f32a427eb4738 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponents/package.order @@ -0,0 +1,7 @@ +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponentsIAST/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponentsIAST/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..0ff50728b658c157293e8ec5ed45d0d9725e40ce --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponentsIAST/package.mo @@ -0,0 +1,100 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Interfaces; +partial package PartialMultiComponentsIAST "Base package for all isotherm models of multi components based on the IAST" + extends Modelica.Icons.FunctionsPackage; + + // + // Basic isotherm equations + // + replaceable partial function x_pyT + "Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST_x_pyT; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end x_pyT; + + replaceable partial function p_xyT + "Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST_p_xyT; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end p_xyT; + + replaceable partial function y_pxT + "Mole fractions of independent gas phase components as function of pressure, uptakes, and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST_y_pxT; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end y_pxT; + + replaceable partial function py_xT + "Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST_py_xT; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + replaceable partial function dx_dp + "Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST_dx_dp; + end dx_dp; + + replaceable partial function dx_dy + "Partial derivative of uptakes w.r.t. molar fractions of independent gas phase components at constant temperature and pressure" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST_dx_dy; + end dx_dy; + + replaceable partial function dx_dT + "Partial derivative of uptakes w.r.t. temperature at contsant pressure and mole fractions" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST_dx_dT; + end dx_dT; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package is the basic package for all isotherm models describing +the adsorption of multi components based on the ideal adsorption solution +theory. +<br/><br/> +This partial package contains all declarations for a multi-component isotherm +model. This means that functions are defined that every multi-component isotherm +model must support. A multi-component isotherm model inherits from this partial +package and must provide the isotherm equations by redeclaring all partial +functions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialMultiComponentsIAST; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponentsIAST/package.order b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponentsIAST/package.order new file mode 100644 index 0000000000000000000000000000000000000000..9591cabf17ee4dd7f796baa2bc4f32a427eb4738 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialMultiComponentsIAST/package.order @@ -0,0 +1,7 @@ +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponents/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..cd8c9e74f419513bea652f30a8fe1e67da9885a0 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponents/package.mo @@ -0,0 +1,100 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Interfaces; +partial package PartialPureComponents "Base package for all isotherm models of pure components" + extends Modelica.Icons.FunctionsPackage; + + // + // Basic isotherm equations + // + replaceable partial function x_pT + "Uptake as function of pressure and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end x_pT; + + replaceable partial function p_xT + "Pressure as function of uptake and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end p_xT; + + replaceable partial function dx_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp; + end dx_dp; + + replaceable partial function dx_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dT; + end dx_dT; + + replaceable partial function ddx_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dp_dp; + end ddx_dp_dp; + + replaceable partial function ddx_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dT_dT; + end ddx_dT_dT; + + replaceable partial function ddx_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dp_dT; + end ddx_dp_dT; + // + // Equations regarding reduced spreading pressure + // + replaceable partial function pi_pT + "Reduced spreading pressure as function of pressure and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT; + end pi_pT; + + replaceable partial function p_piT + "Pressure as function of reduced spreading pressure and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT; + end p_piT; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package is the basic package for all isotherm models describing +the adsorption of pure components. Such models can be classical isotherm models +based on a (plain) boundary surface or isotherm models based on filled pores. +<br/><br/> +This partial package contains all declarations for a pure component isotherm +model. This means that functions are defined that every pure component isotherm +model must support. A pure component isotherm model inherits from this partial +package and must provide the isotherm equations by redeclaring all partial +functions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPureComponents; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponents/package.order b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5b33869cf15d79cfe321d3ef372972c01c4559b4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponents/package.order @@ -0,0 +1,9 @@ +x_pT +p_xT +dx_dp +dx_dT +ddx_dp_dp +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponentsDubinin/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponentsDubinin/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c93e9afa3ef7ab9a93694a66ccccfc887829e0a8 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponentsDubinin/package.mo @@ -0,0 +1,214 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Interfaces; +partial package PartialPureComponentsDubinin "Base package for all isotherm models of pure components based on the model of Dubinin" + extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents; + + // + // Dubinin-specific isotherm equations + // + replaceable partial function W_A + "Filled pore volume as function of molar adsorption potential" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_W_A; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end W_A; + + replaceable partial function A_W + "Molar adsorption potential as function of filled pore volume" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_A_W; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end A_W; + + replaceable partial function dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential at constant pressure and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dW_dA; + end dW_dA; + + replaceable partial function ddW_dA_dA + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption potential at constant pressure and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dA; + end ddW_dA_dA; + + replaceable partial function ddW_dA_dT + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption potential and temperature at constant pressure" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dT; + end ddW_dA_dT; + // + // Redeclare basic isotherm equations + // + redeclare replaceable function extends x_pT + "Uptake as function of pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.FilledPoreVolume W=W_A( + A=A, + c=c) + "Filled pore volume"; + + algorithm + x_adsorpt := c[2] * W + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end x_pT; + + redeclare replaceable function extends p_xT + "Pressure as function of uptake and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A=A_W( + W=x_adsorpt/c[2], + c=c) + "Adsorption potential"; + + algorithm + p_adsorpt :=SorpLib.Media.Functions.SorptionEquilibria.Utilities.p_ApsT( + A=A, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Calculation of the equilibrium pressure of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end p_xT; + + redeclare final function extends dx_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of adsorption potential w.r.t. to pressure at + constant temperature"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_=dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + + algorithm + dx_adsorpt_dp_adsorpt := c[2] * dW_dA_*dA_dp_adsorpt + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure at constant temperature"; + end dx_dp; + + redeclare final function extends ddx_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of adsorption potential w.r.t. to pressure at constant + temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressurePressure ddA_dp_adsorpt_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dp_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Second-order partial derivative of adsorption potential w.r.t. to pressure + at constant temperature"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA_=dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temeprature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA_=ddW_dA_dA( + A=A, + c=c) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential at constant pressure and temeprature"; + + algorithm + ddx_adsorpt_dp_adsorpt_dp_adsorpt := + (c[2] * dA_dp_adsorpt) * ddW_dA_dA_*dA_dp_adsorpt + + (c[2] * dW_dA_) * ddA_dp_adsorpt_dp_adsorpt + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure at constant temperature"; + end ddx_dp_dp; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package is the basic package for all isotherm models describing +the adsorption of pure components based on the model of Dubinin. Such models +describe the adsorption based on filled pores. +<br/><br/> +This partial package contains all declarations for a pure component isotherm +model. This means that functions are defined that every pure component isotherm +model must support. A pure component isotherm model inherits from this partial +package and must provide the isotherm equations by redeclaring all partial +functions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PartialPureComponentsDubinin; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponentsDubinin/package.order b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponentsDubinin/package.order new file mode 100644 index 0000000000000000000000000000000000000000..a757168b57e5583177d5c81a94f7b83d82a7e104 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/PartialPureComponentsDubinin/package.order @@ -0,0 +1,9 @@ +W_A +A_W +dW_dA +ddW_dA_dA +ddW_dA_dT +x_pT +p_xT +dx_dp +ddx_dp_dp diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e35a074e123f0e72882ffe0e7796729a0aa2434a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Media.Functions.SorptionEquilibria; +package Interfaces "Interfaces for sorption equilibria models" + extends Modelica.Icons.InterfacesPackage; + + annotation (Documentation(info="<html> +<p> +This package provides definitions of basic interfaces for sorption equilibria models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Interfaces; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/package.order b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c028d2f9dd019c985d84ae1b07f152449f64ce2d --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Interfaces/package.order @@ -0,0 +1,4 @@ +PartialPureComponents +PartialPureComponentsDubinin +PartialMultiComponents +PartialMultiComponentsIAST diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a56b646e1482eea0432021259958442f67744514 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2; +package Internals "Internal functions used to avoid redundancy" + extends Modelica.Icons.InternalPackage; + + annotation (Documentation(info="<html> +<p> +This package contains functions used for various functions of the IAST for +two components. Thus, redundancy of code shall be avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Internals; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/package.order new file mode 100644 index 0000000000000000000000000000000000000000..28701d404ff72aa0ee4cedb83bc2b64d1ae6df25 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/package.order @@ -0,0 +1,4 @@ +x_pyT_NewtonRaphson +x_pyT_NestedLoop +x_pyT_FastIAST +py_xT_NewtonRaphson diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/py_xT_NewtonRaphson.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/py_xT_NewtonRaphson.mo new file mode 100644 index 0000000000000000000000000000000000000000..54c43502596c364e4bd6ed026fc03c59fb4fc4c7 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/py_xT_NewtonRaphson.mo @@ -0,0 +1,327 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals; +function py_xT_NewtonRaphson + "IAST for two components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature using the standard 'Newton-Raphson' algorithm" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean flag_startValues = false + " = true, if start values are given; otherwise, estimate start values" + annotation (Dialog(tab="General", group="Inputs - Start values")); + input SorpLib.Units.ReducedSpreadingPressure pi_0 = 1 + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i + "Mole fractions of components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.Pressure[size(M_i,1)] p_i_pure + "Hypothetical pure component pressures" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.ReducedSpreadingPressure pi + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] pi_i + "Reduced spreading pressures"; + + Integer no_iteration = 1 + "Counter of loop"; + Real error = 1 + "Error of loop"; + + SorpLib.Units.MolarUptake[size(M_i,1)] q_adsorpt_i = x_adsorpt ./ M_i + "Molar equilibrium uptakes at hypothetical pure component pressures"; + Real[size(M_i,1)] dq_adsorpt_i_dp_i_pure(each unit="mol/(kg.Pa)") + "Partical derivatives of molar equilibrium uptakes at hypothetical pure + component pressures w.r.t. hypothetical pure component pressures"; + + Real delta_sum_q_adsorpt(unit="kg/mol") + "Satisfaction of total molar uptake"; + Real ddelta_sum_q_adsorpt_dpi(unit="kg.kg/(mol.mol)") + "Partial derivative of satisfaction of total molar uptake w.r.t. to reduced + spreading pressure of all components"; + + SorpLib.Units.MolarUptake q_adsorpt = sum(q_adsorpt_i) + "Total molar equilibrium uptake"; + + Modelica.Units.SI.MoleFraction[size(M_i,1)] z_i = q_adsorpt_i ./ q_adsorpt + "Mole fractions of the adsorpt phase"; + +algorithm + if flag_startValues then + // + // Use start values + // + pi := pi_0 + "Reduced spreading pressure of all components"; + + else + // + // Caclulate initial guesses ensuring convergence: Equilibrium pressures + // + p_i_pure[1] := func_p_xT_1(x_adsorpt=x_adsorpt[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Pure component pressure of the first component (not at hypothetical pressure)"; + p_i_pure[2] := func_p_xT_2(x_adsorpt=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Pure component pressure of the second component (not at hypothetical pressure)"; + + // + // Caclulate initial guesses ensuring convergence: Reduced spreading pressures + // + pi_i[1] := func_pi_pT_1(M_adsorptive=M_i[1], + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance=num_comp_1.tolerance_pi) + "Reduced spreading pressure of the first component"; + pi_i[2] := func_pi_pT_2(M_adsorptive=M_i[2], + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance=num_comp_2.tolerance_pi) + "Reduced spreading pressure of the second component"; + + pi := sum(z_i .* pi_i) + "Reduced spreading pressure of all components"; + + end if; + + // + // Loop to solve the inverse of the IAST + // + while error >= num.tolerance_inv and no_iteration <= num.no_max_inv loop + // + // Calculate hypothetical pure component pressures + // + p_i_pure[1] := func_p_piT_1( + M_adsorptive=M_i[1], + pi=pi, + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance_p_adsorpt=num_comp_1.tolerance_p_adsorpt, + tolerance_pi=num_comp_1.tolerance_pi) + "Hypothetical pure component pressure of the first component"; + p_i_pure[2] := func_p_piT_2( + M_adsorptive=M_i[2], + pi=pi, + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance_p_adsorpt=num_comp_2.tolerance_p_adsorpt, + tolerance_pi=num_comp_2.tolerance_pi) + "Hypothetical pure component pressure of the first component"; + + // + // Calculate molar uptakes + // + q_adsorpt_i[1] := 1/M_i[1] * func_x_pT_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + first component"; + q_adsorpt_i[2] := 1/M_i[2] * func_x_pT_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + second component"; + + // + // Calculate partial derivatives of molar uptakes w.r.t. hypothetical pure + // component pressures + // + dq_adsorpt_i_dp_i_pure[1] := 1/M_i[1] * func_dx_dp_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1) + "Molar equilibrium uptake at hypothetical pure component pressure of the + first component"; + dq_adsorpt_i_dp_i_pure[2] := 1/M_i[2] * func_dx_dp_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2) + "Molar equilibrium uptake at hypothetical pure component pressure of the + second component"; + + // + // Apply Newton-Raphson method + // + delta_sum_q_adsorpt := sum(z_i ./ q_adsorpt_i) - 1 / q_adsorpt + "Satisfaction of total molar uptake"; + ddelta_sum_q_adsorpt_dpi := -sum(z_i .* p_i_pure ./ q_adsorpt_i .^ 3 .* + dq_adsorpt_i_dp_i_pure) + "Partial derivative of satisfaction of total molar uptake w.r.t. to reduced + spreading pressure of all components"; + + pi := if pi - delta_sum_q_adsorpt / ddelta_sum_q_adsorpt_dpi > 0 then + pi - delta_sum_q_adsorpt / ddelta_sum_q_adsorpt_dpi else pi / 2 + "Update reduced spreading pressure of all components"; + + // + // Check for convergence + // + no_iteration := no_iteration + 1 + "Counter of loop"; + error := abs(delta_sum_q_adsorpt) + "Error of loop"; + + end while; + + // + // Calculate final ouputs + // + p_adsorpt := sum(z_i .* p_i_pure) + "Equilibrium pressure of the adsorpt phase"; + + y_i := z_i .* p_i_pure ./ p_adsorpt + "Mole fractions of components in the vapor or gas phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function provides an algorithm for solving the inverse of the IAST for two +components. The pressure <i>p_adsorpt</i> and molar composition of the gas/vapour +phase <i>y_i</i> are calculated as a function of the uptakes <i>x_adsorpt</i> +and the temperature <i>T_adsorpt</i>. The algorithm uses a Newton-Raphson method +to solve the system of equations of the inverse of the IAST. +</p> + +<h4>Main equations</h4> +<p> +The algorithm consists of 13 steps: +</p> +<ol> + <li> + Calculate the pure component pressures of each component <i>i</i>: + <pre>p<sub>adsorpt,<i>i</i></sub> = f(x<sub>adsorpt,<i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressures of each component <i>i</i>: + <pre>π<sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, p<sub>adsorpt,<i>i</i></sub>, T<sub>adsorpt</sub>),</pre> + where <i>M<sub><i>i</i></sub></i> is the molar mass. + <br> + </li> + </li> + <li> + Calculate the initial guess of the reduced spreading pressure: + <pre>π = ∑<sub><i>i</i></sub> z<sub><i>i</i></sub> * π<sub><i>i</i></sub>,</pre> + where <i>z<sub><i>i</i></sub></i> is the molar molar composition of each component + <i>i</i> in the adsorpt phase + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, π, T<sub>adsorpt</sub>).</pre> + This formula is an inverse of the reduced spreading pressure, which often + has to be calculated numerically. + <br> + </li> + <li> + Calculate the molar uptake of each component <i>i</i>: + <pre>q<sub>adsorpt,<i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate partial derivatives of the molar uptake of each component <i>i</i> + with respect to the hypothetical pure component pressures of each component + <i>i</i>: + <pre>dq<sub>adsorpt,<i>i</i></sub>/dp<sup>*</sup><sub><i>i</i></sub> = 1 / M<sub><i>i</i></sub> * dx<sub>adsorpt,<i>i</i></sub>/dp<sub>adsorpt</sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>),</pre> + where <i>dx<sub>adsorpt,<i>i</i></sub>/dp<sub>adsorpt</sub></i> is the partial + derivative of the uptake with respect to the pressure. + <br> + </li> + <li> + Calculate the satisfaction of the total molar uptake: + <pre>F = ∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> / q<sub>adsorpt,<i>i</i></sub>] - 1 / ∑<sub><i>i</i></sub> [x<sub>adsorpt,<i>i</i></sub> / M<sub><i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the partial derivative of the total molar uptake with respect to the + reduced spreading pressure: + <pre>dF/dπ = -∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> * p<sup>*</sup><sub><i>i</i></sub> / (q<sup>3</sup><sub>adsorpt,<i>i</i></sub>) * dq<sub>adsorpt,<i>i</i></sub>/dp<sup>*</sup><sub><i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressure of the next iteration step: + <pre>π<sub>next</sub> = <strong>if</strong> π - F / dF/dπ > 0 <strong>then</strong> π - F / dF/dπ > 0 <strong>else</strong> π/2.</pre> + <br> + </li> + <li> + Check for convergence: + <pre>|F| ≤ tolerance.</pre> + If the convergence criterion is not fulfilled, got to step 4. It the convergence + criterion is fulfilled, got to step 11. + <br> + </li> + <li> + Calculate the partial pressure of each component <i>i</i>: + <pre>p<sub>adsorpt,<i>i</i></sub> = z<sub><i>i</i></sub> * p<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the pressure: + <pre>p<sub>adsorpt</sub> = ∑<sub><i>i</i></sub> p<sub>adsorpt,<i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the molar fractions each component <i>i</i> in the gas/vapor + phase: + <pre>y<sub><i>i</i></sub> = p<sub>adsorpt,<i>i</i></sub> / p<sub>adsorpt</sub>.</pre> + </li> +</ol> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end py_xT_NewtonRaphson; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/x_pyT_FastIAST.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/x_pyT_FastIAST.mo new file mode 100644 index 0000000000000000000000000000000000000000..bad9ea755dc37f8914505b9aa37560d184883b2e --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/x_pyT_FastIAST.mo @@ -0,0 +1,462 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals; +function x_pyT_FastIAST + "IAST for two components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature using the 'FastIAST' algorithm" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[:] y_i + "Mole fractions of the components in the gas or vapor phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean flag_startValues = false + " = true, if start values are given; otherwise, estimate start values" + annotation (Dialog(tab="General", group="Inputs - Start values")); + input Real[size(M_i,1)] Kp_i_0(each unit="1/Pa") = fill(1, size(M_i,1)) + "Auxiliary variable for reduced pressues of the components" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + input Real[size(M_i,1)] eta_i_0(each unit="1") = fill(1, size(M_i,1)) + "Reduced pressures of the components" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.Pressure[size(M_i,1)] p_i_pure + "Hypothetical pure component pressures" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.ReducedSpreadingPressure pi + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Real[size(M_i,1)] Kp_i(each unit="1/Pa") + "Auxiliary variable for reduced pressues of the components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Real[size(M_i,1)] eta_i(each unit="1") + "Reduced pressures of the components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real[size(M_i,1)] K_i(each unit="mol/(kg.Pa)") + "Henry constants of the components"; + Real K_avg(unit="mol/(kg.Pa)") + "Average Henry constant"; + + SorpLib.Units.MolarUptake[size(M_i,1)] q_adsorpt_sat + "Saturation uptakes of the components"; + + Integer no_iteration = 1 + "Counter of loop"; + Real error = 1 + "Error of loop"; + + Real[size(M_i,1)] Jac_last_row + "Jacobian matrix: Elements of the last row"; + Real[size(M_i,1)] Jac_diagonal + "Jacobian matrix: Elements of the diagonal"; + + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] pi_i + "Reduced spreading pressures"; + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] delta_pi_i + "Difference between reduced spreading pressures and reduced spreading pressure + of last component"; + + Real[size(M_i,1)] delta_eta_i(each unit="1") + "Newton steps for reduced pressures of the components"; + + Modelica.Units.SI.MoleFraction[size(M_i,1)] z_i + "Mole fractions of the adsorpt phase"; + + SorpLib.Units.MolarUptake[size(M_i,1)] q_adsorpt_i + "Molar equilibrium uptakes at hypothetical pure component pressures"; + SorpLib.Units.MolarUptake q_adsorpt + "Total molar equilibrium uptake"; + +algorithm + if flag_startValues then + // + // Use start values + // + Kp_i := Kp_i_0 + "Auxiliary variable for reduced pressues of the components"; + + eta_i := eta_i_0 + "Reduced pressures of the components"; + + else + // + // Caclulate initial guesses ensuring convergence: Henry constants + // + K_i[1] := 1/M_i[1] * func_dx_dp_1(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_1) + "Henry constant of the first component"; + K_i[2] := 1/M_i[2] * func_dx_dp_2(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_2) + "Henry constant of the second component"; + + K_avg := sum(y_i .* K_i) + "Average Henry constant"; + + // + // Calculate initial guesses ensuring convergence: Saturation uptakes + // + q_adsorpt_sat[1] := 1/M_i[1] * func_x_pT_1( + p_adsorpt=num.p_sat_0, + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Saturation uptake of the first component"; + q_adsorpt_sat[2] := 1/M_i[2] * func_x_pT_2( + p_adsorpt=num.p_sat_0, + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Saturation uptake of the second component"; + + // + // Calculate initial guesses ensuring convergence: Reduced pressures + // + Kp_i := K_i ./ q_adsorpt_sat + "Auxiliary variable for reduced pressues of the components"; + + eta_i := {min(Kp_i[i] / K_i[i] * p_adsorpt * K_avg, p_adsorpt * Kp_i[i]) + for i in 1:size(M_i,1)} + "Reduced pressures of the components"; + + end if; + + // + // Loop to solve the IAST + // + while error >= num.tolerance and no_iteration <= num.no_max loop + // + // Calculate the Jacobian matrix: Last row + // + Jac_last_row := Kp_i .* p_adsorpt .* y_i ./ eta_i.^2 + "Jacobian matrix: Elements of the last row"; + + // + // Calculate hypothetical pure component pressures + // + p_i_pure := eta_i ./ Kp_i + "Hypothetical pure component pressures"; + + // + // Calculate the Jacobian matrix: Diagonal + // + Jac_diagonal[1] := 1 / (M_i[1] * eta_i[1]) * func_x_pT_1( + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Diagonale of the Jacobian matrix: Component 1"; + Jac_diagonal[2] := 1 / (M_i[2] * eta_i[2]) * func_x_pT_2( + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Diagonale of the Jacobian matrix: Component 2"; + + // + // Calculate the Jacobian matrix: Correct last element of the diagonal + // + Jac_diagonal[end] := Jac_last_row[end] + Jac_diagonal[end] * + sum(Jac_last_row[1:end-1] ./ Jac_diagonal[1:end-1]) + "Diagonale of the Jacobian matrix: Last element of the diagonal"; + + // + // Calculate recuded spreading pressures + // + pi_i[1] := func_pi_pT_1(M_adsorptive=M_i[1], + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance=num_comp_1.tolerance_pi) + "Reduced spreading pressure of the first component"; + pi_i[2] := func_pi_pT_2(M_adsorptive=M_i[2], + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance=num_comp_2.tolerance_pi) + "Reduced spreading pressure of the second component"; + + // + // Calculate residuals + // + delta_pi_i := pi_i .- pi_i[end] + "Difference between reduced spreading pressures and reduced spreading pressure + of last component"; + delta_pi_i[end] := 1 - sum(Kp_i .* p_adsorpt .* y_i ./ eta_i) - + sum(Jac_last_row[1:end-1] ./ Jac_diagonal[1:end-1] .* delta_pi_i[1:end-1]) + "Difference between reduced spreading pressures and reduced spreading pressure + of last component: Last element"; + + // + // Apply Newton-Raphson method + // + delta_eta_i[end] := -delta_pi_i[end] / Jac_diagonal[end] + "Newton steps for reduced pressures of the components: Last component"; + delta_eta_i[1:end-1] := (-delta_pi_i[1:end-1] .+ Jac_diagonal[end] * + delta_eta_i[end]) ./ Jac_diagonal[1:end-1] + "Newton steps for reduced pressures of the components: Remaining components"; + + for i in 1:size(M_i,1) loop + if eta_i[i] + delta_eta_i[i] < 0 then + eta_i[i] := eta_i[i] / 2 + "Update reduced pressure"; + + else + eta_i[i] := eta_i[i] + delta_eta_i[i] + "Update reduced pressure"; + + end if; + end for; + + // + // Check for convergence + // + no_iteration := no_iteration + 1 + "Counter of loop"; + error := sum(abs(delta_eta_i)) + "Error of loop"; + + end while; + + // + // Return final results + // + if error >= num.tolerance or no_iteration > num.no_max or max(p_i_pure) >= 1e30 then + // + // Calculation failed: Use 'Nested Loop' algorithm as fallback solution + // + (x_adsorpt,p_i_pure,pi) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'Nested Loop' algorithm to solve IAST"; + + else + // + // Calculate mole fractions of adsorpt phase + // + z_i := y_i .* p_adsorpt ./ p_i_pure + "Mole fractions of the adsorpt phase"; + + // + // Calculate equilibrium uptakes + // + q_adsorpt_i[1] := 1/M_i[1] * func_x_pT_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + first component"; + q_adsorpt_i[2] := 1/M_i[2] * func_x_pT_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + second component"; + + q_adsorpt := 1 / sum(z_i ./ q_adsorpt_i) + "Total molar equilibrium uptake"; + + // + // Calculate final ouputs + // + x_adsorpt := q_adsorpt .* z_i .* M_i + "Equilibrium uptakes of the adsorpt phase"; + + pi := pi_i[end] + "Reduced spreading pressure of all components"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function provides an algorithm for solving the IAST for two components. The +uptakes <i>x_adsorpt</i> are calculated as a function of the pressure <i>p_adsorpt</i>, +the molar composition of the gas/vapour phase <i>y_i</i>, and the temperature +<i>T_adsorpt</i>. The algorithm uses one loops to iterate simultaneously over the +reduced spreading pressure <i>π</i> and the molar composition of the adsorpt phase +<i>z<sub><I>i</i></sub></i>. The algorithm exploits that all relevant information can +be written into a Jacobian matrix in which all elements are zero except the last row, +the last column, and the diagonal. For the calculation, only the information of the +last row and diagonal is required, which reduces the computational effort. +</p> + +<h4>Main equations</h4> +<p> +The algorithm consists of 20 steps: +</p> +<ol> + <li> + Calculate the Henry's constant of each component <i>i</i>: + <pre>K<sub><i>i</i></sub> = 1 / M<sub><i>i</i></sub> * dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub>,</pre> + where <i>M<sub><i>i</i></sub></i> is the molar mass and <i>dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub></i> + is the partial derivative of the uptake with respect to the pressure. + <br> + </li> + <li> + Calculate the average Henry's constant: + <pre>K<sub>avg</sub> = ∑<sub><i>i</i></sub> y<sub><i>i</i></sub> * K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the molar saturation uptake of each component <i>i</i>: + <pre>q<sub>adsorpt,sat,<i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p → ∞, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate auxiliary variable of each component <i>i</i>: + <pre>Kp<sub><i>i</i></sub> = K<sub><i>i</i></sub> / q<sub>adsorpt,sat,<i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the initial guess of the reduced pressure of each component <i>i</i>: + <pre>η<sub><i>i</i></sub> = <strong>min</strong>(Kp<sub><i>i</i></sub> / K<sub><i>i</i></sub> * p<sub>adsorpt</sub> * K<sub>avg</sub>, Kp<sub><i>i</i></sub> * p<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the last row of the Jacobian matrix for each column <i>i</i>: + <pre>Jac<sub>last row,<i>i</i></sub> = Kp<sub><i>i</i></sub> * p<sub>adsorpt</sub> * y<sub><i>i</i></sub> / η<sup>2</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = η<sub><i>i</i></sub> / Kp<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the diagonal of the Jacobian matrix for each component <i>i</i>: + <pre>Jac<sub>diagonal,<i>i</i></sub> = 1 / (M<sub><i>i</i></sub> * η<sub><i>i</i></sub>) * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Correct the last element of the diagonal of the Jacobian matrix: + <pre>Jac<sub>diagonal,last</sub> = Jac<sub>last row,last</sub> + Jac<sub>diagonal,last</sub> * ∑<sub><i>i</i></sub><sup>N-1</sup> [Jac<sub>last row,<i>i</i></sub> / Jac<sub>diagonal,<i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressures of each component <i>i</i>: + <pre>π<sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the differences between the reduced spreading pressure of each + component <i>i</i> and the reduced spreading pressure of the last component: + <pre>Δπ<sub><i>i</i></sub> = π<sub><i>i</i></sub> - π<sub>last</sub>.</pre> + <br> + </li> + <li> + Correct the last element of the differences between the reduced spreading pressure + of each component <i>i</i> and the reduced spreading pressure of the last component: + <pre>Δπ<sub>last</sub> =1 - ∑<sub><i>i</i></sub> [Kp<sub><i>i</i></sub> * p<sub>adsorpt</sub> * y<sub><i>i</i></sub> / η<sub><i>i</i></sub>] - ∑<sub><i>i</i></sub><sup>N-1</sup> [Jac<sub>last row,<i>i</i></sub> / Jac<sub>diagonal,<i>i</i></sub> * Δπ<sub><i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the change of the reduced pressure of the last component: + <pre>Δη<sub>last</sub> = Δπ<sub>last</sub> / Jac<sub>diagonal,last</sub>.</pre> + <br> + </li> + <li> + Calculate the change of the reduced pressure of the remaining components <i>i</i>: + <pre>Δη<sub><i>i</i></sub> = (-Δπ<sub><i>i</i></sub> + Jac<sub>diagonal,last</sub> * Δη<sub>last</sub>) / Jac<sub>diagonal,<i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the reduced pressure of the next iteration step of each component <i>i</i>: + <pre>η<sub>next,<i>i</i></sub> = <strong>if</strong> η<sub><i>i</i></sub> + Δη<sub><i>i</i></sub> > 0 <strong>then</strong> η<sub><i>i</i></sub> + Δη<sub><i>i</i></sub> <strong>else</strong> η<sub><i>i</i></sub>/2.</pre> + <br> + </li> + <li> + Check for convergence: + <pre>∑ |Δη<sub><i>i</i></sub>| ≤ tolerance.</pre> + If the convergence criterion is not fulfilled, got to step 6. It the convergence + criterion is fulfilled, got to step 17. + <br> + </li> + <li> + Calculate the molar composition of each component <i>i</i> in the adsorpt + phase: + <pre>z<sub><i>i</i></sub> = y<sub><i>i</i></sub> * p<sub>adsorpt</sub> / p<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the molar uptake of each component <i>i</i>: + <pre>q<sub>adsorpt,<i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the total molar uptake: + <pre>q<sub>adsorpt,total</sub> = 1 / ∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> / q<sub>adsorpt,<i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the uptakes of each component <i>i</i>: + <pre>x<sub>adsorpt,<i>i</i></sub> = M<sub><i>i</i></sub> * z<sub><i>i</i></sub> * q<sub>adsorpt,total</sub>.</pre> + </li> +</ol> + +<h4>References</h4> +<ul> + <li> + Mangano E., Friedrich, D., and Brandani, S. (2015). Robust algorithms for the solution of the ideal adsorbed solution theory equations. AIChE Journal, 61(3): 981–991. DOI: 10.1002/aic.14684. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_pyT_FastIAST; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/x_pyT_NestedLoop.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/x_pyT_NestedLoop.mo new file mode 100644 index 0000000000000000000000000000000000000000..4c1feef833fe151c7eb7615c0f5d2e5459f48f2c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/x_pyT_NestedLoop.mo @@ -0,0 +1,389 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals; +function x_pyT_NestedLoop + "IAST for two components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature using the 'Nested Loop' algorithm" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[:] y_i + "Mole fractions of the components in the gas or vapor phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean flag_startValues = false + " = true, if start values are given; otherwise, estimate start values" + annotation (Dialog(tab="General", group="Inputs - Start values")); + input Modelica.Units.SI.Pressure[size(M_i,1)] p_i_pure_0= + fill(1, size(M_i,1)) + "Hypothetical pure component pressures" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + input SorpLib.Units.ReducedSpreadingPressure pi_0 = 1 + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.Pressure[size(M_i,1)] p_i_pure + "Hypothetical pure component pressures" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.ReducedSpreadingPressure pi + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real[size(M_i,1)] K_i(each unit="mol/(kg.Pa)") + "Henry constants of the components"; + Real K_avg(unit="mol/(kg.Pa)") + "Average Henry constant"; + + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] pi_i + "Reduced spreading pressures"; + + Integer no_inner = 1 + "Counter of inner loop"; + Integer no_outer = 1 + "Counter of outer loop"; + + SorpLib.Units.ReducedSpreadingPressure error_inner = 1 + "Error of inner loop"; + Modelica.Units.SI.MoleFraction error_outer = 1 + "Error of outer loop"; + + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] delta_pi_i + "Difference between reduced spreading pressures and reduced spreading pressure + of all components"; + Real[size(M_i,1)] ddelta_pi_i_dp_i_pure(each unit="mol/(kg.Pa)") + "Partial derivative of difference between reduced spreading pressures and + reduced spreading pressure of all components w.r.t. the hypothetical pure + component pressures"; + + Modelica.Units.SI.MoleFraction[size(M_i,1)] z_i + "Mole fractions of the adsorpt phase"; + + SorpLib.Units.MolarUptake[size(M_i,1)] q_adsorpt_i + "Molar equilibrium uptakes at hypothetical pure component pressures"; + SorpLib.Units.MolarUptake q_adsorpt + "Total molar equilibrium uptake"; + +algorithm + if flag_startValues then + // + // Use start values + // + p_i_pure := p_i_pure_0 + "Hypothetical pure component pressures"; + pi := pi_0 + "Reduced spreading pressure of all components"; + + else + // + // Caclulate initial guesses ensuring convergence: Henry constants + // + K_i[1] := 1/M_i[1] * func_dx_dp_1(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_1) + "Henry constant of the first component"; + K_i[2] := 1/M_i[2] * func_dx_dp_2(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_2) + "Henry constant of the second component"; + + K_avg := sum(y_i .* K_i) + "Average Henry constant"; + + // + // Caclulate initial guesses ensuring convergence: Reduced spreading pressures + // and hypothetical pure component pressures + // + p_i_pure := p_adsorpt .* K_avg ./ K_i + "Hypothetical pure component pressures"; + + pi_i[1] := func_pi_pT_1(M_adsorptive=M_i[1], + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance=num_comp_1.tolerance_pi) + "Reduced spreading pressure of the first component"; + pi_i[2] := func_pi_pT_2(M_adsorptive=M_i[2], + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance=num_comp_2.tolerance_pi) + "Reduced spreading pressure of the second component"; + + pi := min(pi_i) + "Reduced spreading pressure of all components"; + p_i_pure := pi ./ K_i + "Hypothetical pure component pressures"; + + end if; + + // + // Outer loop: Ensure mass conservation + // + while error_outer >= num.tolerance_outer and no_outer <= num.no_max_outer loop + // + // Inner loop: Ensure identical spreading pressures + // + no_inner :=1 + "Counter of inner loop"; + error_inner :=1 + "Error of inner loop"; + + while error_inner >= num.tolerance_inner and no_inner <= num.no_max_inner loop + // + // Calculate reduced spreading pressures + // + pi_i[1] := func_pi_pT_1(M_adsorptive=M_i[1], + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance=num_comp_1.tolerance_pi) + "Reduced spreading pressure of the first component"; + pi_i[2] := func_pi_pT_2(M_adsorptive=M_i[2], + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance=num_comp_2.tolerance_pi) + "Reduced spreading pressure of the second component"; + + // + // Apply Newton-Raphson method + // + delta_pi_i := pi_i .- pi + "Difference betwenn reduced spreading pressures and reduced spreading pressure + of all components"; + + ddelta_pi_i_dp_i_pure[1] := 1/M_i[1] * func_x_pT_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) / p_i_pure[1] + "Partial derivative of difference between reduced spreading pressure of the + first component and reduced spreading pressure of all components w.r.t. the + hypothetical pure component pressure of the first component"; + ddelta_pi_i_dp_i_pure[2] := 1/M_i[2] * func_x_pT_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) / p_i_pure[2] + "Partial derivative of difference between reduced spreading pressure of the + second component and reduced spreading pressure of all components w.r.t. the + hypothetical pure component pressure of the second component"; + + p_i_pure := p_i_pure .- delta_pi_i ./ ddelta_pi_i_dp_i_pure + "Hypothetical pure component pressures"; + + // + // Check for convergence + // + no_inner := no_inner + 1 + "Counter of inner loop"; + error_inner := sum(abs(delta_pi_i)) + "Error of inner loop"; + + end while; + + // + // Calculate mole fractions of adsorpt phase + // + z_i := y_i .* p_adsorpt ./ p_i_pure + "Mole fractions of the adsorpt phase"; + + // + // Calculate equilibrium uptakes + // + q_adsorpt_i[1] := 1/M_i[1] * func_x_pT_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure compoment pressure of the + first component"; + q_adsorpt_i[2] := 1/M_i[2] * func_x_pT_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure compoment pressure of the + second component"; + + q_adsorpt := 1 / sum(z_i ./ q_adsorpt_i) + "Total molar equilibrium uptake"; + + // + // Apply Newton-Raphson method + // + pi := pi + (-(1 - sum(z_i)) / (1/q_adsorpt)) + "Reduced spreading pressure of all components"; + + // + // Check for convergence + // + no_outer := no_outer + 1 + "Counter of outer loop"; + error_outer := abs(1 - sum(z_i)) + "Error of outer loop"; + + end while; + + // + // Calculate final ouputs + // + x_adsorpt := q_adsorpt .* z_i .* M_i + "Equilibrium uptakes of the adsorpt phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function provides an algorithm for solving the IAST for two components. The +uptakes <i>x_adsorpt</i> are calculated as a function of the pressure <i>p_adsorpt</i>, +the molar composition of the gas/vapour phase <i>y_i</i>, and the temperature +<i>T_adsorpt</i>. The algorithm uses two loops, with the inner loop nested in the +outer loop. Hence, the algorithm is called 'Nested Loop.' The inner loop iterates +over the reduced spreading pressure <i>π</i>, while the outer loop iterates over +the molar composition of the adsorpt phase <i>z<sub><I>i</i></sub></i>. +</p> + +<h4>Main equations</h4> +<p> +The algorithm consists of 17 steps: +</p> +<ol> + <li> + Calculate the Henry's constant of each component <i>i</i>: + <pre>K<sub><i>i</i></sub> = 1 / M<sub><i>i</i></sub> * dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub>,</pre> + where <i>M<sub><i>i</i></sub></i> is the molar mass and <i>dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub></i> + is the partial derivative of the uptake with respect to the pressure. + <br> + </li> + <li> + Calculate the average Henry's constant: + <pre>K<sub>avg</sub> = ∑<sub><i>i</i></sub> y<sub><i>i</i></sub> * K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = p<sub>adsorpt</sub> * K<sub>avg</sub> / K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressures of each component <i>i</i>: + <pre>π<sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the initial guess of the reduced spreading pressure: + <pre>π = <strong>min</strong>(π<sub><i>i</i></sub>).</pre> + <br> + </li> + <li> + Calculate the initial guesses of the hypothetical pure component pressures of each + component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = π / K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressures of each component <i>i</i>: + <pre>π<sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the differences between the reduced spreading pressure of each + component <i>i</i> and the reduced spreading pressure of the last component: + <pre>Δπ<sub><i>i</i></sub> = π<sub><i>i</i></sub> - π<sub>last</sub>.</pre> + <br> + </li> + <li> + Calculate the partial derivatives of the differences between the reduced + spreading pressure of each component <i>i</i> and the reduced spreading + pressure of the last component with respect to the hypothetical pure + component pressures: + <pre>dΔπ<sub><i>i</i></sub>/dp<sup>*</sup><sub><i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>) / p<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component + <i>i</i> of the next iteration step: + <pre>p<sup>*</sup><sub>next,<i>i</i></sub> = p<sup>*</sup><sub><i>i</i></sub> - Δπ<sub><i>i</i></sub> / dΔπ<sub><i>i</i></sub>/dp<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Check for convergence of the inner loop: + <pre>∑<sub><i>i</i></sub> |Δπ<sub><i>i</i></sub>| ≤ tolerance.</pre> + If the convergence criterion is not fulfilled, got to step 7. It the convergence + criterion is fulfilled, got to step 12. + <br> + </li> + <li> + Calculate the molar composition of each component <i>i</i> in the adsorpt + phase: + <pre>z<sub><i>i</i></sub> = y<sub><i>i</i></sub> * p<sub>adsorpt</sub> / p<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the molar uptake of each component <i>i</i>: + <pre>q<sub>adsorpt,<i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the total molar uptake: + <pre>q<sub>adsorpt,total</sub> = 1 / ∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> / q<sub>adsorpt,<i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressure of the next iteration step: + <pre>π<sub>next</sub> = π - (1 - ∑ z<sub><i>i</i></sub>) / (1 / q<sub>adsorpt,total</sub>).</pre> + <br> + </li> + <li> + Check for convergence of the outer loop: + <pre>|1 - ∑<sub><i>i</i></sub> z<sub><i>i</i></sub>| ≤ tolerance.</pre> + If the convergence criterion is not fulfilled, got to step 7. It the convergence + criterion is fulfilled, got to step 17. + <br> + </li> + <li> + Calculate the uptakes of each component <i>i</i>: + <pre>x<sub>adsorpt,<i>i</i></sub> = M<sub><i>i</i></sub> * z<sub><i>i</i></sub> * q<sub>adsorpt,total</sub>.</pre> + </li> +</ol> + +<h4>References</h4> +<ul> + <li> + Mangano E., Friedrich, D., and Brandani, S. (2015). Robust algorithms for the solution of the ideal adsorbed solution theory equations. AIChE Journal, 61(3): 981–991. DOI: 10.1002/aic.14684. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_pyT_NestedLoop; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/x_pyT_NewtonRaphson.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/x_pyT_NewtonRaphson.mo new file mode 100644 index 0000000000000000000000000000000000000000..1ab9a7c9d1c6d812566bc0b1322f678961c0f3c2 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/Internals/x_pyT_NewtonRaphson.mo @@ -0,0 +1,322 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals; +function x_pyT_NewtonRaphson + "IAST for two components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature using the standard 'Newton-Raphson' algorithm" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[:] y_i + "Mole fractions of the components in the gas or vapor phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean flag_startValues = false + " = true, if start values are given; otherwise, estimate start values" + annotation (Dialog(tab="General", group="Inputs - Start values")); + input SorpLib.Units.ReducedSpreadingPressure pi_0 = 1 + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.Pressure[size(M_i,1)] p_i_pure + "Hypothetical pure component pressures" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.ReducedSpreadingPressure pi + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real[size(M_i,1)] K_i(each unit="mol/(kg.Pa)") + "Henry constants of the components"; + Real K_avg(unit="mol/(kg.Pa)") + "Average Henry constant"; + + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] pi_i + "Reduced spreading pressures"; + + Integer no_iteration = 1 + "Counter of loop"; + Real error = 1 + "Error of loop"; + + SorpLib.Units.MolarUptake[size(M_i,1)] q_adsorpt_i + "Molar equilibrium uptakes at hypothetical pure component pressures"; + + Modelica.Units.SI.MoleFraction delta_sum_z_i + "Satisfaction of molar composition of adsorpt phase"; + Real ddelta_sum_z_i_dpi(unit="kg/mol") + "Partial derivative of satisfaction of molar composition of adsorpt phase + w.r.t. to reduced spreading pressure of all components"; + + Modelica.Units.SI.MoleFraction[size(M_i,1)] z_i + "Mole fractions of the adsorpt phase"; + + SorpLib.Units.MolarUptake q_adsorpt + "Total molar equilibrium uptake"; + +algorithm + if flag_startValues then + // + // Use start values + // + pi := pi_0 + "Reduced spreading pressure of all components"; + + else + // + // Caclulate initial guesses ensuring convergence: Henry constants + // + K_i[1] := 1/M_i[1] * func_dx_dp_1(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_1) + "Henry constant of the first component"; + K_i[2] := 1/M_i[2] * func_dx_dp_2(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_2) + "Henry constant of the second component"; + + K_avg := sum(y_i .* K_i) + "Average Henry constant"; + + // + // Caclulate initial guesses ensuring convergence: Reduced spreading pressures + // and hypothetical pure component pressures + // + p_i_pure := p_adsorpt .* K_avg ./ K_i + "Hypothetical pure component pressures"; + + pi_i[1] := func_pi_pT_1(M_adsorptive=M_i[1], + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance=num_comp_1.tolerance_pi) + "Reduced spreading pressure of the first component"; + pi_i[2] := func_pi_pT_2(M_adsorptive=M_i[2], + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance=num_comp_2.tolerance_pi) + "Reduced spreading pressure of the second component"; + + pi := min(pi_i) + "Reduced spreading pressure of all components"; + + end if; + + // + // Loop to solve the IAST + // + while error >= num.tolerance and no_iteration <= num.no_max loop + // + // Calculate hypothetical pure component pressures + // + p_i_pure[1] := func_p_piT_1( + M_adsorptive=M_i[1], + pi=pi, + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance_p_adsorpt=num_comp_1.tolerance_p_adsorpt, + tolerance_pi=num_comp_1.tolerance_pi) + "Hypothetical pure component pressure of the first component"; + p_i_pure[2] := func_p_piT_2( + M_adsorptive=M_i[2], + pi=pi, + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance_p_adsorpt=num_comp_2.tolerance_p_adsorpt, + tolerance_pi=num_comp_2.tolerance_pi) + "Hypothetical pure component pressure of the first component"; + + // + // Calculate molar uptakes + // + q_adsorpt_i[1] := 1/M_i[1] * func_x_pT_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + first component"; + q_adsorpt_i[2] := 1/M_i[2] * func_x_pT_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + second component"; + + // + // Apply Newton-Raphson method + // + delta_sum_z_i := sum((p_adsorpt .* y_i) ./ p_i_pure) - 1 + "Satisfaction of molar composition of adsorpt phase"; + ddelta_sum_z_i_dpi := -sum((p_adsorpt .* y_i) ./ (p_i_pure .* q_adsorpt_i)) + "Partial derivative of satisfaction of molar composition of adsorpt phase + w.r.t. to reduced spreading pressure of all components"; + + pi := if pi - delta_sum_z_i / ddelta_sum_z_i_dpi > 0 then + pi - delta_sum_z_i / ddelta_sum_z_i_dpi else pi / 2 + "Update reduced spreading pressure of all components"; + + // + // Check for convergence + // + no_iteration := no_iteration + 1 + "Counter of loop"; + error := abs(delta_sum_z_i) + "Error of loop"; + + end while; + + // + // Calculate mole fractions of adsorpt phase + // + z_i := y_i .* p_adsorpt ./ p_i_pure + "Mole fractions of the adsorpt phase"; + + // + // Calculate equilibrium uptake + // + q_adsorpt := 1 / sum(z_i ./ q_adsorpt_i) + "Total molar equilibrium uptake"; + + // + // Calculate final ouputs + // + x_adsorpt := q_adsorpt .* z_i .* M_i + "Equilibrium uptakes of the adsorpt phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function provides an algorithm for solving the IAST for two components. The +uptakes <i>x_adsorpt</i> are calculated as a function of the pressure <i>p_adsorpt</i>, +the molar composition of the gas/vapour phase <i>y_i</i>, and the temperature +<i>T_adsorpt</i>. The algorithm uses a Newton-Raphson method to solve the system +of equations of the IAST. +</p> + +<h4>Main equations</h4> +<p> +The algorithm consists of 14 steps: +</p> +<ol> + <li> + Calculate the Henry's constant of each component <i>i</i>: + <pre>K<sub><i>i</i></sub> = 1 / M<sub><i>i</i></sub> * dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub>,</pre> + where <i>M<sub><i>i</i></sub></i> is the molar mass and <i>dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub></i> + is the partial derivative of the uptake with respect to the pressure. + <br> + </li> + <li> + Calculate the average Henry's constant: + <pre>K<sub>avg</sub> = ∑<sub><i>i</i></sub> y<sub><i>i</i></sub> * K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = p<sub>adsorpt</sub> * K<sub>avg</sub> / K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressures of each component <i>i</i>: + <pre>π<sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the initial guess of the reduced spreading pressure: + <pre>π = <strong>min</strong>(π<sub><i>i</i></sub>).</pre> + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, π, T<sub>adsorpt</sub>).</pre> + This formula is an inverse of the reduced spreading pressure, which often + has to be calculated numerically. + <br> + </li> + <li> + Calculate the molar uptake of each component <i>i</i>: + <pre>q<sub>adsorpt,<i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the satisfaction of the molar composition of the adsorpt phase: + <pre>F = ∑<sub><i>i</i></sub> [y<sub><i>i</i></sub> * x<sub>adsorpt</sub> / p<sup>*</sup><sub><i>i</i></sub>] - 1.</pre> + <br> + </li> + <li> + Calculate the partial derivative of the satisfaction of the adsorpt phase + with respect to the reduced spreading pressure: + <pre>dF/dπ = -∑<sub><i>i</i></sub> [y<sub><i>i</i></sub> * p<sub>adsorpt</sub> / (p<sup>*</sup><sub><i>i</i></sub> * q<sub>adsorpt,<i>i</i></sub>)].</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressure of the next iteration step: + <pre>π<sub>next</sub> = <strong>if</strong> π - F / dF/dπ > 0 <strong>then</strong> π - F / dF/dπ > 0 <strong>else</strong> π/2.</pre> + <br> + </li> + <li> + Check for convergence: + <pre>|F| ≤ tolerance.</pre> + If the convergence criterion is not fulfilled, got to step 6. It the convergence + criterion is fulfilled, got to step 12. + <br> + </li> + <li> + Calculate the molar composition of each component <i>i</i> in the adsorpt + phase: + <pre>z<sub><i>i</i></sub> = y<sub><i>i</i></sub> * p<sub>adsorpt</sub> / p<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the total molar uptake: + <pre>q<sub>adsorpt,total</sub> = 1 / ∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> / q<sub>adsorpt,<i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the uptakes of each component <i>i</i>: + <pre>x<sub>adsorpt,<i>i</i></sub> = M<sub><i>i</i></sub> * z<sub><i>i</i></sub> * q<sub>adsorpt,total</sub>.</pre> + </li> +</ol> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_pyT_NewtonRaphson; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..6fe169941927e2ce296919cae395cdc5bd84ddd2 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/package.mo @@ -0,0 +1,805 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents; +package IAST_N2 "Package containing all functions regarding the IAST for two components" + extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponentsIAST; + + // + // Internal package + // + redeclare final function extends x_pyT + "IAST for two components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + + algorithm + // + // Select IAST algorithm + // + if num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NewtonRaphson then + (x_adsorpt,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "Standard 'Newton-Raphson' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop then + (x_adsorpt,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'Nested Loop' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST then + (x_adsorpt,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'FASTIast' algorithm"; + end if; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, M_i=M_i, c_1=c_1, c_2=c_2, func_x_pT_1=func_x_pT_1, func_p_xT_1=func_p_xT_1, func_dx_dp_1=func_dx_dp_1, func_pi_pT_1=func_pi_pT_1, func_p_piT_1=func_p_piT_1, func_x_pT_2=func_x_pT_2, func_p_xT_2=func_p_xT_2, func_dx_dp_2=func_dx_dp_2, func_pi_pT_2=func_pi_pT_2, func_p_piT_2=func_p_piT_2, num=num, num_comp_1=num_comp_1, num_comp_2=num_comp_2), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, M_i=M_i, c_1=c_1, c_2=c_2, func_x_pT_1=func_x_pT_1, func_p_xT_1=func_p_xT_1, func_dx_dp_1=func_dx_dp_1, func_pi_pT_1=func_pi_pT_1, func_p_piT_1=func_p_piT_1, func_x_pT_2=func_x_pT_2, func_p_xT_2=func_p_xT_2, func_dx_dp_2=func_dx_dp_2, func_pi_pT_2=func_pi_pT_2, func_p_piT_2=func_p_piT_2, num=num, num_comp_1=num_comp_1, num_comp_2=num_comp_2))); + end x_pyT; + + redeclare final function extends p_xyT + "IAST for two components: Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + + algorithm + (p_adsorpt,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.py_xT_NewtonRaphson( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "Standard 'Newton-Raphson' algorithm"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, M_i=M_i, c_1=c_1, c_2=c_2, func_x_pT_1=func_x_pT_1, func_p_xT_1=func_p_xT_1, func_dx_dp_1=func_dx_dp_1, func_pi_pT_1=func_pi_pT_1, func_p_piT_1=func_p_piT_1, func_x_pT_2=func_x_pT_2, func_p_xT_2=func_p_xT_2, func_dx_dp_2=func_dx_dp_2, func_pi_pT_2=func_pi_pT_2, func_p_piT_2=func_p_piT_2, num=num, num_comp_1=num_comp_1, num_comp_2=num_comp_2), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, M_i=M_i, c_1=c_1, c_2=c_2, func_x_pT_1=func_x_pT_1, func_p_xT_1=func_p_xT_1, func_dx_dp_1=func_dx_dp_1, func_pi_pT_1=func_pi_pT_1, func_p_piT_1=func_p_piT_1, func_x_pT_2=func_x_pT_2, func_p_xT_2=func_p_xT_2, func_dx_dp_2=func_dx_dp_2, func_pi_pT_2=func_pi_pT_2, func_p_piT_2=func_p_piT_2, num=num, num_comp_1=num_comp_1, num_comp_2=num_comp_2))); + end p_xyT; + + redeclare final function extends y_pxT + "IAST for two components: Mole fractions of independent gas phase components as function of uptakes, pressure, and temperature" + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ + "Mole fractions of all components in the vapor or gas phase"; + + algorithm + // + // Solve inverse of IAST + // + (,y_i_,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.py_xT_NewtonRaphson( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "Standard 'Newton-Raphson' algorithm"; + + // + // Assign correct output values + // + y_i := y_i_[1:end-1] + "Mole fractions of independent components in the gas or vapor phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, M_i=M_i, c_1=c_1, c_2=c_2, func_x_pT_1=func_x_pT_1, func_p_xT_1=func_p_xT_1, func_dx_dp_1=func_dx_dp_1, func_pi_pT_1=func_pi_pT_1, func_p_piT_1=func_p_piT_1, func_x_pT_2=func_x_pT_2, func_p_xT_2=func_p_xT_2, func_dx_dp_2=func_dx_dp_2, func_pi_pT_2=func_pi_pT_2, func_p_piT_2=func_p_piT_2, num=num, num_comp_1=num_comp_1, num_comp_2=num_comp_2), + p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, M_i=M_i, c_1=c_1, c_2=c_2, func_x_pT_1=func_x_pT_1, func_p_xT_1=func_p_xT_1, func_dx_dp_1=func_dx_dp_1, func_pi_pT_1=func_pi_pT_1, func_p_piT_1=func_p_piT_1, func_x_pT_2=func_x_pT_2, func_p_xT_2=func_p_xT_2, func_dx_dp_2=func_dx_dp_2, func_pi_pT_2=func_pi_pT_2, func_p_piT_2=func_p_piT_2, num=num, num_comp_1=num_comp_1, num_comp_2=num_comp_2))); + end y_pxT; + + redeclare final function extends py_xT + "IAST for two components: Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ + "Mole fractions of all components in the vapor or gas phase"; + + algorithm + // + // Solve inverse of IAST + // + (p_adsorpt,y_i_,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.py_xT_NewtonRaphson( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "Standard 'Newton-Raphson' algorithm"; + + // + // Assign correct output values + // + y_i := y_i_[1:end-1] + "Mole fractions of independent components in the gas or vapor phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + redeclare final function extends dx_dp + "IAST for two components: Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature (numerical solution)" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_pdp + "Equilibrium uptakes of the adsorpt phase: p + dp"; + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_mdp + "Equilibrium uptakes of the adsorpt phase: p - dp"; + + algorithm + // + // Select IAST algorithm + // + if num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NewtonRaphson then + (x_adsorpt_pdp,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt + dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "Standard 'Newton-Raphson' algorithm"; + + (x_adsorpt_mdp,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt - dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "Standard 'Newton-Raphson' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop then + (x_adsorpt_pdp,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt + dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'Nested Loop' algorithm"; + + (x_adsorpt_mdp,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt - dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'Nested Loop' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST then + (x_adsorpt_pdp,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt + dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'FASTIast' algorithm"; + + (x_adsorpt_mdp,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt - dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'FASTIast' algorithm"; + end if; + + // + // Calculate derivatives of loadings w.r.t. equilibrium pressure + // + dx_adsorpt_dp_adsorpt := (x_adsorpt_pdp .- x_adsorpt_mdp) ./ (2*dp) + "Calculation of the partial derivatives of the equilibrium uptakes w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + end dx_dp; + + redeclare final function extends dx_dy + "IAST for two components: Partial derivative of uptakes w.r.t. mole fractions of independent gas phase components at constant pressure and temperature (numerical solution)" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_pdy + "Equilibrium uptakes of the adsorpt phase: y + dy"; + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_mdy + "Equilibrium uptakes of the adsorpt phase: y - dy"; + + algorithm + for ind_y_i in 1:size(M_i,1)-1 loop + // + // Select IAST algorithm + // + if num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NewtonRaphson then + (x_adsorpt_pdy,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt, + y_i=cat(1, y_i_[1:ind_y_i - 1], {y_i_[ind_y_i] + dy}, y_i_[ind_y_i + 1:size(M_i,1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "Standard 'Newton-Raphson' algorithm"; + + (x_adsorpt_mdy,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt, + y_i=cat(1, y_i_[1:ind_y_i - 1], {y_i_[ind_y_i] - dy}, y_i_[ind_y_i + 1:size(M_i,1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "Standard 'Newton-Raphson' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop then + (x_adsorpt_pdy,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=cat(1, y_i_[1:ind_y_i - 1], {y_i_[ind_y_i] + dy}, y_i_[ind_y_i + 1:size(M_i,1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'Nested Loop' algorithm"; + + (x_adsorpt_mdy,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=cat(1, y_i_[1:ind_y_i - 1], {y_i_[ind_y_i] - dy}, y_i_[ind_y_i + 1:size(M_i,1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'Nested Loop' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST then + (x_adsorpt_pdy,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt, + y_i=cat(1, y_i_[1:ind_y_i - 1], {y_i_[ind_y_i] + dy}, y_i_[ind_y_i + 1:size(M_i,1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'FASTIast' algorithm"; + + (x_adsorpt_mdy,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt, + y_i=cat(1, y_i_[1:ind_y_i - 1], {y_i_[ind_y_i] - dy}, y_i_[ind_y_i + 1:size(M_i,1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'FASTIast' algorithm"; + end if; + + // + // Calculate partial darivatives for each independent mole fraction + // + dx_adsorpt_dy_i[:,ind_y_i] := (x_adsorpt_pdy .- x_adsorpt_mdy) ./ (2*dy) + "Partial derivatives of the uptakes w.r.t. the mole fractions of independent + gas phase components at constant pressure and temperature"; + end for; + end dx_dy; + + redeclare final function extends dx_dT + "IAST for two components: Partial derivative of uptakes w.r.t. temperature at constant pressure and mole fractions (numerical solution)" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_pdT + "Equilibrium uptakes of the adsorpt phase: T + dT"; + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_mdT + "Equilibrium uptakes of the adsorpt phase: T - dT"; + + algorithm + // + // Select IAST algorithm + // + if num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NewtonRaphson then + (x_adsorpt_pdT,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt + dT, + M_i=M_i, + c_1=c_pdT_1, + c_2=c_pdT_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "Standard 'Newton-Raphson' algorithm"; + + (x_adsorpt_mdT,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt - dT, + M_i=M_i, + c_1=c_mdT_1, + c_2=c_mdT_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "Standard 'Newton-Raphson' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop then + (x_adsorpt_pdT,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt + dT, + M_i=M_i, + c_1=c_pdT_1, + c_2=c_pdT_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'Nested Loop' algorithm"; + + (x_adsorpt_mdT,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt - dT, + M_i=M_i, + c_1=c_mdT_1, + c_2=c_mdT_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'Nested Loop' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST then + (x_adsorpt_pdT,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt + dT, + M_i=M_i, + c_1=c_pdT_1, + c_2=c_pdT_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'FASTIast' algorithm"; + + (x_adsorpt_mdT,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N2.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt - dT, + M_i=M_i, + c_1=c_mdT_1, + c_2=c_mdT_2, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2) "'FASTIast' algorithm"; + end if; + + // + // Calculate derivatives of loadings w.r.t. equilibrium pressure + // + dx_adsorpt_dT_adsorpt := (x_adsorpt_pdT .- x_adsorpt_mdT) ./ (2*dT) + "Calculation of the partial derivatives of the equilibrium uptakes w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + end dx_dT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +The IAST for two components calculates equilibrium uptakes <i>x_adsorpt</i> as a +function of the equilibrium pressure <i>p_adsorpt</i>, mole fractions of independent +components in the gas or vapor phase <i>y_i</i>, and the equilibrium temperature +<i>T_adsorpt</i>. The IAST calculates the multi-component adsorption equilibrium based +on the pure component isotherm models. For this purpose, a system of equations is +solved using numerical methods. +</p> + +<h4>Main equations</h4> +<p> +The system of equations consists of 2 * <i>n_components</i> + 1 equations (i.e., 5), +which can be divided into 4 main equation types: +</p> +<ol> + <li> + Reduced spreading pressure <i>π</i> that is the same for all components: + <pre>π = π<sub><i>i</i></sub> = ∫<sub>0</sub><sup>p<sup>*</sup><sub><i>i</i></sub></sup> [x<sub>adsorpt,<i>i</i></sub> / p<sub>adsorpt,<i>i</i></sub> * dp<sub>adsorpt,<i>i</i></sub>].</pre> + <br> + </li> + <li> + Closing condition of the molar composition of the adsorpt phase <i>z<sub><i>i</i></sub></i>: + <pre>1 = ∑<sub><i>i</i></sub> z<sub><i>i</i></sub> = ∑<sub><i>i</i></sub> [y<sub><i>i</i></sub> * p<sub>adsorpt</sub> / p<sup>*</sup><sub><i>i</i></sub>].</pre> + <br> + </li> + <li> + Molar uptake of the adsorpt phase of each component <i>i</i>: + <pre>q<sub>adsorpt,<i>i</i></sub> = z<sub><i>i</i></sub> * q<sub>total</sub>.</pre> + <br> + </li> + <li> + Total molar uptake of the adsorpt phase: + <pre>q<sub>total</sub> = (∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> / q<sub>adsorpt,<i>i</i></sub>]) ^ (-1).</pre> + <br> + </li> +</ol> +<p> +Herein, for each component <i>i</i<>, <i>p<sup>*</sup><sub><i>i</i></sub></i> is the +hypothetical pure component pressure at which the reduced spreading pressure of each +component <i>π<sub><i>i</i></sub></i> is identical (i.e., equilibrium condition). +</p> + +<h4>Example</h4> +<p> +The following figure shows the IAST for two components for one parameter set. In the +upper sub-figure, the equilibrium pressure changes with time. In the centre sub-figure, +the independent mole fractions change with time. In the lower sub-figure, the +equilibrium temperature changes with time. The left side shows the uptake of component +1, and the right side shows the uptake of component 2. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_multi_iast_n2.png\" alt=\"media_functions_equilibria_multi_iast_n2.png\"> + +<h4>References</h4> +<p> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Mangano E., Friedrich, D., and Brandani, S. (2015). Robust algorithms for the solution of the ideal adsorbed solution theory equations. AIChE Journal, 61(3): 981–991. DOI: 10.1002/aic.14684. + </li> +</ul> +</p> +</html>")); +end IAST_N2; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6d0f8d93aba1f8e0f67c45861309e4734531ccf1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N2/package.order @@ -0,0 +1,8 @@ +Internals +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..47a7a1b05990bd581b025ddc91768595c20422c6 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3; +package Internals "Internal functions used to avoid redundancy" + extends Modelica.Icons.InternalPackage; + + annotation (Documentation(info="<html> +<p> +This package contains functions used for various functions of the IAST for +three components. Thus, redundancy of code shall be avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Internals; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/package.order new file mode 100644 index 0000000000000000000000000000000000000000..28701d404ff72aa0ee4cedb83bc2b64d1ae6df25 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/package.order @@ -0,0 +1,4 @@ +x_pyT_NewtonRaphson +x_pyT_NestedLoop +x_pyT_FastIAST +py_xT_NewtonRaphson diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/py_xT_NewtonRaphson.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/py_xT_NewtonRaphson.mo new file mode 100644 index 0000000000000000000000000000000000000000..0db815632ab958a31dac18596983a63ce0a7d683 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/py_xT_NewtonRaphson.mo @@ -0,0 +1,398 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals; +function py_xT_NewtonRaphson + "IAST for three components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature using the standard 'Newton-Raphson' algorithm" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + input Boolean flag_startValues = false + " = true, if start values are given; otherwise, estimate start values" + annotation (Dialog(tab="General", group="Inputs - Start values")); + input SorpLib.Units.ReducedSpreadingPressure pi_0 = 1 + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i + "Mole fractions of components in the vapor or gas phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.Pressure[size(M_i,1)] p_i_pure + "Hypothetical pure component pressures" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.ReducedSpreadingPressure pi + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] pi_i + "Reduced spreading pressures"; + + Integer no_iteration = 1 + "Counter of loop"; + Real error = 1 + "Error of loop"; + + SorpLib.Units.MolarUptake[size(M_i,1)] q_adsorpt_i = x_adsorpt ./ M_i + "Molar equilibrium uptakes at hypothetical pure component pressures"; + Real[size(M_i,1)] dq_adsorpt_i_dp_i_pure(each unit="mol/(kg.Pa)") + "Partical derivatives of molar equilibrium uptakes at hypothetical pure + component pressures w.r.t. hypothetical pure component pressures"; + + Real delta_sum_q_adsorpt(unit="kg/mol") + "Satisfaction of total molar uptake"; + Real ddelta_sum_q_adsorpt_dpi(unit="kg.kg/(mol.mol)") + "Partial derivative of satisfaction of total molar uptake w.r.t. to reduced + spreading pressure of all components"; + + SorpLib.Units.MolarUptake q_adsorpt = sum(q_adsorpt_i) + "Total molar equilibrium uptake"; + + Modelica.Units.SI.MoleFraction[size(M_i,1)] z_i = q_adsorpt_i ./ q_adsorpt + "Mole fractions of the adsorpt phase"; + +algorithm + if flag_startValues then + // + // Use start values + // + pi := pi_0 + "Reduced spreading pressure of all components"; + + else + // + // Caclulate initial guesses ensuring convergence: Equilibrium pressures + // + p_i_pure[1] := func_p_xT_1(x_adsorpt=x_adsorpt[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Pure component pressure of the first component (not at hypothetical pressure)"; + p_i_pure[2] := func_p_xT_2(x_adsorpt=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Pure component pressure of the second component (not at hypothetical pressure)"; + p_i_pure[3] := func_p_xT_3(x_adsorpt=x_adsorpt[3], + T_adsorpt=T_adsorpt, + c=c_3, + p_adsorpt_lb_start=num_comp_3.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_3.p_adsorpt_ub_start, + tolerance=num_comp_3.tolerance_p_adsorpt) + "Pure component pressure of the third component (not at hypothetical pressure)"; + + // + // Caclulate initial guesses ensuring convergence: Reduced spreading pressures + // + pi_i[1] := func_pi_pT_1(M_adsorptive=M_i[1], + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance=num_comp_1.tolerance_pi) + "Reduced spreading pressure of the first component"; + pi_i[2] := func_pi_pT_2(M_adsorptive=M_i[2], + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance=num_comp_2.tolerance_pi) + "Reduced spreading pressure of the second component"; + pi_i[3] := func_pi_pT_3(M_adsorptive=M_i[3], + p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + integral_pi_lb=num_comp_3.integral_pi_lb, + tolerance=num_comp_3.tolerance_pi) + "Reduced spreading pressure of the third component"; + + pi := sum(z_i .* pi_i) + "Reduced spreading pressure of all components"; + + end if; + + // + // Loop to solve the inverse of the IAST + // + while error >= num.tolerance_inv and no_iteration <= num.no_max_inv loop + // + // Calculate hypothetical pure component pressures + // + p_i_pure[1] := func_p_piT_1( + M_adsorptive=M_i[1], + pi=pi, + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance_p_adsorpt=num_comp_1.tolerance_p_adsorpt, + tolerance_pi=num_comp_1.tolerance_pi) + "Hypothetical pure component pressure of the first component"; + p_i_pure[2] := func_p_piT_2( + M_adsorptive=M_i[2], + pi=pi, + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance_p_adsorpt=num_comp_2.tolerance_p_adsorpt, + tolerance_pi=num_comp_2.tolerance_pi) + "Hypothetical pure component pressure of the first component"; + p_i_pure[3] := func_p_piT_3( + M_adsorptive=M_i[3], + pi=pi, + T_adsorpt=T_adsorpt, + c=c_3, + p_adsorpt_lb_start=num_comp_3.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_3.p_adsorpt_ub_start, + integral_pi_lb=num_comp_3.integral_pi_lb, + tolerance_p_adsorpt=num_comp_3.tolerance_p_adsorpt, + tolerance_pi=num_comp_3.tolerance_pi) + "Hypothetical pure component pressure of the third component"; + + // + // Calculate molar uptakes + // + q_adsorpt_i[1] := 1/M_i[1] * func_x_pT_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + first component"; + q_adsorpt_i[2] := 1/M_i[2] * func_x_pT_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + second component"; + q_adsorpt_i[3] := 1/M_i[3] * func_x_pT_3(p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + p_adsorpt_lb_start=num_comp_3.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_3.p_adsorpt_ub_start, + tolerance=num_comp_3.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + third component"; + + // + // Calculate partial derivatives of molar uptakes w.r.t. hypothetical pure + // component pressures + // + dq_adsorpt_i_dp_i_pure[1] := 1/M_i[1] * func_dx_dp_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1) + "Molar equilibrium uptake at hypothetical pure component pressure of the + first component"; + dq_adsorpt_i_dp_i_pure[2] := 1/M_i[2] * func_dx_dp_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2) + "Molar equilibrium uptake at hypothetical pure component pressure of the + second component"; + dq_adsorpt_i_dp_i_pure[3] := 1/M_i[3] * func_dx_dp_3(p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3) + "Molar equilibrium uptake at hypothetical pure component pressure of the + third component"; + + // + // Apply Newton-Raphson method + // + delta_sum_q_adsorpt := sum(z_i ./ q_adsorpt_i) - 1 / q_adsorpt + "Satisfaction of total molar uptake"; + ddelta_sum_q_adsorpt_dpi := -sum(z_i .* p_i_pure ./ q_adsorpt_i .^ 3 .* + dq_adsorpt_i_dp_i_pure) + "Partial derivative of satisfaction of total molar uptake w.r.t. to reduced + spreading pressure of all components"; + + pi := if pi - delta_sum_q_adsorpt / ddelta_sum_q_adsorpt_dpi > 0 then + pi - delta_sum_q_adsorpt / ddelta_sum_q_adsorpt_dpi else pi / 2 + "Update reduced spreading pressure of all components"; + + // + // Check for convergence + // + no_iteration := no_iteration + 1 + "Counter of loop"; + error := abs(delta_sum_q_adsorpt) + "Error of loop"; + + end while; + + // + // Calculate final ouputs + // + p_adsorpt := sum(z_i .* p_i_pure) + "Equilibrium pressure of the adsorpt phase"; + + y_i := z_i .* p_i_pure ./ p_adsorpt + "Mole fractions of components in the vapor or gas phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function provides an algorithm for solving the inverse of the IAST for three +components. The pressure <i>p_adsorpt</i> and molar composition of the gas/vapour +phase <i>y_i</i> are calculated as a function of the uptakes <i>x_adsorpt</i> +and the temperature <i>T_adsorpt</i>. The algorithm uses a Newton-Raphson method +to solve the system of equations of the inverse of the IAST. +</p> + +<h4>Main equations</h4> +<p> +The algorithm consists of 13 steps: +</p> +<ol> + <li> + Calculate the pure component pressures of each component <i>i</i>: + <pre>p<sub>adsorpt,<i>i</i></sub> = f(x<sub>adsorpt,<i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressures of each component <i>i</i>: + <pre>π<sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, p<sub>adsorpt,<i>i</i></sub>, T<sub>adsorpt</sub>),</pre> + where <i>M<sub><i>i</i></sub></i> is the molar mass. + <br> + </li> + </li> + <li> + Calculate the initial guess of the reduced spreading pressure: + <pre>π = ∑<sub><i>i</i></sub> z<sub><i>i</i></sub> * π<sub><i>i</i></sub>,</pre> + where <i>z<sub><i>i</i></sub></i> is the molar molar composition of each component + <i>i</i> in the adsorpt phase + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, π, T<sub>adsorpt</sub>).</pre> + This formula is an inverse of the reduced spreading pressure, which often + has to be calculated numerically. + <br> + </li> + <li> + Calculate the molar uptake of each component <i>i</i>: + <pre>q<sub>adsorpt,<i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate partial derivatives of the molar uptake of each component <i>i</i> + with respect to the hypothetical pure component pressures of each component + <i>i</i>: + <pre>dq<sub>adsorpt,<i>i</i></sub>/dp<sup>*</sup><sub><i>i</i></sub> = 1 / M<sub><i>i</i></sub> * dx<sub>adsorpt,<i>i</i></sub>/dp<sub>adsorpt</sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>),</pre> + where <i>dx<sub>adsorpt,<i>i</i></sub>/dp<sub>adsorpt</sub></i> is the partial + derivative of the uptake with respect to the pressure. + <br> + </li> + <li> + Calculate the satisfaction of the total molar uptake: + <pre>F = ∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> / q<sub>adsorpt,<i>i</i></sub>] - 1 / ∑<sub><i>i</i></sub> [x<sub>adsorpt,<i>i</i></sub> / M<sub><i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the partial derivative of the total molar uptake with respect to the + reduced spreading pressure: + <pre>dF/dπ = -∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> * p<sup>*</sup><sub><i>i</i></sub> / (q<sup>3</sup><sub>adsorpt,<i>i</i></sub>) * dq<sub>adsorpt,<i>i</i></sub>/dp<sup>*</sup><sub><i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressure of the next iteration step: + <pre>π<sub>next</sub> = <strong>if</strong> π - F / dF/dπ > 0 <strong>then</strong> π - F / dF/dπ > 0 <strong>else</strong> π/2.</pre> + <br> + </li> + <li> + Check for convergence: + <pre>|F| ≤ tolerance.</pre> + If the convergence criterion is not fulfilled, got to step 4. It the convergence + criterion is fulfilled, got to step 11. + <br> + </li> + <li> + Calculate the partial pressure of each component <i>i</i>: + <pre>p<sub>adsorpt,<i>i</i></sub> = z<sub><i>i</i></sub> * p<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the pressure: + <pre>p<sub>adsorpt</sub> = ∑<sub><i>i</i></sub> p<sub>adsorpt,<i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the molar fractions each component <i>i</i> in the gas/vapor + phase: + <pre>y<sub><i>i</i></sub> = p<sub>adsorpt,<i>i</i></sub> / p<sub>adsorpt</sub>.</pre> + </li> +</ol> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end py_xT_NewtonRaphson; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/x_pyT_FastIAST.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/x_pyT_FastIAST.mo new file mode 100644 index 0000000000000000000000000000000000000000..8d20c51d9757dd3f894c5837b975229edf1a0d80 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/x_pyT_FastIAST.mo @@ -0,0 +1,538 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals; +function x_pyT_FastIAST + "IAST for three components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature using the 'FastIAST' algorithm" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[:] y_i + "Mole fractions of the components in the gas or vapor phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + input Boolean flag_startValues = false + " = true, if start values are given; otherwise, estimate start values" + annotation (Dialog(tab="General", group="Inputs - Start values")); + input Real[size(M_i,1)] Kp_i_0(each unit="1/Pa") = fill(1, size(M_i,1)) + "Auxiliary variable for reduced pressues of the components" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + input Real[size(M_i,1)] eta_i_0(each unit="1") = fill(1, size(M_i,1)) + "Reduced pressures of the components" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.Pressure[size(M_i,1)] p_i_pure + "Hypothetical pure component pressures" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.ReducedSpreadingPressure pi + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Real[size(M_i,1)] Kp_i(each unit="1/Pa") + "Auxiliary variable for reduced pressues of the components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Real[size(M_i,1)] eta_i(each unit="1") + "Reduced pressures of the components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real[size(M_i,1)] K_i(each unit="mol/(kg.Pa)") + "Henry constants of the components"; + Real K_avg(unit="mol/(kg.Pa)") + "Average Henry constant"; + + SorpLib.Units.MolarUptake[size(M_i,1)] q_adsorpt_sat + "Saturation uptakes of the components"; + + Integer no_iteration = 1 + "Counter of loop"; + Real error = 1 + "Error of loop"; + + Real[size(M_i,1)] Jac_last_row + "Jacobian matrix: Elements of the last row"; + Real[size(M_i,1)] Jac_diagonal + "Jacobian matrix: Elements of the diagonal"; + + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] pi_i + "Reduced spreading pressures"; + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] delta_pi_i + "Difference between reduced spreading pressures and reduced spreading pressure + of last component"; + + Real[size(M_i,1)] delta_eta_i(each unit="1") + "Newton steps for reduced pressures of the components"; + + Modelica.Units.SI.MoleFraction[size(M_i,1)] z_i + "Mole fractions of the adsorpt phase"; + + SorpLib.Units.MolarUptake[size(M_i,1)] q_adsorpt_i + "Molar equilibrium uptakes at hypothetical pure component pressures"; + SorpLib.Units.MolarUptake q_adsorpt + "Total molar equilibrium uptake"; + +algorithm + if flag_startValues then + // + // Use start values + // + Kp_i := Kp_i_0 + "Auxiliary variable for reduced pressues of the components"; + + eta_i := eta_i_0 + "Reduced pressures of the components"; + + else + // + // Caclulate initial guesses ensuring convergence: Henry constants + // + K_i[1] := 1/M_i[1] * func_dx_dp_1(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_1) + "Henry constant of the first component"; + K_i[2] := 1/M_i[2] * func_dx_dp_2(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_2) + "Henry constant of the second component"; + K_i[3] := 1/M_i[3] * func_dx_dp_3(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_3) + "Henry constant of the third component"; + + K_avg := sum(y_i .* K_i) + "Average Henry constant"; + + // + // Calculate initial guesses ensuring convergence: Saturation uptakes + // + q_adsorpt_sat[1] := 1/M_i[1] * func_x_pT_1( + p_adsorpt=num.p_sat_0, + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Saturation uptake of the first component"; + q_adsorpt_sat[2] := 1/M_i[2] * func_x_pT_2( + p_adsorpt=num.p_sat_0, + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Saturation uptake of the second component"; + q_adsorpt_sat[3] := 1/M_i[3] * func_x_pT_3( + p_adsorpt=num.p_sat_0, + T_adsorpt=T_adsorpt, + c=c_3, + p_adsorpt_lb_start=num_comp_3.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_3.p_adsorpt_ub_start, + tolerance=num_comp_3.tolerance_p_adsorpt) + "Saturation uptake of the third component"; + + // + // Calculate initial guesses ensuring convergence: Reduced pressures + // + Kp_i := K_i ./ q_adsorpt_sat + "Auxiliary variable for reduced pressues of the components"; + + eta_i := {min(Kp_i[i] / K_i[i] * p_adsorpt * K_avg, p_adsorpt * Kp_i[i]) + for i in 1:size(M_i,1)} + "Reduced pressures of the components"; + + end if; + + // + // Loop to solve the IAST + // + while error >= num.tolerance and no_iteration <= num.no_max loop + // + // Calculate the Jacobian matrix: Last row + // + Jac_last_row := Kp_i .* p_adsorpt .* y_i ./ eta_i.^2 + "Jacobian matrix: Elements of the last row"; + + // + // Calculate hypothetical pure component pressures + // + p_i_pure := eta_i ./ Kp_i + "Hypothetical pure component pressures"; + + // + // Calculate the Jacobian matrix: Diagonal + // + Jac_diagonal[1] := 1 / (M_i[1] * eta_i[1]) * func_x_pT_1( + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Diagonale of the Jacobian matrix: Component 1"; + Jac_diagonal[2] := 1 / (M_i[2] * eta_i[2]) * func_x_pT_2( + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Diagonale of the Jacobian matrix: Component 2"; + Jac_diagonal[3] := 1 / (M_i[3] * eta_i[3]) * func_x_pT_3( + p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + p_adsorpt_lb_start=num_comp_3.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_3.p_adsorpt_ub_start, + tolerance=num_comp_3.tolerance_p_adsorpt) + "Diagonale of the Jacobian matrix: Component 3"; + + // + // Calculate the Jacobian matrix: Correct last element of the diagonal + // + Jac_diagonal[end] := Jac_last_row[end] + Jac_diagonal[end] * + sum(Jac_last_row[1:end-1] ./ Jac_diagonal[1:end-1]) + "Diagonale of the Jacobian matrix: Last element of the diagonal"; + + // + // Calculate recuded spreading pressures + // + pi_i[1] := func_pi_pT_1(M_adsorptive=M_i[1], + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance=num_comp_1.tolerance_pi) + "Reduced spreading pressure of the first component"; + pi_i[2] := func_pi_pT_2(M_adsorptive=M_i[2], + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance=num_comp_2.tolerance_pi) + "Reduced spreading pressure of the second component"; + pi_i[3] := func_pi_pT_3(M_adsorptive=M_i[3], + p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + integral_pi_lb=num_comp_3.integral_pi_lb, + tolerance=num_comp_3.tolerance_pi) + "Reduced spreading pressure of the third component"; + + // + // Calculate residuals + // + delta_pi_i := pi_i .- pi_i[end] + "Difference between reduced spreading pressures and reduced spreading pressure + of last component"; + delta_pi_i[end] := 1 - sum(Kp_i .* p_adsorpt .* y_i ./ eta_i) - + sum(Jac_last_row[1:end-1] ./ Jac_diagonal[1:end-1] .* delta_pi_i[1:end-1]) + "Difference between reduced spreading pressures and reduced spreading pressure + of last component: Last element"; + + // + // Apply Newton-Raphson method + // + delta_eta_i[end] := -delta_pi_i[end] / Jac_diagonal[end] + "Newton steps for reduced pressures of the components: Last component"; + delta_eta_i[1:end-1] := (-delta_pi_i[1:end-1] .+ Jac_diagonal[end] * + delta_eta_i[end]) ./ Jac_diagonal[1:end-1] + "Newton steps for reduced pressures of the components: Remaining components"; + + for i in 1:size(M_i,1) loop + if eta_i[i] + delta_eta_i[i] < 0 then + eta_i[i] := eta_i[i] / 2 + "Update reduced pressure"; + + else + eta_i[i] := eta_i[i] + delta_eta_i[i] + "Update reduced pressure"; + + end if; + end for; + + // + // Check for convergence + // + no_iteration := no_iteration + 1 + "Counter of loop"; + error := sum(abs(delta_eta_i)) + "Error of loop"; + + end while; + + // + // Return final results + // + if error >= num.tolerance or no_iteration > num.no_max or max(p_i_pure) >= 1e30 then + // + // Calculation failed: Use 'Nested Loop' algorithm as fallback solution + // + (x_adsorpt,p_i_pure,pi) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=y_i, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'Nested Loop' algorithm to solve IAST"; + + else + // + // Calculate mole fractions of adsorpt phase + // + z_i := y_i .* p_adsorpt ./ p_i_pure + "Mole fractions of the adsorpt phase"; + + // + // Calculate equilibrium uptakes + // + q_adsorpt_i[1] := 1/M_i[1] * func_x_pT_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + first component"; + q_adsorpt_i[2] := 1/M_i[2] * func_x_pT_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + second component"; + q_adsorpt_i[3] := 1/M_i[3] * func_x_pT_3(p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + p_adsorpt_lb_start=num_comp_3.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_3.p_adsorpt_ub_start, + tolerance=num_comp_3.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + second component"; + + q_adsorpt := 1 / sum(z_i ./ q_adsorpt_i) + "Total molar equilibrium uptake"; + + // + // Calculate final ouputs + // + x_adsorpt := q_adsorpt .* z_i .* M_i + "Equilibrium uptakes of the adsorpt phase"; + + pi := pi_i[end] + "Reduced spreading pressure of all components"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function provides an algorithm for solving the IAST for three components. The +uptakes <i>x_adsorpt</i> are calculated as a function of the pressure <i>p_adsorpt</i>, +the molar composition of the gas/vapour phase <i>y_i</i>, and the temperature +<i>T_adsorpt</i>. The algorithm uses one loops to iterate simultaneously over the +reduced spreading pressure <i>π</i> and the molar composition of the adsorpt phase +<i>z<sub><I>i</i></sub></i>. The algorithm exploits that all relevant information can +be written into a Jacobian matrix in which all elements are zero except the last row, +the last column, and the diagonal. For the calculation, only the information of the +last row and diagonal is required, which reduces the computational effort. +</p> + +<h4>Main equations</h4> +<p> +The algorithm consists of 20 steps: +</p> +<ol> + <li> + Calculate the Henry's constant of each component <i>i</i>: + <pre>K<sub><i>i</i></sub> = 1 / M<sub><i>i</i></sub> * dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub>,</pre> + where <i>M<sub><i>i</i></sub></i> is the molar mass and <i>dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub></i> + is the partial derivative of the uptake with respect to the pressure. + <br> + </li> + <li> + Calculate the average Henry's constant: + <pre>K<sub>avg</sub> = ∑<sub><i>i</i></sub> y<sub><i>i</i></sub> * K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the molar saturation uptake of each component <i>i</i>: + <pre>q<sub>adsorpt,sat,<i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p → ∞, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate auxiliary variable of each component <i>i</i>: + <pre>Kp<sub><i>i</i></sub> = K<sub><i>i</i></sub> / q<sub>adsorpt,sat,<i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the initial guess of the reduced pressure of each component <i>i</i>: + <pre>η<sub><i>i</i></sub> = <strong>min</strong>(Kp<sub><i>i</i></sub> / K<sub><i>i</i></sub> * p<sub>adsorpt</sub> * K<sub>avg</sub>, Kp<sub><i>i</i></sub> * p<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the last row of the Jacobian matrix for each column <i>i</i>: + <pre>Jac<sub>last row,<i>i</i></sub> = Kp<sub><i>i</i></sub> * p<sub>adsorpt</sub> * y<sub><i>i</i></sub> / η<sup>2</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = η<sub><i>i</i></sub> / Kp<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the diagonal of the Jacobian matrix for each component <i>i</i>: + <pre>Jac<sub>diagonal,<i>i</i></sub> = 1 / (M<sub><i>i</i></sub> * η<sub><i>i</i></sub>) * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Correct the last element of the diagonal of the Jacobian matrix: + <pre>Jac<sub>diagonal,last</sub> = Jac<sub>last row,last</sub> + Jac<sub>diagonal,last</sub> * ∑<sub><i>i</i></sub><sup>N-1</sup> [Jac<sub>last row,<i>i</i></sub> / Jac<sub>diagonal,<i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressures of each component <i>i</i>: + <pre>π<sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the differences between the reduced spreading pressure of each + component <i>i</i> and the reduced spreading pressure of the last component: + <pre>Δπ<sub><i>i</i></sub> = π<sub><i>i</i></sub> - π<sub>last</sub>.</pre> + <br> + </li> + <li> + Correct the last element of the differences between the reduced spreading pressure + of each component <i>i</i> and the reduced spreading pressure of the last component: + <pre>Δπ<sub>last</sub> =1 - ∑<sub><i>i</i></sub> [Kp<sub><i>i</i></sub> * p<sub>adsorpt</sub> * y<sub><i>i</i></sub> / η<sub><i>i</i></sub>] - ∑<sub><i>i</i></sub><sup>N-1</sup> [Jac<sub>last row,<i>i</i></sub> / Jac<sub>diagonal,<i>i</i></sub> * Δπ<sub><i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the change of the reduced pressure of the last component: + <pre>Δη<sub>last</sub> = Δπ<sub>last</sub> / Jac<sub>diagonal,last</sub>.</pre> + <br> + </li> + <li> + Calculate the change of the reduced pressure of the remaining components <i>i</i>: + <pre>Δη<sub><i>i</i></sub> = (-Δπ<sub><i>i</i></sub> + Jac<sub>diagonal,last</sub> * Δη<sub>last</sub>) / Jac<sub>diagonal,<i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the reduced pressure of the next iteration step of each component <i>i</i>: + <pre>η<sub>next,<i>i</i></sub> = <strong>if</strong> η<sub><i>i</i></sub> + Δη<sub><i>i</i></sub> > 0 <strong>then</strong> η<sub><i>i</i></sub> + Δη<sub><i>i</i></sub> <strong>else</strong> η<sub><i>i</i></sub>/2.</pre> + <br> + </li> + <li> + Check for convergence: + <pre>∑ |Δη<sub><i>i</i></sub>| ≤ tolerance.</pre> + If the convergence criterion is not fulfilled, got to step 6. It the convergence + criterion is fulfilled, got to step 17. + <br> + </li> + <li> + Calculate the molar composition of each component <i>i</i> in the adsorpt + phase: + <pre>z<sub><i>i</i></sub> = y<sub><i>i</i></sub> * p<sub>adsorpt</sub> / p<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the molar uptake of each component <i>i</i>: + <pre>q<sub>adsorpt,<i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the total molar uptake: + <pre>q<sub>adsorpt,total</sub> = 1 / ∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> / q<sub>adsorpt,<i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the uptakes of each component <i>i</i>: + <pre>x<sub>adsorpt,<i>i</i></sub> = M<sub><i>i</i></sub> * z<sub><i>i</i></sub> * q<sub>adsorpt,total</sub>.</pre> + </li> +</ol> + +<h4>References</h4> +<ul> + <li> + Mangano E., Friedrich, D., and Brandani, S. (2015). Robust algorithms for the solution of the ideal adsorbed solution theory equations. AIChE Journal, 61(3): 981–991. DOI: 10.1002/aic.14684. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_pyT_FastIAST; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/x_pyT_NestedLoop.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/x_pyT_NestedLoop.mo new file mode 100644 index 0000000000000000000000000000000000000000..d10f163c693723cce336596affeb07fcf9dd2d86 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/x_pyT_NestedLoop.mo @@ -0,0 +1,457 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals; +function x_pyT_NestedLoop + "IAST for three components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature using the 'Nested Loop' algorithm" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[:] y_i + "Mole fractions of the components in the gas or vapor phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + input Boolean flag_startValues = false + " = true, if start values are given; otherwise, estimate start values" + annotation (Dialog(tab="General", group="Inputs - Start values")); + input Modelica.Units.SI.Pressure[size(M_i,1)] p_i_pure_0= + fill(1, size(M_i,1)) + "Hypothetical pure component pressures" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + input SorpLib.Units.ReducedSpreadingPressure pi_0 = 1 + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.Pressure[size(M_i,1)] p_i_pure + "Hypothetical pure component pressures" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.ReducedSpreadingPressure pi + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real[size(M_i,1)] K_i(each unit="mol/(kg.Pa)") + "Henry constants of the components"; + Real K_avg(unit="mol/(kg.Pa)") + "Average Henry constant"; + + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] pi_i + "Reduced spreading pressures"; + + Integer no_inner = 1 + "Counter of inner loop"; + Integer no_outer = 1 + "Counter of outer loop"; + + SorpLib.Units.ReducedSpreadingPressure error_inner = 1 + "Error of inner loop"; + Modelica.Units.SI.MoleFraction error_outer = 1 + "Error of outer loop"; + + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] delta_pi_i + "Difference between reduced spreading pressures and reduced spreading pressure + of all components"; + Real[size(M_i,1)] ddelta_pi_i_dp_i_pure(each unit="mol/(kg.Pa)") + "Partial derivative of difference between reduced spreading pressures and + reduced spreading pressure of all components w.r.t. the hypothetical pure + component pressures"; + + Modelica.Units.SI.MoleFraction[size(M_i,1)] z_i + "Mole fractions of the adsorpt phase"; + + SorpLib.Units.MolarUptake[size(M_i,1)] q_adsorpt_i + "Molar equilibrium uptakes at hypothetical pure component pressures"; + SorpLib.Units.MolarUptake q_adsorpt + "Total molar equilibrium uptake"; + +algorithm + if flag_startValues then + // + // Use start values + // + p_i_pure := p_i_pure_0 + "Hypothetical pure component pressures"; + pi := pi_0 + "Reduced spreading pressure of all components"; + + else + // + // Caclulate initial guesses ensuring convergence: Henry constants + // + K_i[1] := 1/M_i[1] * func_dx_dp_1(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_1) + "Henry constant of the first component"; + K_i[2] := 1/M_i[2] * func_dx_dp_2(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_2) + "Henry constant of the second component"; + K_i[3] := 1/M_i[3] * func_dx_dp_3(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_3) + "Henry constant of the third component"; + + K_avg := sum(y_i .* K_i) + "Average Henry constant"; + + // + // Caclulate initial guesses ensuring convergence: Reduced spreading pressures + // and hypothetical pure component pressures + // + p_i_pure := p_adsorpt .* K_avg ./ K_i + "Hypothetical pure component pressures"; + + pi_i[1] := func_pi_pT_1(M_adsorptive=M_i[1], + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance=num_comp_1.tolerance_pi) + "Reduced spreading pressure of the first component"; + pi_i[2] := func_pi_pT_2(M_adsorptive=M_i[2], + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance=num_comp_2.tolerance_pi) + "Reduced spreading pressure of the second component"; + pi_i[3] := func_pi_pT_3(M_adsorptive=M_i[3], + p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + integral_pi_lb=num_comp_3.integral_pi_lb, + tolerance=num_comp_3.tolerance_pi) + "Reduced spreading pressure of the third component"; + + pi := min(pi_i) + "Reduced spreading pressure of all components"; + p_i_pure := pi ./ K_i + "Hypothetical pure component pressures"; + + end if; + + // + // Outer loop: Ensure mass conservation + // + while error_outer >= num.tolerance_outer and no_outer <= num.no_max_outer loop + // + // Inner loop: Ensure identical spreading pressures + // + no_inner :=1 + "Counter of inner loop"; + error_inner :=1 + "Error of inner loop"; + + while error_inner >= num.tolerance_inner and no_inner <= num.no_max_inner loop + // + // Calculate reduced spreading pressures + // + pi_i[1] := func_pi_pT_1(M_adsorptive=M_i[1], + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance=num_comp_1.tolerance_pi) + "Reduced spreading pressure of the first component"; + pi_i[2] := func_pi_pT_2(M_adsorptive=M_i[2], + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance=num_comp_2.tolerance_pi) + "Reduced spreading pressure of the second component"; + pi_i[3] := func_pi_pT_3(M_adsorptive=M_i[3], + p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + integral_pi_lb=num_comp_3.integral_pi_lb, + tolerance=num_comp_3.tolerance_pi) + "Reduced spreading pressure of the third component"; + + // + // Apply Newton-Raphson method + // + delta_pi_i := pi_i .- pi + "Difference betwenn reduced spreading pressures and reduced spreading pressure + of all components"; + + ddelta_pi_i_dp_i_pure[1] := 1/M_i[1] * func_x_pT_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) / p_i_pure[1] + "Partial derivative of difference between reduced spreading pressure of the + first component and reduced spreading pressure of all components w.r.t. the + hypothetical pure component pressure of the first component"; + ddelta_pi_i_dp_i_pure[2] := 1/M_i[2] * func_x_pT_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) / p_i_pure[2] + "Partial derivative of difference between reduced spreading pressure of the + second component and reduced spreading pressure of all components w.r.t. the + hypothetical pure component pressure of the second component"; + ddelta_pi_i_dp_i_pure[3] := 1/M_i[3] * func_x_pT_3(p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + p_adsorpt_lb_start=num_comp_3.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_3.p_adsorpt_ub_start, + tolerance=num_comp_3.tolerance_p_adsorpt) / p_i_pure[3] + "Partial derivative of difference between reduced spreading pressure of the + third component and reduced spreading pressure of all components w.r.t. the + hypothetical pure component pressure of the third component"; + + p_i_pure := p_i_pure .- delta_pi_i ./ ddelta_pi_i_dp_i_pure + "Hypothetical pure component pressures"; + + // + // Check for convergence + // + no_inner := no_inner + 1 + "Counter of inner loop"; + error_inner := sum(abs(delta_pi_i)) + "Error of inner loop"; + + end while; + + // + // Calculate mole fractions of adsorpt phase + // + z_i := y_i .* p_adsorpt ./ p_i_pure + "Mole fractions of the adsorpt phase"; + + // + // Calculate equilibrium uptakes + // + q_adsorpt_i[1] := 1/M_i[1] * func_x_pT_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure compoment pressure of the + first component"; + q_adsorpt_i[2] := 1/M_i[2] * func_x_pT_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure compoment pressure of the + second component"; + q_adsorpt_i[3] := 1/M_i[3] * func_x_pT_3(p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + p_adsorpt_lb_start=num_comp_3.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_3.p_adsorpt_ub_start, + tolerance=num_comp_3.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure compoment pressure of the + third component"; + + q_adsorpt := 1 / sum(z_i ./ q_adsorpt_i) + "Total molar equilibrium uptake"; + + // + // Apply Newton-Raphson method + // + pi := pi + (-(1 - sum(z_i)) / (1/q_adsorpt)) + "Reduced spreading pressure of all components"; + + // + // Check for convergence + // + no_outer := no_outer + 1 + "Counter of outer loop"; + error_outer := abs(1 - sum(z_i)) + "Error of outer loop"; + + end while; + + // + // Calculate final ouputs + // + x_adsorpt := q_adsorpt .* z_i .* M_i + "Equilibrium uptakes of the adsorpt phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function provides an algorithm for solving the IAST for three components. The +uptakes <i>x_adsorpt</i> are calculated as a function of the pressure <i>p_adsorpt</i>, +the molar composition of the gas/vapour phase <i>y_i</i>, and the temperature +<i>T_adsorpt</i>. The algorithm uses two loops, with the inner loop nested in the +outer loop. Hence, the algorithm is called 'Nested Loop.' The inner loop iterates +over the reduced spreading pressure <i>π</i>, while the outer loop iterates over +the molar composition of the adsorpt phase <i>z<sub><I>i</i></sub></i>. +</p> + +<h4>Main equations</h4> +<p> +The algorithm consists of 17 steps: +</p> +<ol> + <li> + Calculate the Henry's constant of each component <i>i</i>: + <pre>K<sub><i>i</i></sub> = 1 / M<sub><i>i</i></sub> * dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub>,</pre> + where <i>M<sub><i>i</i></sub></i> is the molar mass and <i>dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub></i> + is the partial derivative of the uptake with respect to the pressure. + <br> + </li> + <li> + Calculate the average Henry's constant: + <pre>K<sub>avg</sub> = ∑<sub><i>i</i></sub> y<sub><i>i</i></sub> * K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = p<sub>adsorpt</sub> * K<sub>avg</sub> / K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressures of each component <i>i</i>: + <pre>π<sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the initial guess of the reduced spreading pressure: + <pre>π = <strong>min</strong>(π<sub><i>i</i></sub>).</pre> + <br> + </li> + <li> + Calculate the initial guesses of the hypothetical pure component pressures of each + component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = π / K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressures of each component <i>i</i>: + <pre>π<sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the differences between the reduced spreading pressure of each + component <i>i</i> and the reduced spreading pressure of the last component: + <pre>Δπ<sub><i>i</i></sub> = π<sub><i>i</i></sub> - π<sub>last</sub>.</pre> + <br> + </li> + <li> + Calculate the partial derivatives of the differences between the reduced + spreading pressure of each component <i>i</i> and the reduced spreading + pressure of the last component with respect to the hypothetical pure + component pressures: + <pre>dΔπ<sub><i>i</i></sub>/dp<sup>*</sup><sub><i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>) / p<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component + <i>i</i> of the next iteration step: + <pre>p<sup>*</sup><sub>next,<i>i</i></sub> = p<sup>*</sup><sub><i>i</i></sub> - Δπ<sub><i>i</i></sub> / dΔπ<sub><i>i</i></sub>/dp<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Check for convergence of the inner loop: + <pre>∑<sub><i>i</i></sub> |Δπ<sub><i>i</i></sub>| ≤ tolerance.</pre> + If the convergence criterion is not fulfilled, got to step 7. It the convergence + criterion is fulfilled, got to step 12. + <br> + </li> + <li> + Calculate the molar composition of each component <i>i</i> in the adsorpt + phase: + <pre>z<sub><i>i</i></sub> = y<sub><i>i</i></sub> * p<sub>adsorpt</sub> / p<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the molar uptake of each component <i>i</i>: + <pre>q<sub>adsorpt,<i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the total molar uptake: + <pre>q<sub>adsorpt,total</sub> = 1 / ∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> / q<sub>adsorpt,<i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressure of the next iteration step: + <pre>π<sub>next</sub> = π - (1 - ∑ z<sub><i>i</i></sub>) / (1 / q<sub>adsorpt,total</sub>).</pre> + <br> + </li> + <li> + Check for convergence of the outer loop: + <pre>|1 - ∑<sub><i>i</i></sub> z<sub><i>i</i></sub>| ≤ tolerance.</pre> + If the convergence criterion is not fulfilled, got to step 7. It the convergence + criterion is fulfilled, got to step 17. + <br> + </li> + <li> + Calculate the uptakes of each component <i>i</i>: + <pre>x<sub>adsorpt,<i>i</i></sub> = M<sub><i>i</i></sub> * z<sub><i>i</i></sub> * q<sub>adsorpt,total</sub>.</pre> + </li> +</ol> + +<h4>References</h4> +<ul> + <li> + Mangano E., Friedrich, D., and Brandani, S. (2015). Robust algorithms for the solution of the ideal adsorbed solution theory equations. AIChE Journal, 61(3): 981–991. DOI: 10.1002/aic.14684. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_pyT_NestedLoop; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/x_pyT_NewtonRaphson.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/x_pyT_NewtonRaphson.mo new file mode 100644 index 0000000000000000000000000000000000000000..c9486456e7d20d78567bda5f2a9295090dd200f2 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/Internals/x_pyT_NewtonRaphson.mo @@ -0,0 +1,385 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals; +function x_pyT_NewtonRaphson + "IAST for two components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature using the standard 'Newton-Raphson' algorithm" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMultiIAST; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MoleFraction[:] y_i + "Mole fractions of the components in the gas or vapor phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + input Boolean flag_startValues = false + " = true, if start values are given; otherwise, estimate start values" + annotation (Dialog(tab="General", group="Inputs - Start values")); + input SorpLib.Units.ReducedSpreadingPressure pi_0 = 1 + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Inputs - Start values", + enable=flag_startValues)); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.Pressure[size(M_i,1)] p_i_pure + "Hypothetical pure component pressures" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.ReducedSpreadingPressure pi + "Reduced spreading pressure of all components" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real[size(M_i,1)] K_i(each unit="mol/(kg.Pa)") + "Henry constants of the components"; + Real K_avg(unit="mol/(kg.Pa)") + "Average Henry constant"; + + SorpLib.Units.ReducedSpreadingPressure[size(M_i,1)] pi_i + "Reduced spreading pressures"; + + Integer no_iteration = 1 + "Counter of loop"; + Real error = 1 + "Error of loop"; + + SorpLib.Units.MolarUptake[size(M_i,1)] q_adsorpt_i + "Molar equilibrium uptakes at hypothetical pure component pressures"; + + Modelica.Units.SI.MoleFraction delta_sum_z_i + "Satisfaction of molar composition of adsorpt phase"; + Real ddelta_sum_z_i_dpi(unit="kg/mol") + "Partial derivative of satisfaction of molar composition of adsorpt phase + w.r.t. to reduced spreading pressure of all components"; + + Modelica.Units.SI.MoleFraction[size(M_i,1)] z_i + "Mole fractions of the adsorpt phase"; + + SorpLib.Units.MolarUptake q_adsorpt + "Total molar equilibrium uptake"; + +algorithm + if flag_startValues then + // + // Use start values + // + pi := pi_0 + "Reduced spreading pressure of all components"; + + else + // + // Caclulate initial guesses ensuring convergence: Henry constants + // + K_i[1] := 1/M_i[1] * func_dx_dp_1(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_1) + "Henry constant of the first component"; + K_i[2] := 1/M_i[2] * func_dx_dp_2(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_2) + "Henry constant of the second component"; + K_i[3] := 1/M_i[3] * func_dx_dp_3(p_adsorpt=num.p_K_0, + T_adsorpt=T_adsorpt, + c=c_3) + "Henry constant of the third component"; + + K_avg := sum(y_i .* K_i) + "Average Henry constant"; + + // + // Caclulate initial guesses ensuring convergence: Reduced spreading pressures + // and hypothetical pure component pressures + // + p_i_pure := p_adsorpt .* K_avg ./ K_i + "Hypothetical pure component pressures"; + + pi_i[1] := func_pi_pT_1(M_adsorptive=M_i[1], + p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance=num_comp_1.tolerance_pi) + "Reduced spreading pressure of the first component"; + pi_i[2] := func_pi_pT_2(M_adsorptive=M_i[2], + p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance=num_comp_2.tolerance_pi) + "Reduced spreading pressure of the second component"; + pi_i[3] := func_pi_pT_3(M_adsorptive=M_i[3], + p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + integral_pi_lb=num_comp_3.integral_pi_lb, + tolerance=num_comp_3.tolerance_pi) + "Reduced spreading pressure of the third component"; + + pi := min(pi_i) + "Reduced spreading pressure of all components"; + + end if; + + // + // Loop to solve the IAST + // + while error >= num.tolerance and no_iteration <= num.no_max loop + // + // Calculate hypothetical pure component pressures + // + p_i_pure[1] := func_p_piT_1( + M_adsorptive=M_i[1], + pi=pi, + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + integral_pi_lb=num_comp_1.integral_pi_lb, + tolerance_p_adsorpt=num_comp_1.tolerance_p_adsorpt, + tolerance_pi=num_comp_1.tolerance_pi) + "Hypothetical pure component pressure of the first component"; + p_i_pure[2] := func_p_piT_2( + M_adsorptive=M_i[2], + pi=pi, + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + integral_pi_lb=num_comp_2.integral_pi_lb, + tolerance_p_adsorpt=num_comp_2.tolerance_p_adsorpt, + tolerance_pi=num_comp_2.tolerance_pi) + "Hypothetical pure component pressure of the first component"; + p_i_pure[3] := func_p_piT_3( + M_adsorptive=M_i[3], + pi=pi, + T_adsorpt=T_adsorpt, + c=c_3, + p_adsorpt_lb_start=num_comp_3.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_3.p_adsorpt_ub_start, + integral_pi_lb=num_comp_3.integral_pi_lb, + tolerance_p_adsorpt=num_comp_3.tolerance_p_adsorpt, + tolerance_pi=num_comp_3.tolerance_pi) + "Hypothetical pure component pressure of the third component"; + + // + // Calculate molar uptakes + // + q_adsorpt_i[1] := 1/M_i[1] * func_x_pT_1(p_adsorpt=p_i_pure[1], + T_adsorpt=T_adsorpt, + c=c_1, + p_adsorpt_lb_start=num_comp_1.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_1.p_adsorpt_ub_start, + tolerance=num_comp_1.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + first component"; + q_adsorpt_i[2] := 1/M_i[2] * func_x_pT_2(p_adsorpt=p_i_pure[2], + T_adsorpt=T_adsorpt, + c=c_2, + p_adsorpt_lb_start=num_comp_2.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_2.p_adsorpt_ub_start, + tolerance=num_comp_2.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + second component"; + q_adsorpt_i[3] := 1/M_i[3] * func_x_pT_3(p_adsorpt=p_i_pure[3], + T_adsorpt=T_adsorpt, + c=c_3, + p_adsorpt_lb_start=num_comp_3.p_adsorpt_lb_start, + p_adsorpt_ub_start=num_comp_3.p_adsorpt_ub_start, + tolerance=num_comp_3.tolerance_p_adsorpt) + "Molar equilibrium uptake at hypothetical pure component pressure of the + third component"; + + // + // Apply Newton-Raphson method + // + delta_sum_z_i := sum((p_adsorpt .* y_i) ./ p_i_pure) - 1 + "Satisfaction of molar composition of adsorpt phase"; + ddelta_sum_z_i_dpi := -sum((p_adsorpt .* y_i) ./ (p_i_pure .* q_adsorpt_i)) + "Partial derivative of satisfaction of molar composition of adsorpt phase + w.r.t. to reduced spreading pressure of all components"; + + pi := if pi - delta_sum_z_i / ddelta_sum_z_i_dpi > 0 then + pi - delta_sum_z_i / ddelta_sum_z_i_dpi else pi / 2 + "Update reduced spreading pressure of all components"; + + // + // Check for convergence + // + no_iteration := no_iteration + 1 + "Counter of loop"; + error := abs(delta_sum_z_i) + "Error of loop"; + + end while; + + // + // Calculate mole fractions of adsorpt phase + // + z_i := y_i .* p_adsorpt ./ p_i_pure + "Mole fractions of the adsorpt phase"; + + // + // Calculate equilibrium uptake + // + q_adsorpt := 1 / sum(z_i ./ q_adsorpt_i) + "Total molar equilibrium uptake"; + + // + // Calculate final ouputs + // + x_adsorpt := q_adsorpt .* z_i .* M_i + "Equilibrium uptakes of the adsorpt phase"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function provides an algorithm for solving the IAST for three components. The +uptakes <i>x_adsorpt</i> are calculated as a function of the pressure <i>p_adsorpt</i>, +the molar composition of the gas/vapour phase <i>y_i</i>, and the temperature +<i>T_adsorpt</i>. The algorithm uses a Newton-Raphson method to solve the system +of equations of the IAST. +</p> + +<h4>Main equations</h4> +<p> +The algorithm consists of 14 steps: +</p> +<ol> + <li> + Calculate the Henry's constant of each component <i>i</i>: + <pre>K<sub><i>i</i></sub> = 1 / M<sub><i>i</i></sub> * dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub>,</pre> + where <i>M<sub><i>i</i></sub></i> is the molar mass and <i>dx<sub><i>i</i></sub>/dp<sub><i>i</i></sub></i> + is the partial derivative of the uptake with respect to the pressure. + <br> + </li> + <li> + Calculate the average Henry's constant: + <pre>K<sub>avg</sub> = ∑<sub><i>i</i></sub> y<sub><i>i</i></sub> * K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = p<sub>adsorpt</sub> * K<sub>avg</sub> / K<sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressures of each component <i>i</i>: + <pre>π<sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the initial guess of the reduced spreading pressure: + <pre>π = <strong>min</strong>(π<sub><i>i</i></sub>).</pre> + <br> + </li> + <li> + Calculate the hypothetical pure component pressures of each component <i>i</i>: + <pre>p<sup>*</sup><sub><i>i</i></sub> = f(M<sub><i>i</i></sub>, π, T<sub>adsorpt</sub>).</pre> + This formula is an inverse of the reduced spreading pressure, which often + has to be calculated numerically. + <br> + </li> + <li> + Calculate the molar uptake of each component <i>i</i>: + <pre>q<sub>adsorpt,<i>i</i></sub> = 1 / M<sub><i>i</i></sub> * x<sub>adsorpt,<i>i</i></sub>(p<sup>*</sup><sub><i>i</i></sub>, T<sub>adsorpt</sub>).</pre> + <br> + </li> + <li> + Calculate the satisfaction of the molar composition of the adsorpt phase: + <pre>F = ∑<sub><i>i</i></sub> [y<sub><i>i</i></sub> * x<sub>adsorpt</sub> / p<sup>*</sup><sub><i>i</i></sub>] - 1.</pre> + <br> + </li> + <li> + Calculate the partial derivative of the satisfaction of the adsorpt phase + with respect to the reduced spreading pressure: + <pre>dF/dπ = -∑<sub><i>i</i></sub> [y<sub><i>i</i></sub> * p<sub>adsorpt</sub> / (p<sup>*</sup><sub><i>i</i></sub> * q<sub>adsorpt,<i>i</i></sub>)].</pre> + <br> + </li> + <li> + Calculate the reduced spreading pressure of the next iteration step: + <pre>π<sub>next</sub> = <strong>if</strong> π - F / dF/dπ > 0 <strong>then</strong> π - F / dF/dπ > 0 <strong>else</strong> π/2.</pre> + <br> + </li> + <li> + Check for convergence: + <pre>|F| ≤ tolerance.</pre> + If the convergence criterion is not fulfilled, got to step 6. It the convergence + criterion is fulfilled, got to step 12. + <br> + </li> + <li> + Calculate the molar composition of each component <i>i</i> in the adsorpt + phase: + <pre>z<sub><i>i</i></sub> = y<sub><i>i</i></sub> * p<sub>adsorpt</sub> / p<sup>*</sup><sub><i>i</i></sub>.</pre> + <br> + </li> + <li> + Calculate the total molar uptake: + <pre>q<sub>adsorpt,total</sub> = 1 / ∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> / q<sub>adsorpt,<i>i</i></sub>].</pre> + <br> + </li> + <li> + Calculate the uptakes of each component <i>i</i>: + <pre>x<sub>adsorpt,<i>i</i></sub> = M<sub><i>i</i></sub> * z<sub><i>i</i></sub> * q<sub>adsorpt,total</sub>.</pre> + </li> +</ol> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_pyT_NewtonRaphson; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..7e7810017910ffb4eaabd56ad644b899528619aa --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/package.mo @@ -0,0 +1,1282 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents; +package IAST_N3 "Package containing all functions regarding the IAST for three components" + extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponentsIAST; + + // + // Internal package + // + redeclare final function extends x_pyT + "IAST for three components: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + + // + // Definition of inputs + // + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + + algorithm + // + // Select IAST algorithm + // + if num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NewtonRaphson then + (x_adsorpt,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Standard 'Newton-Raphson' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop then + (x_adsorpt,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'Nested Loop' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST then + (x_adsorpt,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'FASTIast' algorithm"; + + end if; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, M_i=M_i, c_1=c_1, c_2=c_2, c_3=c_3, func_x_pT_1=func_x_pT_1, func_p_xT_1=func_p_xT_1, func_dx_dp_1=func_dx_dp_1, func_pi_pT_1=func_pi_pT_1, func_p_piT_1=func_p_piT_1, func_x_pT_2=func_x_pT_2, func_p_xT_2=func_p_xT_2, func_dx_dp_2=func_dx_dp_2, func_pi_pT_2=func_pi_pT_2, func_p_piT_2=func_p_piT_2, func_x_pT_3=func_x_pT_3, func_p_xT_3=func_p_xT_3, func_dx_dp_3=func_dx_dp_3, func_pi_pT_3=func_pi_pT_3, func_p_piT_3=func_p_piT_3, num=num, num_comp_1=num_comp_1, num_comp_2=num_comp_2, num_comp_3=num_comp_3), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, M_i=M_i, c_1=c_1, c_2=c_2, c_3=c_3, func_x_pT_1=func_x_pT_1, func_p_xT_1=func_p_xT_1, func_dx_dp_1=func_dx_dp_1, func_pi_pT_1=func_pi_pT_1, func_p_piT_1=func_p_piT_1, func_x_pT_2=func_x_pT_2, func_p_xT_2=func_p_xT_2, func_dx_dp_2=func_dx_dp_2, func_pi_pT_2=func_pi_pT_2, func_p_piT_2=func_p_piT_2, func_x_pT_3=func_x_pT_3, func_p_xT_3=func_p_xT_3, func_dx_dp_3=func_dx_dp_3, func_pi_pT_3=func_pi_pT_3, func_p_piT_3=func_p_piT_3, num=num, num_comp_1=num_comp_1, num_comp_2=num_comp_2, num_comp_3=num_comp_3))); + end x_pyT; + + redeclare final function extends p_xyT + "IAST for three components: Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + + // + // Definition of inputs + // + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ = cat(1, y_i, {1-sum(y_i)}) + "Mole fractions of all components in the vapor or gas phase"; + + algorithm + (p_adsorpt,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.py_xT_NewtonRaphson( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Standard 'Newton-Raphson' algorithm"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, M_i=M_i, c_1=c_1, c_2=c_2, c_3=c_3, func_x_pT_1=func_x_pT_1, func_p_xT_1=func_p_xT_1, func_dx_dp_1=func_dx_dp_1, func_pi_pT_1=func_pi_pT_1, func_p_piT_1=func_p_piT_1, func_x_pT_2=func_x_pT_2, func_p_xT_2=func_p_xT_2, func_dx_dp_2=func_dx_dp_2, func_pi_pT_2=func_pi_pT_2, func_p_piT_2=func_p_piT_2, func_x_pT_3=func_x_pT_3, func_p_xT_3=func_p_xT_3, func_dx_dp_3=func_dx_dp_3, func_pi_pT_3=func_pi_pT_3, func_p_piT_3=func_p_piT_3, num=num, num_comp_1=num_comp_1, num_comp_2=num_comp_2, num_comp_3=num_comp_3), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, M_i=M_i, c_1=c_1, c_2=c_2, c_3=c_3, func_x_pT_1=func_x_pT_1, func_p_xT_1=func_p_xT_1, func_dx_dp_1=func_dx_dp_1, func_pi_pT_1=func_pi_pT_1, func_p_piT_1=func_p_piT_1, func_x_pT_2=func_x_pT_2, func_p_xT_2=func_p_xT_2, func_dx_dp_2=func_dx_dp_2, func_pi_pT_2=func_pi_pT_2, func_p_piT_2=func_p_piT_2, func_x_pT_3=func_x_pT_3, func_p_xT_3=func_p_xT_3, func_dx_dp_3=func_dx_dp_3, func_pi_pT_3=func_pi_pT_3, func_p_piT_3=func_p_piT_3, num=num, num_comp_1=num_comp_1, num_comp_2=num_comp_2, num_comp_3=num_comp_3))); + end p_xyT; + + redeclare final function extends y_pxT + "IAST for three components: Mole fractions of independent gas phase components as function of uptakes, pressure, and temperature" + + // + // Definition of inputs + // + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ + "Mole fractions of all components in the vapor or gas phase"; + + algorithm + // + // Solve inverse of IAST + // + (,y_i_,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.py_xT_NewtonRaphson( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Standard 'Newton-Raphson' algorithm"; + + // + // Assign correct output values + // + y_i := y_i_[1:end-1] + "Mole fractions of independent components in the gas or vapor phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end y_pxT; + + redeclare final function extends py_xT + "IAST for three components: Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + + // + // Definition of inputs + // + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[size(M_i,1)] y_i_ + "Mole fractions of all components in the vapor or gas phase"; + + algorithm + // + // Solve inverse of IAST + // + (p_adsorpt,y_i_,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.py_xT_NewtonRaphson( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Standard 'Newton-Raphson' algorithm"; + + // + // Assign correct output values + // + y_i := y_i_[1:end-1] + "Mole fractions of independent components in the gas or vapor phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + redeclare final function extends dx_dp + "IAST for three components: Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature (numerical solution)" + + // + // Definition of inputs + // + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_pdp + "Equilibrium uptakes of the adsorpt phase: p + dp"; + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_mdp + "Equilibrium uptakes of the adsorpt phase: p - dp"; + + algorithm + // + // Select IAST algorithm + // + if num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NewtonRaphson then + (x_adsorpt_pdp,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt + dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Standard 'Newton-Raphson' algorithm"; + + (x_adsorpt_mdp,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt - dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Standard 'Newton-Raphson' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop then + (x_adsorpt_pdp,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt + dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'Nested Loop' algorithm"; + + (x_adsorpt_mdp,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt - dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'Nested Loop' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST then + (x_adsorpt_pdp,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt + dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'FASTIast' algorithm"; + + (x_adsorpt_mdp,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt - dp, + y_i=y_i_, + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'FASTIast' algorithm"; + + end if; + + // + // Calculate derivatives of loadings w.r.t. equilibrium pressure + // + dx_adsorpt_dp_adsorpt := (x_adsorpt_pdp .- x_adsorpt_mdp) ./ (2*dp) + "Calculation of the partial derivatives of the equilibrium uptakes w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + end dx_dp; + + redeclare final function extends dx_dy + "IAST for three components: Partial derivative of uptakes w.r.t. mole fractions of independent gas phase components at constant pressure and temperature (numerical solution)" + + // + // Definition of inputs + // + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_pdy + "Equilibrium uptakes of the adsorpt phase: y + dy"; + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_mdy + "Equilibrium uptakes of the adsorpt phase: y - dy"; + + algorithm + for ind_y_i in 1:size(M_i,1)-1 loop + // + // Select IAST algorithm + // + if num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NewtonRaphson then + (x_adsorpt_pdy,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt, + y_i=cat( + 1, + y_i_[1:ind_y_i - 1], + {y_i_[ind_y_i] + dy}, + y_i_[ind_y_i + 1:size(M_i, 1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Standard 'Newton-Raphson' algorithm"; + + (x_adsorpt_mdy,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt, + y_i=cat( + 1, + y_i_[1:ind_y_i - 1], + {y_i_[ind_y_i] - dy}, + y_i_[ind_y_i + 1:size(M_i, 1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Standard 'Newton-Raphson' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop then + (x_adsorpt_pdy,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=cat( + 1, + y_i_[1:ind_y_i - 1], + {y_i_[ind_y_i] + dy}, + y_i_[ind_y_i + 1:size(M_i, 1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'Nested Loop' algorithm"; + + (x_adsorpt_mdy,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=cat( + 1, + y_i_[1:ind_y_i - 1], + {y_i_[ind_y_i] - dy}, + y_i_[ind_y_i + 1:size(M_i, 1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'Nested Loop' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST then + (x_adsorpt_pdy,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt, + y_i=cat( + 1, + y_i_[1:ind_y_i - 1], + {y_i_[ind_y_i] + dy}, + y_i_[ind_y_i + 1:size(M_i, 1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'FASTIast' algorithm"; + + (x_adsorpt_mdy,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt, + y_i=cat( + 1, + y_i_[1:ind_y_i - 1], + {y_i_[ind_y_i] - dy}, + y_i_[ind_y_i + 1:size(M_i, 1)]), + T_adsorpt=T_adsorpt, + M_i=M_i, + c_1=c_1, + c_2=c_2, + c_3=c_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'FASTIast' algorithm"; + + end if; + + // + // Calculate partial darivatives for each independent mole fraction + // + dx_adsorpt_dy_i[:,ind_y_i] := (x_adsorpt_pdy .- x_adsorpt_mdy) ./ (2*dy) + "Partial derivatives of the uptakes w.r.t. the mole fractions of independent + gas phase components at constant pressure and temperature"; + end for; + end dx_dy; + + redeclare final function extends dx_dT + "IAST for three components: Partial derivative of uptakes w.r.t. temperature at constant pressure and mole fractions (numerical solution)" + + // + // Definition of inputs + // + input Real[:] c_3 + "Coefficients of the isotherm model of the third component" + annotation (Dialog(tab="General", group="Inputs - Components")); + input Real[size(c_2,1)] c_pdT_3 + "Coefficients of the isotherm model of the third component: T + dT" + annotation (Dialog(tab="General", group="Inputs - Components")); + input Real[size(c_2,1)] c_mdT_3 + "Coefficients of the isotherm model of the third component: T - dT" + annotation (Dialog(tab="General", group="Inputs - Components")); + + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT func_x_pT_3 + "Uptake of the third component as function of pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT_3 + "Pressure of the third component as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp_3 + "Partial derivative of the uptake of the third component w.r.t. the equilibrium + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT func_pi_pT_3 + "Reduced spreading pressure of the third component as function of pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT func_p_piT_3 + "Pressure of the third component as function of reduced spreading pressure + and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.Records.NumericsIAST_PureComponents num_comp_3 + "Record definining numerics of the third component's isotherm model" + annotation (Dialog(tab="General", group="Inputs - Numerics"), + choicesAllMatching=true); + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_pdT + "Equilibrium uptakes of the adsorpt phase: T + dT"; + SorpLib.Units.Uptake[size(M_i,1)] x_adsorpt_mdT + "Equilibrium uptakes of the adsorpt phase: T - dT"; + + algorithm + // + // Select IAST algorithm + // + if num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NewtonRaphson then + (x_adsorpt_pdT,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt + dT, + M_i=M_i, + c_1=c_pdT_1, + c_2=c_pdT_2, + c_3=c_pdT_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Standard 'Newton-Raphson' algorithm"; + + (x_adsorpt_mdT,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NewtonRaphson( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt - dT, + M_i=M_i, + c_1=c_mdT_1, + c_2=c_mdT_2, + c_3=c_mdT_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "Standard 'Newton-Raphson' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop then + (x_adsorpt_pdT,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt + dT, + M_i=M_i, + c_1=c_pdT_1, + c_2=c_pdT_2, + c_3=c_pdT_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'Nested Loop' algorithm"; + + (x_adsorpt_mdT,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_NestedLoop( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt - dT, + M_i=M_i, + c_1=c_mdT_1, + c_2=c_mdT_2, + c_3=c_mdT_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'Nested Loop' algorithm"; + + elseif num.IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST then + (x_adsorpt_pdT,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt + dT, + M_i=M_i, + c_1=c_pdT_1, + c_2=c_pdT_2, + c_3=c_pdT_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'FASTIast' algorithm"; + + (x_adsorpt_mdT,,,,) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.IAST_N3.Internals.x_pyT_FastIAST( + p_adsorpt=p_adsorpt, + y_i=y_i_, + T_adsorpt=T_adsorpt - dT, + M_i=M_i, + c_1=c_mdT_1, + c_2=c_mdT_2, + c_3=c_mdT_3, + func_x_pT_1=func_x_pT_1, + func_p_xT_1=func_p_xT_1, + func_dx_dp_1=func_dx_dp_1, + func_pi_pT_1=func_pi_pT_1, + func_p_piT_1=func_p_piT_1, + func_x_pT_2=func_x_pT_2, + func_p_xT_2=func_p_xT_2, + func_dx_dp_2=func_dx_dp_2, + func_pi_pT_2=func_pi_pT_2, + func_p_piT_2=func_p_piT_2, + func_x_pT_3=func_x_pT_3, + func_p_xT_3=func_p_xT_3, + func_dx_dp_3=func_dx_dp_3, + func_pi_pT_3=func_pi_pT_3, + func_p_piT_3=func_p_piT_3, + num=num, + num_comp_1=num_comp_1, + num_comp_2=num_comp_2, + num_comp_3=num_comp_3) + "'FASTIast' algorithm"; + + end if; + + // + // Calculate derivatives of loadings w.r.t. equilibrium pressure + // + dx_adsorpt_dT_adsorpt := (x_adsorpt_pdT .- x_adsorpt_mdT) ./ (2*dT) + "Calculation of the partial derivatives of the equilibrium uptakes w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + end dx_dT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +The IAST for three components calculates equilibrium uptakes <i>x_adsorpt</i> as a +function of the equilibrium pressure <i>p_adsorpt</i>, mole fractions of independent +components in the gas or vapor phase <i>y_i</i>, and the equilibrium temperature +<i>T_adsorpt</i>. The IAST calculates the multi-component adsorption equilibrium based +on the pure component isotherm models. For this purpose, a system of equations is +solved using numerical methods. +</p> + +<h4>Main equations</h4> +<p> +The system of equations consists of 2 * <i>n_components</i> + 1 equations (i.e., 5), +which can be divided into 4 main equation types: +</p> +<ol> + <li> + Reduced spreading pressure <i>π</i> that is the same for all components: + <pre>π = π<sub><i>i</i></sub> = ∫<sub>0</sub><sup>p<sup>*</sup><sub><i>i</i></sub></sup> [x<sub>adsorpt,<i>i</i></sub> / p<sub>adsorpt,<i>i</i></sub> * dp<sub>adsorpt,<i>i</i></sub>].</pre> + <br> + </li> + <li> + Closing condition of the molar composition of the adsorpt phase <i>z<sub><i>i</i></sub></i>: + <pre>1 = ∑<sub><i>i</i></sub> z<sub><i>i</i></sub> = ∑<sub><i>i</i></sub> [y<sub><i>i</i></sub> * p<sub>adsorpt</sub> / p<sup>*</sup><sub><i>i</i></sub>].</pre> + <br> + </li> + <li> + Molar uptake of the adsorpt phase of each component <i>i</i>: + <pre>q<sub>adsorpt,<i>i</i></sub> = z<sub><i>i</i></sub> * q<sub>total</sub>.</pre> + <br> + </li> + <li> + Total molar uptake of the adsorpt phase: + <pre>q<sub>total</sub> = (∑<sub><i>i</i></sub> [z<sub><i>i</i></sub> / q<sub>adsorpt,<i>i</i></sub>]) ^ (-1).</pre> + <br> + </li> +</ol> +<p> +Herein, for each component <i>i</i<>, <i>p<sup>*</sup><sub><i>i</i></sub></i> is the +hypothetical pure component pressure at which the reduced spreading pressure of each +component <i>π<sub><i>i</i></sub></i> is identical (i.e., equilibrium condition). +</p> + +<h4>Example</h4> +<p> +The following figure shows the IAST for three components for one parameter set. In the +upper sub-figure, the equilibrium pressure changes with time. In the centre sub-figure, +the independent mole fractions change with time. In the lower sub-figure, the +equilibrium temperature changes with time. The left side shows the uptake of component +1, the middle shows the uptake of component 2, and the right side shows the uptake of +component 3. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_multi_iast_n3.png\" alt=\"media_functions_equilibria_multi_iast_n3.png\"> + +<h4>References</h4> +<p> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Mangano E., Friedrich, D., and Brandani, S. (2015). Robust algorithms for the solution of the ideal adsorbed solution theory equations. AIChE Journal, 61(3): 981–991. DOI: 10.1002/aic.14684. + </li> +</ul> +</p> +</html>")); +end IAST_N3; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6d0f8d93aba1f8e0f67c45861309e4734531ccf1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/IAST_N3/package.order @@ -0,0 +1,8 @@ +Internals +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/calc_p_i_num_i_den.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/calc_p_i_num_i_den.mo new file mode 100644 index 0000000000000000000000000000000000000000..059044cbc47307768e67f31eeeb6418c748f41fb --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/calc_p_i_num_i_den.mo @@ -0,0 +1,70 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.Internals; +function calc_p_i_num_i_den + "Extended Langmuir isotherm model: Corrected partial pressures, numerators, denominator of the isotherm model" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real[:,:] c + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_threshold_min = 0 + "Threshold for partial pressures of all components: If a partial pressure is + below the threshold, its value is set to the threshold" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[size(c,2)] p_i_regulated + "Regulated equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Real den + "Identical denominator for each component of the isotherm model" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + den := 1 + "Start value of the denominator"; + + for ind_comp in 1:size(c,2) loop + p_i_regulated[ind_comp] := max(p_i[ind_comp], p_threshold_min) + "Limiter of partial pressures to increase numerical stability"; + + num_i[ind_comp] := c[1,ind_comp] * c[2,ind_comp] * p_i_regulated[ind_comp] + "Individual numerators"; + + den := den + c[2,ind_comp] * p_i_regulated[ind_comp] + "Identical denominator"; + end for; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function regulates the equilibrium pressures <i>p_i</i> (i.e., partial +pressures) so that they are equal or greater than <i>p_threshold_min</i>. Further, +this function calculates the numerators <i>num_i</i> and denominator <i>den</i> +of the extended Langmuir isotherm model. For full details of the extended Langmuir +isotherm model, check the documentation of the package +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end calc_p_i_num_i_den; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/p_i_xT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/p_i_xT.mo new file mode 100644 index 0000000000000000000000000000000000000000..0b087cc00508d544e81920f9f213900ca2983fe1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/p_i_xT.mo @@ -0,0 +1,79 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.Internals; +function p_i_xT + "Extended Langmuir isotherm model: Partial pressures as function of uptakes and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real[size(c,2), size(c,2)] A + "Matrix A of A*z = -x_adsorpt"; + Real[size(c,2)] z + "Vector z of A*z = -x_adsorpt (i.e., z = first substitution)"; + +algorithm + // + // Set up matrix A and solve system of linear equations: + // + // To calculate the invesere function of the extended Langmuir isotherm regarding + // the equilibrium pressure and mole fractions of the independent components of + // the gas or vapor phase, the term ' c[2,ind] * p_i[ind]' is substituted by + // 'z.' Thus, a system of linear equations is created that can be solved. + // Re-substitution allows to calculate partial pressures p_i and, thus, the + // equilibrium pressure and mole fractions. + // + for ind in 1:size(c,2) loop + A[ind,:] := fill(x_adsorpt[ind], size(c,2)) + "First, fill row with correct uptake"; + A[ind,ind] := x_adsorpt[ind] - c[1,ind] + "Second, correct diagonale"; + end for; + + z := Modelica.Math.Matrices.solve(A, -1 .* x_adsorpt) + "Third, solve the system of linear equations"; + + // + // Calculate partial pressures + // + for ind in 1:size(c,2) loop + p_i[ind] := max(z[ind] / c[2,ind], p_threshold_min) + "Re-substituate values and consider threshold if necessary"; + end for; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium pressures <i>p_i</i> (i.e., partial +pressures) as function of the equilibrium uptakes <i>x_adsorpt</i> and the +equilibrium temperature <i>T_adsorpt</i>. Thus, this function is a inverse of the +function 'x_pyT.' For full details of the original function 'x_pyT,' check the +documentation of the package +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end p_i_xT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..6d907b172ea63ccf591a3ecec528c61d060f2c7f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir; +package Internals "Internal functions used to avoid redundancy" + extends Modelica.Icons.InternalPackage; + + annotation (Documentation(info="<html> +<p> +This package contains functions used for various functions of the extended Langmuir +isotherm model. Thus, redundancy of code shall be avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Internals; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e5d8b7b6016638f5265244d86c90a7940b38f584 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/Internals/package.order @@ -0,0 +1,2 @@ +calc_p_i_num_i_den +p_i_xT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2e2535df44b5a9b8a04a0f045618c380f29c290a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/package.mo @@ -0,0 +1,387 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents; +package Langmuir "Package containing all functions regarding the extended Langmuir isotherm" + extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponents; + + // + // Internal package + // + redeclare final function extends x_pyT + "Extended Langmuir isotherm model: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real den + "Identical denominator for each component of the isotherm model"; + + algorithm + (p_i, num_i, den) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.Internals.calc_p_i_num_i_den( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + x_adsorpt := num_i ./ den + "Calculate equilibrium uptakes of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end x_pyT; + + redeclare final function extends p_xyT + "Extended Langmuir isotherm model: Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.Internals.p_i_xT( + x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min) + "Partial pressures"; + + p_adsorpt := sum(p_i) + "Equilibrium pressure"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end p_xyT; + + redeclare final function extends y_pxT + "Extended Langmuir isotherm model: Mole fractions of independent gas phase components as function of uptakes, pressure, and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.Internals.p_i_xT( + x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min) + "Partial pressures"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / max(p_adsorpt, p_threshold_min) + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end y_pxT; + + redeclare final function extends py_xT + "Extended Langmuir isotherm model: Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.Internals.p_i_xT( + x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min) + "Partial pressures"; + + p_adsorpt := max(sum(p_i), p_threshold_min) + "Equilibrium pressure"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / p_adsorpt + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + redeclare final function extends dx_dp + "Extended Langmuir isotherm model: Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real den + "Identical denominator for each component of the isotherm model"; + + Real[size(c,2)] dnum_i_dp_adsorpt + "Partial derivatives of the numerators w.r.t. the equilibrium pressure"; + Real dden_dp_adsorpt + "Partial derivative of the denominator w.r.t. the equilbrium pressure"; + + algorithm + (p_i, num_i, den) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.Internals.calc_p_i_num_i_den( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + // + // Calculate partial derivatives + // + dden_dp_adsorpt := 0 + "Start value of the derivative of the denominator w.r.t. equilbrium pressure"; + + for ind_comp in 1:size(c,2) loop + dnum_i_dp_adsorpt[ind_comp] := c[1,ind_comp] * c[2,ind_comp] * y_i_[ind_comp] + "Partial derivatives of numerators w.r.t. equilibrium pressure"; + + dden_dp_adsorpt := dden_dp_adsorpt + c[2,ind_comp] * y_i_[ind_comp] + "Partial derivative of denominator w.r.t. equilibrium pressure"; + end for; + + // + // Calculate derivatives of loadings w.r.t. equilibrium pressure + // + dx_adsorpt_dp_adsorpt := + (dnum_i_dp_adsorpt.* den .- num_i.* dden_dp_adsorpt) ./ den^2 + "Calculation of the partial derivatives of the equilibrium uptakes w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + end dx_dp; + + redeclare final function extends dx_dy + "Extended Langmuir isotherm model: Partial derivative of uptakes w.r.t. mole fractions of independent gas phase components at constant pressure and temperature" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real den + "Identical denominator for each component of the isotherm model"; + + Real[size(c,2),size(c,2)-1] dnum_i_dy_i + "Partial derivatives of the numerators w.r.t. the mole fractions of independent + gas phase components"; + Real[size(c,2)-1] dden_dy_i + "Partial derivative of the denominator w.r.t. the mole fractions of independent + gas phase components"; + + algorithm + (p_i, num_i, den) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.Internals.calc_p_i_num_i_den( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + // + // Calculate partial derivatives of numerators, which varies with components and + // mole fractions of independent components + // + dnum_i_dy_i:=zeros(size(c, 2), size(c, 2) - 1) + "Partial derivatives of the numerators w.r.t. the mole fractions of independent + gas phase components"; + + for ind_comp in 1:size(c,2) loop + if ind_comp < size(c,2) then + // Partial derivatives of independent components + // + dnum_i_dy_i[ind_comp,ind_comp] := c[1,ind_comp] * c[2,ind_comp] * p_adsorpt + "Partial derivatives of numerators w.r.t. the mole fractions of independent + gas phase components"; + + else + // Partial derivatives of dependent component + // + for ind_y_i in 1:size(c,2)-1 loop + dnum_i_dy_i[ind_comp,ind_y_i] := c[1,ind_comp] * c[2,ind_comp] * (-p_adsorpt) + "Partial derivatives of numerators w.r.t. the mole fractions of independent + gas phase components"; + + end for; + end if; + end for; + + // + // Calculate partial derivatives of the denominator, which varies with components and + // mole fractions of independent components + // + dden_dy_i:=zeros(size(c, 2) - 1) + "Partial derivative of the denominator w.r.t. the mole fractions of independent + gas phase components"; + + for ind_y_i in 1:size(c,2)-1 loop + dden_dy_i[ind_y_i] := dden_dy_i[ind_y_i] + + c[2,ind_y_i] * p_adsorpt + + c[2,size(c,2)] * (-p_adsorpt) + "Partial derivative of the denominator w.r.t. the mole fractions of independent + gas phase components"; + end for; + + // + // Calculate partial derivatives of uptakes w.r.t. mole fractions of independent + // gas phase components + // + for ind_comp in 1:size(c,2) loop + for ind_y_i in 1:size(c,2)-1 loop + dx_adsorpt_dy_i[ind_comp,ind_y_i] := + (dnum_i_dy_i[ind_comp,ind_y_i] * den - + num_i[ind_comp] * dden_dy_i[ind_y_i]) ./ den^2 + "Partial derivatives of the uptakes w.r.t. the mole fractions of independent + gas phase components at constant pressure and temperature"; + end for; + end for; + end dx_dy; + + redeclare final function extends dx_dT + "Extended Langmuir isotherm model: Partial derivative of uptakes w.r.t. temperature at constant pressure and mole fractions" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real den + "Identical denominator for each component of the isotherm model"; + + Real[size(c,2)] dnum_i_dT_adsorpt + "Derivatives of the numerators w.r.t. the equilibrium temperature"; + Real dden_dT_adsorpt + "Derivative of the denominator w.r.t. the equilbrium temperature"; + + algorithm + (p_i, num_i, den) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir.Internals.calc_p_i_num_i_den( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + // + // Calculate partial derivatives + // + dden_dT_adsorpt := 0 + "Start value of the derivative of the denominator w.r.t. equilbrium pressure"; + + for ind_comp in 1:size(c,2) loop + dnum_i_dT_adsorpt[ind_comp] := + (c[2,ind_comp] * p_i[ind_comp]) * dc_dT_adsorpt[1,ind_comp] + + (c[1,ind_comp] * p_i[ind_comp]) * dc_dT_adsorpt[2,ind_comp] + "Derivatives of numerators w.r.t. equilibrium temperature"; + + dden_dT_adsorpt := dden_dT_adsorpt + + (p_i[ind_comp]) * dc_dT_adsorpt[2,ind_comp] + "Derivative of denominator w.r.t. equilibrium temperature"; + end for; + + // + // Calculate derivatives of uptakes wrt. total pressure + // + dx_adsorpt_dT_adsorpt := + (dnum_i_dT_adsorpt.* den .- num_i.* dden_dT_adsorpt) ./ den^2 + "Calculation of the partial derivatives of the equilibrium uptakes w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + end dx_dT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The extended Langmuir isotherm model calculates equilibrium uptakes <i>x_adsorpt</i> +as a function of the equilibrium pressure <i>p_adsorpt</i>, mole fractions of +independent components in the gas or vapor phase <i>y_i</i>, and the equilibrium +temperature <i>T_adsorpt</i>. Each component of the extended Langmuir isotherm model +has two parameters. +</p> + +<h4>Main equations</h4> +<p> +The extended Langmuir isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt,<i>i</i></sub> = x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) * (b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,<i>i</i></sub>) / (1 + ∑[b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,<i>i</i></sub>]); +</pre> +<p> +Herein, for each component <i>i</i>, <i>x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>)</i> +is the saturation uptake and <i>b<sub><i>i</i></sub>(T<sub>adsorpt</sub>)</i> is the +Langmuir coefficient. Typical temperature dependencies may have the following forms: +</p> +<pre> + x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) = a<sub>0,<i>i</i></sub> + a<sub>1,<i>i</i></sub>/T<sub>adsorpt</sub>; +</pre> +<pre> + b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) = b<sub>0,<i>i</i></sub> * <strong>exp</strong>(-ΔH<sub>ads,<i>i</i></sub>/(R * T<sub>adsorpt</sub>)); +</pre> +<p> +Herein, for each component <i>i</i>, <i>a<sub>0,<i>i</i></sub></i>, <i>a<sub>1, +<i>i</i></sub></i>, <i>b<sub>0,<i>i</i></sub></i>, and <i>ΔH<sub>ads,<i>i</i></sub></i> +are fiiting parameters. The parameter <i>ΔH<sub>ads,<i>i</i></sub></i> is the +isosteric adsorption heat, which is invariant with the surface uptake. Note that the +extended Langmuir isotherm model only consists of thermodynamic consistency if the +saturation uptake <i>x<sub>sat,<i>i</i></sub></i> is constant. +</p> + +<h4>Required parameter order in function input c[:,no_components]:</h4> +<p> +For each component <i>i</i>, the required parameter order in the function input <i>c</i> +is as follows: +</p> +<ul> + <li> + c[1,<i>i</i>] = x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[2,<i>i</i>] = b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) in 1/Pa + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + All adsorption sites are energetically equivalent. + </li> + <li> + All adsorption sites can be occupied. + </li> + <li> + No interactions occur between the adsorbent molecules. + </li> + <li> + The adsorbent surface is covered monomolecularly. + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the extended Langmuir isotherm model for one parameter set +and two components. In the upper sub-figure, the equilibrium pressure changes with +time. In the centre sub-figure, the independent mole fractions change with time. +In the lower sub-figure, the equilibrium temperature changes with time. The left +side shows the uptake of component 1, and the right side shows the uptake of +component 2. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_multi_langmuir.png\" alt=\"media_functions_equilibria_multi_langmuir.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Amrutha and Jeppu, G. and Girish, C.R. and Prabhu, B., and Mayer, K. (2023). Multi-component Adsorption Isotherms: Review and Modeling Studies, Environmental Processes, 10:38. DOI: https://doi.org/10.1007/s40710-023-00631-0. + </li> +</ul> +</html>")); +end Langmuir; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6d0f8d93aba1f8e0f67c45861309e4734531ccf1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Langmuir/package.order @@ -0,0 +1,8 @@ +Internals +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/dx_CO2_dp.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/dx_CO2_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..8750735d9cedb01e7beac1235465828c9e7bd678 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/dx_CO2_dp.mo @@ -0,0 +1,63 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals; +function dx_CO2_dp + "Mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Partial derivative of uptake w.r.t. pressure as function of pressure and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp; + + // + // Definition of inputs + // + input Real[:] dc_dp_adsorpt + "Partial derivatives of coefficients of isotherm model w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = c[2] * p_adsorpt / + ((1 + (c[2]*p_adsorpt)^c[3])^(1/c[3])) + "Derivative of uptake w.r.t. to first coefficient of Toth isotherm"; + Real dx_adsorpt_dc2 = c[1] * p_adsorpt * + ((c[2]*p_adsorpt)^c[3] + 1) ^ (-1/c[3] - 1) + "Derivative of uptake w.r.t. to second coefficient of Toth isotherm"; + Real dx_adsorpt_dc3 = c[1] * c[2] * p_adsorpt * + (log(1 + (c[2]*p_adsorpt)^c[3]) / c[3]^2 - + (c[2]*p_adsorpt)^c[3] * log(c[2]*p_adsorpt) / + (c[3] * (1 + (c[2]*p_adsorpt)^c[3]))) / + ((1 + (c[2]*p_adsorpt)^c[3])^(1/c[3])) + "Derivative of uptake w.r.t. to third coefficient of Toth isotherm"; + +algorithm + dx_adsorpt_dp_adsorpt := + c[1]*c[2] * ((c[2]*p_adsorpt)^c[3] + 1) ^ (-1/c[3] - 1) + + dx_adsorpt_dc1*dc_dp_adsorpt[1] + + dx_adsorpt_dc2*dc_dp_adsorpt[2] + + dx_adsorpt_dc3*dc_dp_adsorpt[3] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'x_pT' of the Toth isotherm +model w.r.t.o the equilibrium pressure. For full details of the original function 'x_pT,' +check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT\">SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT</a>. +<br> +In contrast to the existing function 'dx_dp' of the Toth isotherm model, this function +recognises that the coefficients <i>c</i> can also depend on the equilibrium pressure. +Therefore, this function has the partial derivatives of the coefficients w.r.t. the +equilibrium pressure <i>dc_dp_adsorpt</i> as an additional input. +</p> +</html>", revisions="<html> +<ul> + <li> + August 1, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dx_CO2_dp; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/p_i_xT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/p_i_xT.mo new file mode 100644 index 0000000000000000000000000000000000000000..53028e2f4b4c816f9a6aa175496dc0eda0a7692c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/p_i_xT.mo @@ -0,0 +1,112 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals; +function p_i_xT + "Mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Partial pressures as function of uptakes and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real Phi_available(unit="1") + "Fraction of sites available for adsorption"; + Real A_CO2(unit="1/Pa") + "Enhancement factor of saturation uptake of CO2"; + + Real DH_avg(unit="J/mol") + "Average isosteric heat of adsorption"; + Real B_CO2(unit="1/Pa") + "Toth coefficient"; + +algorithm + // + // First, calculate the equilibrium pressure of component 1 (i.e., CO2) + // + Phi_available := c[3,1] - c[5,1] * + (1 - Modelica.Math.exp(-(c[7,1] * x_adsorpt[2]) ^ c[8,1])) + "Fraction of sites available for adsorption"; + A_CO2 := (c[4,1] + (Phi_available - c[4,1]) * + Modelica.Math.exp(-c[6,1] / x_adsorpt[2])) / c[4,1] + "Enhancement factor of saturation uptake of CO2"; + + DH_avg := (1 - Modelica.Math.exp(-c[6,1] / x_adsorpt[2])) * c[10,1] + + Modelica.Math.exp(-c[6,1] / x_adsorpt[2]) * c[11,1] + "Average isosteric heat of adsorption"; + B_CO2 := c[9,1] * Modelica.Math.exp(-DH_avg / (Modelica.Constants.R * T_adsorpt)) + "Toth coefficient"; + + p_i[1] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.p_xT( + x_adsorpt=x_adsorpt[1], + T_adsorpt=T_adsorpt, + c={A_CO2 * c[1,1], + B_CO2, + c[2,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium pressure of CO2"; + + p_i[1] := max(p_i[1], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Second, calculte the equilibrium pressure of component 2 (i.e., H2O) + // + // + p_i[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.p_xT( + x_adsorpt=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium pressure of H2O"; + + p_i[2] := max(p_i[2], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium pressures <i>p_i</i> (i.e., partial +pressures) as function of the equilibrium uptakes <i>x_adsorpt</i> and the +equilibrium temperature <i>T_adsorpt</i>. Thus, this function is a inverse of the +function 'x_pyT.' For full details of the original function 'x_pyT,' check the +documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + August 1, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end p_i_xT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9a128b7910d0392ea0af33a84ad3725f43c99bb0 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB; +package Internals "Internal functions used to avoid redundancy" + extends Modelica.Icons.InternalPackage; + + annotation (Documentation(info="<html> +<p> +This package contains functions used for various functions of the mechanistic +Toth-GAB isotherm model. Thus, redundancy of code shall be avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + August 1, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Internals; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/package.order new file mode 100644 index 0000000000000000000000000000000000000000..54b2b5782fac298b13169d076ab45becf29995f8 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/package.order @@ -0,0 +1,3 @@ +dx_CO2_dp +p_i_xT +x_H20_pT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/x_H20_pT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/x_H20_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..3735144ea837759e081b2558c7e3e71b9d5b33b5 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/Internals/x_H20_pT.mo @@ -0,0 +1,86 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals; +function x_H20_pT + "Mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Equilibrium uptake of component 2 (i.e., H2O) as function of partial pessures and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptake of component 2 (i.e., H2O)" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O_max= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.x_pT( + p_adsorpt=max(c[1,2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Maximal equilibrium uptake of H2O achieved at relative humidity of 1 (i.e., + p_adsorpt_H2O = p_sat_H2O"; + +algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the equilibrium uptake of component 1 (i.e., CO2) + // + // + x_adsorpt_H2O := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.x_pT( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of H2O"; + + x_adsorpt_H2O := min(x_adsorpt_H2O, x_adsorpt_H2O_max) + "Limit equilibrium uptake of H2O to its maximal equilibrium uptake"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium uptake of component 2 (i.e., H2O) +<i>x_adsorpt_H2O</i> as function of the partial equilibrium pressures <i>p_i</i> +and the equilibrium temperature <i>T_adsorpt</i>. For full details of the isotherm +model, check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + August 1, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_H20_pT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e76c5286ffb5caa8ffb58c43a583441b97b432cd --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/package.mo @@ -0,0 +1,939 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents; +package MechanisticTothGAB "Package containing all functions regarding the mechanistic Toth-GAB isotherm developed by Young et al. (2021) for adsorption of CO2 & H2O" + extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponents; + + // + // Internal package + // + redeclare final function extends x_pyT + "Mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + + // + // Definition of variables + // +protected + Real Phi_available(unit="1") + "Fraction of sites available for adsorption"; + Real A_CO2(unit="1/Pa") + "Enhancement factor of saturation uptake of CO2"; + + Real DH_avg(unit="J/mol") + "Average isosteric heat of adsorption"; + Real B_CO2(unit="1/Pa") + "Toth coefficient"; + + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the equilibrium uptake of component 1 (i.e., CO2) + // + x_adsorpt[2] := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals.x_H20_pT( + p_i=p_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate the equilibrium uptake of component 1 (i.e., CO2) + // + Phi_available := c[3,1] - c[5,1] * + (1 - Modelica.Math.exp(-(c[7,1] * x_adsorpt[2]) ^ c[8,1])) + "Fraction of sites available for adsorption"; + A_CO2 := (c[4,1] + (Phi_available - c[4,1]) * + Modelica.Math.exp(-c[6,1] / x_adsorpt[2])) / c[4,1] + "Enhancement factor of saturation uptake of CO2"; + + DH_avg := (1 - Modelica.Math.exp(-c[6,1] / x_adsorpt[2])) * c[10,1] + + Modelica.Math.exp(-c[6,1] / x_adsorpt[2]) * c[11,1] + "Average isosteric heat of adsorption"; + B_CO2 := c[9,1] * Modelica.Math.exp(-DH_avg / (Modelica.Constants.R * T_adsorpt)) + "Toth coefficient"; + + x_adsorpt[1] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={A_CO2 * c[1,1], + B_CO2, + c[2,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of CO2"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end x_pyT; + + redeclare final function extends p_xyT + "Mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals.p_i_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) "Partial pressures"; + + p_adsorpt := sum(p_i) + "Equilibrium pressure"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end p_xyT; + + redeclare final function extends y_pxT + "Mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Mole fractions of independent gas phase components as function of uptakes, pressure, and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals.p_i_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) "Partial pressures"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / max(p_adsorpt, p_threshold_min) + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end y_pxT; + + redeclare final function extends py_xT + "Mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals.p_i_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) "Partial pressures"; + + p_adsorpt := max(sum(p_i), p_threshold_min) + "Equilibrium pressure"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / p_adsorpt + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + redeclare final function extends dx_dp + "Mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptakes of component 2 (i.e., H2O)"; + + Real Phi_available(unit="1") + "Fraction of sites available for adsorption"; + Real A_CO2(unit="1/Pa") + "Enhancement factor of saturation uptake of CO2"; + + Real DH_avg(unit="J/mol") + "Average isosteric heat of adsorption"; + Real B_CO2(unit="1/Pa") + "Toth coefficient"; + + Real dA_CO2_dx_adsorpt_H2O(unit="kg/(Pa.kg)") + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + uptake of H2O"; + Real dA_CO2_dPhi_available(unit="1/Pa") + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + the fraction of sites available for adsorption"; + Real dPhi_available_dx_adsorpt_H2O(unit="kg/kg") + "Partial derivative of fraction of sites available for adsorption w.r.t. the + uptake of H2O"; + + Real dB_CO2_dH_avg(unit="mol/(Pa.J)") + "Partial derivative of Toth coefficient w.r.t. the average isosteric + adsorption enthalpy"; + Real dH_avg_dx_adsorpt_H20(unit="J.kg/(mol.kg)") + "Partial derivative of average isosteric heat of adsorption w.r.t. the + uptake of H2O"; + + Real dc_1_CO2_dp_adsorpt + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + Real dc_2_CO2_dp_adsorpt + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + Real dc_3_CO2_dp_adsorpt + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the partial derivative of the equilibrium uptake + // w.r.t. the equilibrium pressure of component 1 (i.e., CO2) + // + x_adsorpt_H2O := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals.x_H20_pT( + p_i=p_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate partial derivatives: + // + // The partial derivative of component 2 (i.e., H2O) must be calculated first + // because it is required to calculate the partial derivative of component 1 + // (i.e., CO2). + // + // The existing derivative function of the GAB isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // equilibrium pressure (i.e., y_i_[2]). + // + dx_adsorpt_dp_adsorpt[2] := y_i_[2] * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dp( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + + // + // Note that for component 1, the coefficients of the isotherm model are + // enhanced by the uptake of component 2. Hence, the parameters c depend also + // on the partial pressure of component 2 and, thus, on the equilibrium + // pressure. Note that all coefficients are devided by 'y_i_[1]' to compensate + // the multiplication by 'y_i_[1],' which is the partial derivative of the + // partial pressure of component 1 w.r.t. the equilibrium pressure. + // + Phi_available := c[3,1] - c[5,1] * + (1 - Modelica.Math.exp(-(c[7,1] * x_adsorpt_H2O) ^ c[8,1])) + "Fraction of sites available for adsorption"; + A_CO2 := (c[4,1] + (Phi_available - c[4,1]) * + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O)) / c[4,1] + "Enhancement factor of saturation uptake of CO2"; + + DH_avg := (1 - Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O)) * + c[10,1] + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) * c[11,1] + "Average isosteric heat of adsorption"; + B_CO2 := c[9,1] * Modelica.Math.exp(-DH_avg / (Modelica.Constants.R * T_adsorpt)) + "Toth coefficient"; + + dA_CO2_dx_adsorpt_H2O := c[6,1] * (Phi_available - c[4,1]) * + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) / (c[4,1] * x_adsorpt_H2O^2) + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + uptake of H2O"; + dA_CO2_dPhi_available := Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) / c[4,1] + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + the fraction of sites available for adsorption"; + dPhi_available_dx_adsorpt_H2O := - c[5,1] * c[8,1] * (c[7,1] * x_adsorpt_H2O) ^ + c[8,1] * Modelica.Math.exp(-(c[7,1] * x_adsorpt_H2O) ^ c[8,1]) / x_adsorpt_H2O + "Partial derivative of fraction of sites available for adsorption w.r.t. the + uptake of H2O"; + + dB_CO2_dH_avg := -B_CO2 / (Modelica.Constants.R * T_adsorpt) + "Partial derivative of Toth coefficient w.r.t. the average isosteric + adsorption enthalpy"; + dH_avg_dx_adsorpt_H20 := c[6,1] * (c[11,1] - c[10,1]) / x_adsorpt_H2O^2 * + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) + "Partial derivative of average isosteric heat of adsorption w.r.t. the + uptake of H2O"; + + dc_1_CO2_dp_adsorpt := c[1,1] * (dA_CO2_dx_adsorpt_H2O + + dA_CO2_dPhi_available * dPhi_available_dx_adsorpt_H2O) * + dx_adsorpt_dp_adsorpt[2] / y_i_[1] + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + dc_2_CO2_dp_adsorpt := dB_CO2_dH_avg * dH_avg_dx_adsorpt_H20 * + dx_adsorpt_dp_adsorpt[2] / y_i_[1] + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + dc_3_CO2_dp_adsorpt := 0 / y_i_[1] + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + + dx_adsorpt_dp_adsorpt[1] := y_i_[1]* + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals.dx_CO2_dp( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={A_CO2 * c[1,1], + B_CO2, + c[2,1]}, + dc_dp_adsorpt={dc_1_CO2_dp_adsorpt, + dc_2_CO2_dp_adsorpt, + dc_3_CO2_dp_adsorpt}) + "Partial derivative of first component's equilibrium uptake w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + end dx_dp; + + redeclare final function extends dx_dy + "Mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Partial derivative of uptakes w.r.t. mole fractions of independent gas phase components at constant pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptakes of component 2 (i.e., H2O)"; + + Real Phi_available(unit="1") + "Fraction of sites available for adsorption"; + Real A_CO2(unit="1/Pa") + "Enhancement factor of saturation uptake of CO2"; + + Real DH_avg(unit="J/mol") + "Average isosteric heat of adsorption"; + Real B_CO2(unit="1/Pa") + "Toth coefficient"; + + Real dA_CO2_dx_adsorpt_H2O(unit="kg/(Pa.kg)") + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + uptake of H2O"; + Real dA_CO2_dPhi_available(unit="1/Pa") + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + the fraction of sites available for adsorption"; + Real dPhi_available_dx_adsorpt_H2O(unit="kg/kg") + "Partial derivative of fraction of sites available for adsorption w.r.t. the + uptake of H2O"; + + Real dB_CO2_dH_avg(unit="mol/(Pa.J)") + "Partial derivative of Toth coefficient w.r.t. the average isosteric + adsorption enthalpy"; + Real dH_avg_dx_adsorpt_H20(unit="J.kg/(mol.kg)") + "Partial derivative of average isosteric heat of adsorption w.r.t. the + uptake of H2O"; + + Real dc_1_CO2_dp_adsorpt + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + Real dc_2_CO2_dp_adsorpt + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + Real dc_3_CO2_dp_adsorpt + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the partial derivative of the equilibrium uptake + // w.r.t. the independent mole fractions of component 1 (i.e., CO2) + // + x_adsorpt_H2O := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals.x_H20_pT( + p_i=p_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate partial derivatives: + // + // The partial derivative of component 2 (i.e., H2O) must be calculated first + // because it is required to calculate the partial derivative of component 1 + // (i.e., CO2). + // + // The existing derivative function of the GAB isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // independent mole fractions (i.e., -p_adsorpt) + // + dx_adsorpt_dy_i[2,1] := -p_adsorpt * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dp( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + independent mole fractions at constant pressure and temperature"; + + // + // Note that for component 1, the coefficients of the isotherm model are + // enhanced by the uptake of component 2. Hence, the parameters c depend also + // on the partial pressure of component 2 and, thus, on the equilibrium + // pressure. Note that all coefficients are devided by 'p_adsorpt' to compensate + // the multiplication by 'p_adsorpt,' which is the partial derivative of the + // partial pressure of component 1 w.r.t. the equilibrium pressure. + // + Phi_available := c[3,1] - c[5,1] * + (1 - Modelica.Math.exp(-(c[7,1] * x_adsorpt_H2O) ^ c[8,1])) + "Fraction of sites available for adsorption"; + A_CO2 := (c[4,1] + (Phi_available - c[4,1]) * + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O)) / c[4,1] + "Enhancement factor of saturation uptake of CO2"; + + DH_avg := (1 - Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O)) * + c[10,1] + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) * c[11,1] + "Average isosteric heat of adsorption"; + B_CO2 := c[9,1] * Modelica.Math.exp(-DH_avg / (Modelica.Constants.R * T_adsorpt)) + "Toth coefficient"; + + dA_CO2_dx_adsorpt_H2O := c[6,1] * (Phi_available - c[4,1]) * + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) / (c[4,1] * x_adsorpt_H2O^2) + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + uptake of H2O"; + dA_CO2_dPhi_available := Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) / c[4,1] + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + the fraction of sites available for adsorption"; + dPhi_available_dx_adsorpt_H2O := - c[5,1] * c[8,1] * (c[7,1] * x_adsorpt_H2O) ^ + c[8,1] * Modelica.Math.exp(-(c[7,1] * x_adsorpt_H2O) ^ c[8,1]) / x_adsorpt_H2O + "Partial derivative of fraction of sites available for adsorption w.r.t. the + uptake of H2O"; + + dB_CO2_dH_avg := -B_CO2 / (Modelica.Constants.R * T_adsorpt) + "Partial derivative of Toth coefficient w.r.t. the average isosteric + adsorption enthalpy"; + dH_avg_dx_adsorpt_H20 := c[6,1] * (c[11,1] - c[10,1]) / x_adsorpt_H2O^2 * + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) + "Partial derivative of average isosteric heat of adsorption w.r.t. the + uptake of H2O"; + + dc_1_CO2_dp_adsorpt := c[1,1] * (dA_CO2_dx_adsorpt_H2O + + dA_CO2_dPhi_available * dPhi_available_dx_adsorpt_H2O) * + dx_adsorpt_dy_i[2,1] / p_adsorpt + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + dc_2_CO2_dp_adsorpt := dB_CO2_dH_avg * dH_avg_dx_adsorpt_H20 * + dx_adsorpt_dy_i[2,1] / p_adsorpt + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + dc_3_CO2_dp_adsorpt := 0 / p_adsorpt + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + + dx_adsorpt_dy_i[1, 1] := p_adsorpt* + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals.dx_CO2_dp( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={A_CO2 * c[1,1], + B_CO2, + c[2,1]}, + dc_dp_adsorpt={dc_1_CO2_dp_adsorpt, + dc_2_CO2_dp_adsorpt, + dc_3_CO2_dp_adsorpt}) + "Partial derivative of first component's equilibrium uptake w.r.t. the + independent mole fractions at constant pressure and temperature"; + end dx_dy; + + redeclare final function extends dx_dT + "Mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Partial derivative of uptakes w.r.t. temperature at constant pressure and mole fractions" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptakes of component 2 (i.e., H2O)"; + + Real Phi_available(unit="1") + "Fraction of sites available for adsorption"; + Real A_CO2(unit="1/Pa") + "Enhancement factor of saturation uptake of CO2"; + + Real DH_avg(unit="J/mol") + "Average isosteric heat of adsorption"; + Real B_CO2(unit="1/Pa") + "Toth coefficient"; + + Real dA_CO2_dc4(unit="1/Pa") + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + the fourth coefficient of the Toth isotherm"; + Real dA_CO2_dc6(unit="kg/(Pa.kg)") + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + the sixth coefficient of the Toth isotherm"; + Real dA_CO2_dPhi_available(unit="1/Pa") + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + the fraction of sites available for adsorption"; + Real dA_CO2_dx_adsorpt_H2O(unit="kg/(Pa.kg)") + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + uptake of H2O"; + + Real dPhi_available_dc3(unit="1") + "Partial derivative of fraction of sites available for adsorption w.r.t. the + third coefficient of the Toth isotherm"; + Real dPhi_available_dc5(unit="1") + "Partial derivative of fraction of sites available for adsorption w.r.t. the + fivth coefficient of the Toth isotherm"; + Real dPhi_available_dc7(unit="kg/kg") + "Partial derivative of fraction of sites available for adsorption w.r.t. the + seventh coefficient of the Toth isotherm"; + Real dPhi_available_dc8(unit="kg/kg") + "Partial derivative of fraction of sites available for adsorption w.r.t. the + eigth coefficient of the Toth isotherm"; + Real dPhi_available_dx_adsorpt_H2O(unit="kg/kg") + "Partial derivative of fraction of sites available for adsorption w.r.t. the + uptake of H2O"; + Real dPhi_available_dT_adsorpt(unit="1/K") + "Partial derivative of fraction of sites available for adsorption w.r.t. the + equilibrium temperature"; + + Real dB_CO2_dc9(unit="1") + "Partial derivative of Toth coefficient w.r.t. the nith coefficient of the + Toth isotherm"; + Real dB_CO2_dH_avg(unit="mol/(Pa.J)") + "Partial derivative of Toth coefficient w.r.t. the average isosteric + adsorption enthalpy"; + Real dB_CO2_dT_adsorpt(unit="1/(Pa.K)") + "Partial derivative of Toth coefficient w.r.t. the equilibrium temperature"; + + Real dH_avg_dc6(unit="J.kg/(mol.kg)") + "Partial derivative of average isosteric heat of adsorption w.r.t. the + sixth coefficient of the Toth isotherm"; + Real dH_avg_dc10(unit="1") + "Partial derivative of average isosteric heat of adsorption w.r.t. the + tenth coefficient of the Toth isotherm"; + Real dH_avg_dc11(unit="1") + "Partial derivative of average isosteric heat of adsorption w.r.t. the + eleventh coefficient of the Toth isotherm"; + Real dH_avg_dx_adsorpt_H20(unit="J.kg/(mol.kg)") + "Partial derivative of average isosteric heat of adsorption w.r.t. the + uptake of H2O"; + Real dH_avg_dT_adsorpt(unit="J/(mol.K)") + "Partial derivative of average isosteric heat of adsorption w.r.t. the + equilibrium temperature"; + + Real dc_1_CO2_dT_adsorpt + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + Real dc_2_CO2_dT_adsorpt + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + Real dc_3_CO2_dT_adsorpt + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the partial derivative of the equilibrium uptake + // w.r.t. the equilibrium temperature of component 1 (i.e., CO2) + // + x_adsorpt_H2O := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB.Internals.x_H20_pT( + p_i=p_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate partial derivatives: + // + // The existing derivative functions of the Toth and GAB isotherm models + // correspond to partial derivatives w.r.t. the equilibrium temperature. Again, + // the partial derivative of component 2 (i.e., H2O) must be calculated first + // because it is required to calculate the partial derivative of component 1 + // (i.e., CO2). + // + dx_adsorpt_dT_adsorpt[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dT( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + dc_dT_adsorpt={dc_dT_adsorpt[1,2], + dc_dT_adsorpt[2,2], + dc_dT_adsorpt[3,2], + dc_dT_adsorpt[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + + // + // Note that for component 1, the coefficients of the isotherm model are + // enhanced by the uptake of component 2. Hence, the parameter dc_dT cannot + // directly be passed to the existing derivative function of the Toth isotherm + // model. Instead, the the correct derivative must be calculated first. + // + Phi_available := c[3,1] - c[5,1] * + (1 - Modelica.Math.exp(-(c[7,1] * x_adsorpt_H2O) ^ c[8,1])) + "Fraction of sites available for adsorption"; + A_CO2 := (c[4,1] + (Phi_available - c[4,1]) * + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O)) / c[4,1] + "Enhancement factor of saturation uptake of CO2"; + + DH_avg := (1 - Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O)) * + c[10,1] + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) * c[11,1] + "Average isosteric heat of adsorption"; + B_CO2 := c[9,1] * Modelica.Math.exp(-DH_avg / (Modelica.Constants.R * T_adsorpt)) + "Toth coefficient"; + + dA_CO2_dc4 := -Phi_available * Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) / + c[4,1] ^ 2 + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + the fourth coefficient of the Toth isotherm"; + dA_CO2_dc6 :=(c[4, 1] - Phi_available)*Modelica.Math.exp(-c[6, 1]/ + x_adsorpt_H2O)/(c[4, 1]*x_adsorpt_H2O) + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + the sixth coefficient of the Toth isotherm"; + dA_CO2_dPhi_available := Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) / c[4,1] + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + the fraction of sites available for adsorption"; + dA_CO2_dx_adsorpt_H2O := c[6,1] * (Phi_available - c[4,1]) * + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) / (c[4,1] * x_adsorpt_H2O^2) + "Partial derivative of enhancement factor of saturation uptake of CO2 w.r.t. + uptake of H2O"; + + dPhi_available_dc3 := 1 + "Partial derivative of fraction of sites available for adsorption w.r.t. the + third coefficient of the Toth isotherm"; + dPhi_available_dc5 := Modelica.Math.exp(-(c[7,1] * x_adsorpt_H2O) ^ c[8,1]) - 1 + "Partial derivative of fraction of sites available for adsorption w.r.t. the + fivth coefficient of the Toth isotherm"; + dPhi_available_dc7 := - c[5,1] * c[8,1] * (c[7,1] * x_adsorpt_H2O) ^ + c[8,1] * Modelica.Math.exp(-(c[7,1] * x_adsorpt_H2O) ^ c[8,1]) / c[7,1] + "Partial derivative of fraction of sites available for adsorption w.r.t. the + seventh coefficient of the Toth isotherm"; + dPhi_available_dc8 := c[5,1] * (c[7,1] * x_adsorpt_H2O) ^ c[8,1] * + log(c[7,1] * x_adsorpt_H2O) * Modelica.Math.exp(-(c[7,1] * x_adsorpt_H2O) ^ + c[8,1]) + "Partial derivative of fraction of sites available for adsorption w.r.t. the + eigth coefficient of the Toth isotherm"; + dPhi_available_dx_adsorpt_H2O := - c[5,1] * c[8,1] * (c[7,1] * x_adsorpt_H2O) ^ + c[8,1] * Modelica.Math.exp(-(c[7,1] * x_adsorpt_H2O) ^ c[8,1]) / x_adsorpt_H2O + "Partial derivative of fraction of sites available for adsorption w.r.t. the + uptake of H2O"; + dPhi_available_dT_adsorpt := dPhi_available_dc3 * dc_dT_adsorpt[3,1] + + dPhi_available_dc5 * dc_dT_adsorpt[5,1] + + dPhi_available_dc7 * dc_dT_adsorpt[7,1] + + dPhi_available_dc8 * dc_dT_adsorpt[8,1] + + dPhi_available_dx_adsorpt_H2O * dx_adsorpt_dT_adsorpt[2] + "Partial derivative of fraction of sites available for adsorption w.r.t. the + equilibrium temperature"; + + dB_CO2_dc9 := Modelica.Math.exp(-DH_avg / (Modelica.Constants.R * T_adsorpt)) + "Partial derivative of Toth coefficient w.r.t. the nith coefficient of the + Toth isotherm"; + dB_CO2_dH_avg := -B_CO2 / (Modelica.Constants.R * T_adsorpt) + "Partial derivative of Toth coefficient w.r.t. the average isosteric + adsorption enthalpy"; + dB_CO2_dT_adsorpt := B_CO2 * DH_avg / (Modelica.Constants.R * T_adsorpt^2) + "Partial derivative of Toth coefficient w.r.t. the equilibrium temperature"; + + dH_avg_dc6 := -(c[11,1] - c[10,1]) * + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) / x_adsorpt_H2O + "Partial derivative of average isosteric heat of adsorption w.r.t. the + sixth coefficient of the Toth isotherm"; + dH_avg_dc10 := 1 - Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) + "Partial derivative of average isosteric heat of adsorption w.r.t. the + tenth coefficient of the Toth isotherm"; + dH_avg_dc11 := Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) + "Partial derivative of average isosteric heat of adsorption w.r.t. the + eleventh coefficient of the Toth isotherm"; + dH_avg_dx_adsorpt_H20 := c[6,1] * (c[11,1] - c[10,1]) / x_adsorpt_H2O^2 * + Modelica.Math.exp(-c[6,1] / x_adsorpt_H2O) + "Partial derivative of average isosteric heat of adsorption w.r.t. the + uptake of H2O"; + dH_avg_dT_adsorpt := dH_avg_dc6 * dc_dT_adsorpt[6,1] + + dH_avg_dc10 * dc_dT_adsorpt[10,1] + + dH_avg_dc11 * dc_dT_adsorpt[11,1] + + dH_avg_dx_adsorpt_H20 * dx_adsorpt_dT_adsorpt[2] + "Partial derivative of average isosteric heat of adsorption w.r.t. the + equilibrium temperature"; + + dc_1_CO2_dT_adsorpt := A_CO2 * dc_dT_adsorpt[1,1] + c[1,1] * ( + dA_CO2_dc4 * dc_dT_adsorpt[4,1] + + dA_CO2_dc6 * dc_dT_adsorpt[6,1] + + dA_CO2_dPhi_available * dPhi_available_dT_adsorpt + + dA_CO2_dx_adsorpt_H2O * dx_adsorpt_dT_adsorpt[2]) + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + dc_2_CO2_dT_adsorpt := dB_CO2_dc9 * dc_dT_adsorpt[9,1] + + dB_CO2_dH_avg * dH_avg_dT_adsorpt + + dB_CO2_dT_adsorpt + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + dc_3_CO2_dT_adsorpt := dc_dT_adsorpt[2,1] + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + + dx_adsorpt_dT_adsorpt[1] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={A_CO2 * c[1,1], + B_CO2, + c[2,1]}, + dc_dT_adsorpt={dc_1_CO2_dT_adsorpt, + dc_2_CO2_dT_adsorpt, + dc_3_CO2_dT_adsorpt}) + "Partial derivative of first component's equilibrium uptake w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + end dx_dT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + August 1, 2024, by Mirko Engelpracht:<br/> + Adaptations (e.g., object-orientied approach) due to restructuring the library + and documentation. + </li> + <li> + November, 2023, by Daniel Rezo:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +The mechanistic Toth-GAB isotherm model calculates equilibrium uptakes <i>x_adsorpt</i> +of CO<sub>2</sub> and H<sub>2</sub>O on amine-functionalized sorbents as a function +of the equilibrium pressure <i>p_adsorpt</i>, mole fractions of independent +components in the gas or vapor phase <i>y_i</i>, and the equilibrium temperature +<i>T_adsorpt</i>. The model was developed by Young et al. (2021) for modeling of +direct air capture systems. A mechanistic Toth isotherm model describes the +uptake of CO<sub>2</sub>, while a GAB isotherm model describes the uptake of +H<sub>2</sub>O. +</p> + +<h4>Main equations</h4> +<p> +The mechanistic Toth isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt,CO<sub>2</sub></sub> = A<sub>CO<sub>2</sub></sub>(x<sub>adsorpt,H<sub>2</sub>O</sub>) * x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) * B<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>, x<sub>adsorpt,H<sub>2</sub>O</sub>) * p<sub>adsorpt,CO<sub>2</sub></sub> / ((1 + (B<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>, x<sub>adsorpt,H<sub>2</sub>O</sub>) * p<sub>adsorpt,CO<sub>2</sub></sub>) ^ t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)) ^ (1/t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>))); +</pre> +<p> +with: +</p> +<pre> + A<sub>CO<sub>2</sub></sub>(x<sub>adsorpt,H<sub>2</sub>O</sub>) = (Φ<sub>dry</sub> + (Φ<sub>available</sub>(x<sub>adsorpt,H<sub>2</sub>O</sub>) - Φ<sub>dry</sub>) * <strong>exp</strong>(-C<sub>CO<sub>2</sub></sub> / x<sub>adsorpt,H<sub>2</sub>O</sub>)) / Φ<sub>dry</sub>; +</pre> +<pre> + Φ<sub>available</sub>(x<sub>adsorpt,H<sub>2</sub>O</sub>) = Φ<sub>max</sub> - f<sub>blocked</sub> = Φ<sub>max</sub> - f<sub>blocked,max</sub> * (1 - <strong>exp</strong>(-(k<sub>CO<sub>2</sub></sub> * x<sub>adsorpt,H<sub>2</sub>O</sub>) ^ n<sub>CO<sub>2</sub></sub>)); +</pre> +<pre> + B<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>, x<sub>adsorpt,H<sub>2</sub>O</sub>) = b<sub>ref,CO<sub>2</sub></sub> * <strong>exp</strong>(-ΔH<sub>avg</sub></sub>(x<sub>adsorpt,H<sub>2</sub>O</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<pre> + ΔH<sub>avg</sub>(x<sub>adsorpt,H<sub>2</sub>O</sub>) = (1 - <strong>exp</strong>(-C<sub>CO<sub>2</sub></sub> / x<sub>adsorpt,H<sub>2</sub>O</sub>)) * ΔH<sub>dry</sub> + <strong>exp</strong>(-C<sub>CO<sub>2</sub></sub> / x<sub>adsorpt,H<sub>2</sub>O</sub>) * ΔH<sub>wet</sub>; +</pre> +<p> +Herein, <i>x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)</i> is the saturation +uptake, <i>B<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>, x<sub>adsorpt,H<sub>2</sub>O</sub>)</i> +is the Toth coefficient, and <i>t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)</i> is +the Toth exponent. The coefficient <i>A<sub>CO<sub>2</sub></sub></i> describes the +enhancement of CO<sub>2</sub> uptake due to the presence of H<sub>2</sub>O (i.e., +H<sub>2</sub>O uptake). The coefficient A<sub>CO<sub>2</sub></sub> depends on the +fraction of sites available for adsorption <i>Φ<sub>available</sub></i>, the amine +efficiency under dry conditions <i>Φ<sub>dry</sub></i>, the critical water loading +<i>C<sub>CO<sub>2</sub></sub></i>, the maximal possible amine efficiency <i>Φ<sub>max</sub></i>, +the fraction of blocked adsorption sites <i>f<sub>blocked</sub></i>, the maximal fraction +of blocked adsorption sites <i>f<sub>blocked,max</sub></i> as well as the two parameters +<i>k<sub>CO<sub>2</sub></sub></i> and <i>n<sub>CO<sub>2</sub></sub></i>. The Toth coefficient +<i>B<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub></i> depends on the Toth coefficient +<i>b<sub>ref,CO<sub>2</sub></sub></i> at reference temperature <i>T<sub>ref,CO<sub>2</sub></sub></i> +and the average isosteric adsorption enthalpy <i>ΔH<sub>avg</sub>(x<sub>adsorpt,H<sub>2</sub>O</sub>)</i>. +The latter depends on the isosteric adsorption under dry conditions <i>ΔH<sub>dry</sub></i> +and wet conditions <i>ΔH<sub>wet</sub></i>. Typical temperature dependencies of the +saturation uptake <i>x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)</i> and the Toth +coefficient <i>t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)</i> may have the following +forms: +</p> +<pre> + x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) = x<sub>ref,CO<sub>2</sub></sub> * <strong>exp</strong>(Χ<sub>CO<sub>2</sub></sub> * (1 - T<sub>adsorpt</sub>/T<sub>ref,CO<sub>2</sub></sub>)); +</pre> +<pre> + t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) = t<sub>ref,CO<sub>2</sub></sub> + α<sub>CO<sub>2</sub></sub> * (1 - T<sub>ref,CO<sub>2</sub></sub>/T<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>ref,CO<sub>2</sub></sub></i> is the saturation uptake at reference +temperature <i>T<sub>ref,CO<sub>2</sub></sub></i> and <i>t<sub>ref,CO<sub>2</sub></sub></i> +is the Toth exponent at reference temperature. The parameter <i>Χ<sub>CO<sub>2</sub></sub></i> +describes the change of the saturation uptake with temperature, and the parameter +<i>α<sub>CO<sub>2</sub></sub></i> describes the change of the Toth exponent +with temperature. +<br/> +<p> +The GAB isotherm model has the following form: +</p> +</p> +<pre> + x<sub>adsorpt,H<sub>2</sub>O</sub> = x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) / ((1 - k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)) * (1 + (c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) - 1) * k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>))); +</pre> +<p> +with +</p> +<pre> + φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = p<sub>adsorpt</sub>/p<sub>sat,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> is the monolayer +uptake and <i>c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> and +<i>k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> are affinity coefficients of +the GAB isotherm model. These three parameters can be modeled independent of temperature. +When assuming these three parameters to be dependent on temperature, typical temperature +dependencies may have the following forms: +</p> +<pre> + x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = x<sub>mon,ref,H<sub>2</sub>O</sub> * <strong>exp</strong>(Χ<sub>H<sub>2</sub>O</sub> * (1 - T<sub>adsorpt</sub>/T<sub>ref,H<sub>2</sub>O</sub>)); +</pre> +<pre> + c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = <strong>exp</strong>((E<sub>1,H<sub>2</sub>O</sub> - E<sub>10+,H<sub>2</sub>O</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<pre> + k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = <strong>exp</strong>((E<sub>2-9,H<sub>2</sub>O</sub> - E<sub>10+,H<sub>2</sub>O</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + E<sub>1,H<sub>2</sub>O</sub> = C<sub>H<sub>2</sub>O</sub> - <strong>exp</strong>(D<sub>H<sub>2</sub>O</sub> * T<sub>adsorpt</sub>); +</pre> +<pre> + E<sub>2-9,H<sub>2</sub>O</sub> = F<sub>H<sub>2</sub>O</sub> + G<sub>H<sub>2</sub>O</sub> * T<sub>adsorpt</sub>; +</pre> +<pre> + E<sub>10+,H<sub>2</sub>O</sub> = Δh<sub>vap,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>mon,ref,H<sub>2</sub>O</sub></i> is the monolayer uptake at reference +temperature <i>T<sub>ref,H<sub>2</sub>O</sub></i> and <i>Χ<sub>H<sub>2</sub>O</sub></i> +describes the change of the monolayer uptake with temperature. The coefficient +<i>E<sub>1,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption of the first layer +and <i>E<sub>2-9,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption of layers +2-9: These enthalpies of adsorption can be modeled temperature-dependent as shown +in the example above, with the four fitting parameters <i>C<sub>H<sub>2</sub>O</sub></i>, +<i>D<sub>H<sub>2</sub>O</sub></i>, <i>E<sub>H<sub>2</sub>O</sub></i>, and <i>F<sub>H<sub>2</sub>O</sub></i>. +The coefficient <i>E<sub>10+,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption +for layer 10 or higher layers and is assumed to correspond to the temperature-dependent +enthalpy of vaporization <i>Δh<sub>vap,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i>. +</p> + +<h4>Required parameter order in function input c[:,no_components]:</h4> +<p> +For component 1 (i.e., CO<sub>2</sub>), the required parameter order in the function +input <i>c</i> is as follows: +</p> +<ul> + <li> + c[1,1] = x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[2,1] = t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[3,1] = Φ<sub>max</sub> in - + </li> + <li> + c[4,1] = Φ<sub>dry</sub> in - + </li> + <li> + c[5,1] = f<sub>blocked,max</sub> in - + </li> + <li> + c[6,1] = C<sub>CO<sub>2</sub></sub> in kg/kg + </li> + <li> + c[7,1] = k<sub>CO<sub>2</sub></sub> in kg/kg + </li> + <li> + c[8,1] = n<sub>CO<sub>2</sub></sub> in - + </li> + <li> + c[9,1] = b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) in 1/Pa + </li> + <li> + c[10,1] = ΔH<sub>dry</sub> in J/mol + </li> + <li> + c[11,1] = ΔH<sub>wet</sub> in J/mol + </li> +</ul> +<p> +For component 2 (i.e., H<sub>2</sub>0), the required parameter order in the function +input <i>c</i> is as follows: +</p> +<ul> + <li> + c[1,2] = p<sub>sat,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2,2] = x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[3,2] = c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[4,2] = k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[5,2] = 0 (i.e., not required) + </li> + <li> + c[6,2] = 0 (i.e., not required) + </li> + <li> + c[7,2] = 0 (i.e., not required) + </li> + <li> + c[8,2] = 0 (i.e., not required) + </li> + <li> + c[9,2] = 0 (i.e., not required) + </li> + <li> + c[10,2] = 0 (i.e., not required) + </li> + <li> + c[11,2] = 0 (i.e., not required) + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the mechanistic Toth-GAB isotherm model for one parameter set. +In the upper sub-figure, the equilibrium pressure changes with time. In the centre +sub-figure, the independent mole fractions change with time. In the lower sub-figure, +the equilibrium temperature changes with time. The left side shows the uptake of +component 1 (i.e., CO<sub>2</sub>), and the right side shows the uptake of component +2 (i.e., H<sub>2</sub>0). +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_multi_mechanistic_toth_gab.png\" alt=\"media_functions_equilibria_multi_mechanistic_toth_gab.png\"> + +<h4>References</h4> +<ul> + <li> + <li> + Young, J. and García-Díez, E. and Garcia, S. and van der Spek, M. (2021). The impact of binary water–CO<sub>2</sub> isotherm models on the optimal performance of sorbent-based direct air capture processes, Energy & Environmental Science, 14:5377. DOI: http://doi.org/10.1039/d1ee01272j. + </li> +</ul> +</html>")); +end MechanisticTothGAB; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6d0f8d93aba1f8e0f67c45861309e4734531ccf1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/MechanisticTothGAB/package.order @@ -0,0 +1,8 @@ +Internals +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/calc_p_i_num_i_den.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/calc_p_i_num_i_den.mo new file mode 100644 index 0000000000000000000000000000000000000000..44fdab031fbc73a3cce21056f8916de9f3086f43 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/calc_p_i_num_i_den.mo @@ -0,0 +1,71 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.Internals; +function calc_p_i_num_i_den + "Extended Sips isotherm model: Corrected partial pressures, numerators, denominator of the isotherm model" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real[:,:] c + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_threshold_min = 0 + "Threshold for partial pressures of all components: If a partial pressure is + below the threshold, its value is set to the threshold" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[size(c,2)] p_i_regulated + "Regulated equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Real den + "Identical denominator for each component of the isotherm model" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + den := 1 + "Start value of the denominator"; + + for ind_comp in 1:size(c,2) loop + p_i_regulated[ind_comp] := max(p_i[ind_comp], p_threshold_min) + "Limiter of partial pressures to increase numerical stability"; + + num_i[ind_comp] := c[1,ind_comp] * (c[2,ind_comp] * + p_i_regulated[ind_comp]) ^ (1/c[3,ind_comp]) + "Individual numerators"; + + den := den + (c[2,ind_comp] * p_i_regulated[ind_comp]) ^ (1/c[3,ind_comp]) + "Identical denominator"; + end for; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function regulates the equilibrium pressures <i>p_i</i> (i.e., partial +pressures) so that they are equal or greater than <i>p_threshold_min</i>. Further, +this function calculates the numerators <i>num_i</i> and denominator <i>den</i> +of the extended Sips isotherm model. For full details of the extended Sips +isotherm mode, check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + November 9, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end calc_p_i_num_i_den; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/p_i_xT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/p_i_xT.mo new file mode 100644 index 0000000000000000000000000000000000000000..ead11ad3d46dc9ee1a2657ceb93dab0f786302f9 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/p_i_xT.mo @@ -0,0 +1,75 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.Internals; +function p_i_xT + "Extended Sips isotherm model: Partial pressures as function of uptakes and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real[size(c,2), size(c,2)] A + "Matrix A of A*z = -x_adsorpt"; + Real[size(c,2)] z + "Vector z of A*z = -x_adsorpt (i.e., z = first substitution)"; + +algorithm + // + // Set up matrix A and solve system of linear equations: + // + // To calculate the invesere function of the extended Sips isotherm regarding + // the equilibrium pressure and mole fractions of the independent components of + // the gas or vapor phase, the term ' (c[2,ind] * p_i[ind]) ^ (1/c[3,ind])' is + // substituted by 'z.' Thus, a system of linear equations is created that can + // be solved. Re-substitution allows to calculate partial pressures p_i and, + // thus, the equilibrium pressure and mole fractions. + // + for ind in 1:size(c,2) loop + A[ind,:] := fill(x_adsorpt[ind], size(c,2)) + "First, fill row with correct uptake"; + A[ind,ind] := x_adsorpt[ind] - c[1,ind] + "Second, correct diagonale"; + end for; + + z := Modelica.Math.Matrices.solve(A, -1 .* x_adsorpt) + "Third, solve the system of linear equations"; + + for ind in 1:size(c,2) loop + p_i[ind] := max(z[ind] ^ c[3,ind] / c[2,ind], p_threshold_min) + "Re-substituate values and consider threshold if necessary"; + end for; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium pressures <i>p_i</i> (i.e., partial +pressures) as function of the equilibrium uptakes <i>x_adsorpt</i> and the +equilibrium temperature <i>T_adsorpt</i>. Thus, this function is a inverse of the +function 'x_pyT.' For full details of the original function 'x_pyT,' check the +documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + November 9, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end p_i_xT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..23df589b6d955b18f79bb2e84bffc1dc3e51e00f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips; +package Internals "Internal functions used to avoid redundancy" + extends Modelica.Icons.InternalPackage; + + annotation (Documentation(info="<html> +<p> +This package contains functions used for various functions of the extended Sips isotherm +model. Thus, redundancy of code shall be avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + November 9, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Internals; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e5d8b7b6016638f5265244d86c90a7940b38f584 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/Internals/package.order @@ -0,0 +1,2 @@ +calc_p_i_num_i_den +p_i_xT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..191be0f79523f019b871dbe5d4cbe16216b9db3b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/package.mo @@ -0,0 +1,405 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents; +package Sips "Package containing all functions regarding the extended Sips isotherm" + extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponents; + + // + // Internal package + // + redeclare final function extends x_pyT + "Extended Sips isotherm model: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real den + "Identical denominator for each component of the isotherm model"; + + algorithm + (p_i, num_i, den) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.Internals.calc_p_i_num_i_den( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + x_adsorpt := num_i ./ den + "Calculate equilibrium uptakes of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end x_pyT; + + redeclare final function extends p_xyT + "Extended Sips isotherm model: Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.Internals.p_i_xT( + x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min) + "Partial pressures"; + + p_adsorpt := sum(p_i) + "Equilibrium pressure"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end p_xyT; + + redeclare final function extends y_pxT + "Extended Sips isotherm model: Mole fractions of independent gas phase components as function of uptakes, pressure, and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.Internals.p_i_xT( + x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min) + "Partial pressures"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / max(p_adsorpt, p_threshold_min) + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end y_pxT; + + redeclare final function extends py_xT + "Extended Sips isotherm model: Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.Internals.p_i_xT( + x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min) + "Partial pressures"; + + p_adsorpt := max(sum(p_i), p_threshold_min) + "Equilibrium pressure"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / p_adsorpt + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + redeclare final function extends dx_dp + "Extended Sips isotherm model: Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real den + "Identical denominator for each component of the isotherm model"; + + Real[size(c,2)] dnum_i_dp_adsorpt + "Partial derivatives of the numerators w.r.t. the equilibrium pressure"; + Real dden_dp_adsorpt + "Partial derivative of the denominator w.r.t. the equilbrium pressure"; + + algorithm + (p_i, num_i, den) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.Internals.calc_p_i_num_i_den( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + // + // Calculate partial derivatives + // + dden_dp_adsorpt := 0 + "Start value of the derivative of the denominator w.r.t. equilbrium pressure"; + + for ind_comp in 1:size(c,2) loop + dnum_i_dp_adsorpt[ind_comp] := num_i[ind_comp] / + (c[3,ind_comp] * p_i[ind_comp]) * y_i_[ind_comp] + "Partial derivatives of numerators w.r.t. equilibrium pressure"; + + dden_dp_adsorpt := dden_dp_adsorpt + (c[2,ind_comp] * p_i[ind_comp]) ^ + (1/c[3,ind_comp]) / (c[3,ind_comp] * p_i[ind_comp]) * y_i_[ind_comp] + "Partial derivative of denominator w.r.t. equilibrium pressure"; + end for; + + // + // Calculate derivatives of loadings w.r.t. equilibrium pressure + // + dx_adsorpt_dp_adsorpt := + (dnum_i_dp_adsorpt.* den .- num_i.* dden_dp_adsorpt) ./ den^2 + "Calculation of the partial derivatives of the equilibrium uptakes w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + end dx_dp; + + redeclare final function extends dx_dy + "Extended Sips isotherm model: Partial derivative of uptakes w.r.t. mole fractions of independent gas phase components at constant pressure and temperature" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real den + "Identical denominator for each component of the isotherm model"; + + Real[size(c,2),size(c,2)-1] dnum_i_dy_i + "Partial derivatives of the numerators w.r.t. the mole fractions of independent + gas phase components"; + Real[size(c,2)-1] dden_dy_i + "Partial derivative of the denominator w.r.t. the mole fractions of independent + gas phase components"; + + algorithm + (p_i, num_i, den) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.Internals.calc_p_i_num_i_den( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + // + // Calculate partial derivatives of numerators, which varies with components and + // mole fractions of independent components + // + dnum_i_dy_i:=zeros(size(c,2),size(c,2)-1) + "Partial derivatives of the numerators w.r.t. the mole fractions of independent + gas phase components"; + + for ind_comp in 1:size(c,2) loop + if ind_comp < size(c,2) then + // Partial derivatives of independent components + // + dnum_i_dy_i[ind_comp,ind_comp] := num_i[ind_comp] / + (c[3,ind_comp] * p_i[ind_comp]) * p_adsorpt + "Partial derivatives of numerators w.r.t. the mole fractions of independent + gas phase components"; + + else + // Partial derivatives of dependent component + // + for ind_y_i in 1:size(c,2)-1 loop + dnum_i_dy_i[ind_comp,ind_y_i] := num_i[ind_comp] / + (c[3,ind_comp] * p_i[ind_comp]) * (-p_adsorpt) + "Partial derivatives of numerators w.r.t. the mole fractions of independent + gas phase components"; + + end for; + end if; + end for; + + // + // Calculate partial derivatives of the denominator, which varies with components and + // mole fractions of independent components + // + dden_dy_i:=zeros(size(c, 2) - 1) + "Partial derivative of the denominator w.r.t. the mole fractions of independent + gas phase components"; + + for ind_y_i in 1:size(c,2)-1 loop + dden_dy_i[ind_y_i] := dden_dy_i[ind_y_i] + + (c[2,ind_y_i] * p_i[ind_y_i]) ^ (1/c[3,ind_y_i]) / + (c[3,ind_y_i] * p_i[ind_y_i]) * p_adsorpt + + (c[2,size(c,2)] * p_i[size(c,2)]) ^ (1/c[3,size(c,2)]) / + (c[3,size(c,2)] * p_i[size(c,2)]) * (-p_adsorpt) + "Partial derivative of the denominator w.r.t. the mole fractions of independent + gas phase components"; + end for; + + // + // Calculate partial derivatives of uptakes w.r.t. mole fractions of independent + // gas phase components + // + for ind_comp in 1:size(c,2) loop + for ind_y_i in 1:size(c,2)-1 loop + dx_adsorpt_dy_i[ind_comp,ind_y_i] := + (dnum_i_dy_i[ind_comp,ind_y_i] * den - + num_i[ind_comp] * dden_dy_i[ind_y_i]) ./ den^2 + "Partial derivatives of the uptakes w.r.t. the mole fractions of independent + gas phase components at constant pressure and temperature"; + end for; + end for; + end dx_dy; + + redeclare final function extends dx_dT + "Extended Sips isotherm model: Partial derivative of uptakes w.r.t. temperature at constant pressure and mole fractions" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real den + "Identical denominator for each component of the isotherm model"; + + Real[size(c,2)] dnum_i_dT_adsorpt + "Derivatives of the numerators w.r.t. the equilibrium temperature"; + Real dden_dT_adsorpt + "Derivative of the denominator w.r.t. the equilbrium temperature"; + + algorithm + (p_i, num_i, den) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips.Internals.calc_p_i_num_i_den( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + // + // Calculate partial derivatives + // + dden_dT_adsorpt := 0 + "Start value of the derivative of the denominator w.r.t. equilbrium pressure"; + + for ind_comp in 1:size(c,2) loop + dnum_i_dT_adsorpt[ind_comp] := + (num_i[ind_comp] / c[1,ind_comp]) * dc_dT_adsorpt[1,ind_comp] + + (num_i[ind_comp] / (c[2,ind_comp] * c[3,ind_comp])) * + dc_dT_adsorpt[2,ind_comp] + + (-num_i[ind_comp] * log(c[2,ind_comp] *p_i[ind_comp]) / c[3,ind_comp]^2) * + dc_dT_adsorpt[3,ind_comp] + "Derivatives of numerators w.r.t. equilibrium temperature"; + + dden_dT_adsorpt := dden_dT_adsorpt + + ((c[2,ind_comp] * p_i[ind_comp]) ^ (1/c[3,ind_comp]) / + (c[2,ind_comp] * c[3,ind_comp])) * dc_dT_adsorpt[2,ind_comp] + + (-(c[2,ind_comp] * p_i[ind_comp]) ^ (1/c[3,ind_comp]) * + log(c[2,ind_comp] * p_i[ind_comp]) / c[3,ind_comp]^2) * + dc_dT_adsorpt[3,ind_comp] + "Derivative of denominator w.r.t. equilibrium temperature"; + end for; + + // + // Calculate derivatives of uptakes wrt. total pressure + // + dx_adsorpt_dT_adsorpt := + (dnum_i_dT_adsorpt.* den .- num_i.* dden_dT_adsorpt) ./ den^2 + "Calculation of the partial derivatives of the equilibrium uptakes w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + end dx_dT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 9, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The extended Sips isotherm model calculates equilibrium uptakes <i>x_adsorpt</i> +as a function of the equilibrium pressure <i>p_adsorpt</i>, mole fractions of +independent components in the gas or vapor phase <i>y_i</i>, and the equilibrium +temperature <i>T_adsorpt</i>. Each component of the extended Sips isotherm model +has three parameters. +</p> + +<h4>Main equations</h4> +<p> +The extended Sips isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt,<i>i</i></sub> = x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) * (b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,<i>i</i></sub>) ^ (1/n<sub><i>i</i></sub>(T<sub>adsorpt</sub>)) / (1 + ∑[(b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,<i>i</i></sub>) ^ (1/n<sub><i>i</i></sub>(T<sub>adsorpt</sub>))]); +</pre> +<p> +where <i>x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>)</i> is the saturation uptake +of component <i>i</i>, <i>b<sub><i>i</i></sub>(T<sub>adsorpt</sub>)</i> is the Sips +coefficient of component <i>i</i>, and <i>n<sub><i>i</i></sub>(T<sub>adsorpt</sub>)</i> +is the Sips exponent of component <i>i</i>. Typical temperature dependencies may +have the following forms: +</p> +<pre> + x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) = x<sub>ref,<i>i</i></sub> * <strong>exp</strong>(Χ<sub><i>i</i></sub> * (1 - T<sub>adsorpt</sub>/T<sub>ref,<i>i</i></sub>)); +</pre> +<pre> + b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) = b<sub>ref,<i>i</i></sub> * <strong>exp</strong>(Q<sub><i>i</i></sub>/(R * T<sub>ref,<i>i</i></sub>) * (T<sub>ref,<i>i</i></sub>/T<sub>adsorpt</sub> - 1)); +</pre> +<pre> + n<sub><i>i</i></sub>(T<sub>adsorpt</sub>) = (1/n<sub>ref,<i>i</i></sub> + α<sub><i>i</i></sub> * (1 - T<sub>ref,<i>i</i></sub>/T<sub>adsorpt</sub>)) ^ (-1); +</pre> +<p> +Herein, for each component <i>i</i>, <i>x<sub>ref,<i>i</i></sub></i> is the saturation +uptake at reference temperature <i>T<sub>ref,<i>i</i></sub></i>, <i>b<sub>ref,<i>i</i></sub></i> +is the Sips coefficient at reference temperature, and <i>n<sub>ref,<i>i</i></sub></i> +is the Sips exponent at reference temperature. The parameter <i>Q<sub><i>i</i></sub></i> +is a measure for the isosteric adsorption enthalpy at a fractional loading of +<i>x<sub>adsorpt,<i>i</i></sub>/x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) = 0.5</i>, +the parameter <i>Χ<sub><i>i</i></sub></i> describes the change of the saturation +uptake with temperature, and the parameter <i>α<sub><i>i</i></sub></i> describes +the change of the Sips exponent with temperature. All seven parameters can be used as +fitting parameters. +<br/><br/> +Note that the Sips exponent <i>n,<i>i</i>(T<sub>adsorpt</sub>)</i> is typically greater +than unity. For <i>n,<i>i</i>(T<sub>adsorpt</sub>) = 1</i>, the Sips isotherm becomes +the Langmuir isotherm. Hence, the Sips exponent <i>n,<i>i</i>(T<sub>adsorpt</sub>)</i> +can be interpreted as a parameter describing the heterogeneity of the adsorption system. +</p> + +<h4>Required parameter order in function input c[:,no_components]:</h4> +<p> +For each component <i>i</i>, the required parameter order in the function input <i>c</i> +is as follows: +</p> +<ul> + <li> + c[1,<i>i</i>] = x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[2,<i>i</i>] = b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) in 1/Pa + </li> + <li> + c[3,<i>i</i>] = n<sub><i>i</i></sub>(T<sub>adsorpt</sub>) in - + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + No proper Henry law behavior. + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the extended Sips isotherm model for one parameter set +and two components. In the upper sub-figure, the equilibrium pressure changes with +time. In the centre sub-figure, the independent mole fractions change with time. +In the lower sub-figure, the equilibrium temperature changes with time. The left +side shows the uptake of component 1, and the right side shows the uptake of +component 2. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_multi_sips.png\" alt=\"media_functions_equilibria_multi_sips.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> + <li> + Amrutha and Jeppu, G. and Girish, C.R. and Prabhu, B., and Mayer, K. (2023). Multi-component Adsorption Isotherms: Review and Modeling Studies, Environmental Processes, 10:38. DOI: https://doi.org/10.1007/s40710-023-00631-0. + </li> +</ul> +</html>")); +end Sips; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6d0f8d93aba1f8e0f67c45861309e4734531ccf1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Sips/package.order @@ -0,0 +1,8 @@ +Internals +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_everything.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_everything.mo new file mode 100644 index 0000000000000000000000000000000000000000..ce8097fd9a250bcd8309d31df74cb7a7b27a39f0 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_everything.mo @@ -0,0 +1,140 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.IAST_N2; +model Test_changing_everything + "Tester for all functions of the IAST for two components: Changing pressure, independent mole fractions, and temperature" + + // + // Definition of parameters of component 1 + // + parameter SorpLib.Units.Uptake[2] a0_1 = {1.468 * 0.04401, 7.891 * 0.04401} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_1(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_1(each unit="1/Pa") = {0.024e-6, 0.001645e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_1(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 + // + parameter SorpLib.Units.Uptake[2] a0_2 = {2.847 * 0.044097, 2.223 * 0.044097} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_2(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_2(each unit="1/Pa") = {0.028e-6, 1.228e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_2(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMultiIAST_N2( + final p_adsorpt_der=10000, + final y_i_der={-0.9/100}, + final T_adsorpt_der=80/100, + final p_adsorpt_start=100, + final y_i_start={0.95}, + final T_adsorpt_start=293.15, + final no_components=2, + final M_i={0.04401,0.044097}, + final no_coefficients_1=4, + final no_coefficients_2=4, + redeclare final package IsothermModelComponent1 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent2 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + num(IASTAlgorithm=SorpLib.Choices.IASTAlgorithm.NewtonRaphson), + num_comp_1(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_2(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2)); + +equation + // + // Coefficients of the isotherm model of component 1 + // + c_1[1] = a0_1[1] + a1_1[1] / T_adsorpt + "Coefficients of isotherm model"; + c_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_1[3] = a0_1[2] + a1_1[2] / T_adsorpt + "Coefficients of isotherm model"; + c_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 2 + // + c_2[1] = a0_2[1] + a1_2[1] / T_adsorpt + "Coefficients of isotherm model"; + c_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_2[3] = a0_2[2] + a1_2[2] / T_adsorpt + "Coefficients of isotherm model"; + c_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the IAST for two components. +<br/><br/> +As an example, this tester increases the pressure, independent mole fractions, and +temperature with time. To see the behavior of all functions, plot the variables +<i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and +<i>dx_adsorpt_dT_adsorpt</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_everything; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_mole_fractions.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_mole_fractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..b68100b2af8a4b4e206bdf5e3e00e6a427e3e23d --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_mole_fractions.mo @@ -0,0 +1,140 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.IAST_N2; +model Test_changing_mole_fractions + "Tester for all functions of the IAST for two components: Changing independent mole fractions" + + // + // Definition of parameters of component 1 + // + parameter SorpLib.Units.Uptake[2] a0_1 = {1.468 * 0.04401, 7.891 * 0.04401} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_1(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_1(each unit="1/Pa") = {0.024e-6, 0.001645e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_1(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 + // + parameter SorpLib.Units.Uptake[2] a0_2 = {2.847 * 0.044097, 2.223 * 0.044097} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_2(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_2(each unit="1/Pa") = {0.028e-6, 1.228e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_2(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMultiIAST_N2( + final p_adsorpt_der=0, + final y_i_der={-0.98/100}, + final T_adsorpt_der=0, + final p_adsorpt_start=100000, + final y_i_start={0.99}, + final T_adsorpt_start=293.15, + final no_components=2, + final M_i={0.04401,0.044097}, + final no_coefficients_1=4, + final no_coefficients_2=4, + redeclare final package IsothermModelComponent1 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent2 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + num(IASTAlgorithm=SorpLib.Choices.IASTAlgorithm.NewtonRaphson), + num_comp_1(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_2(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2)); + +equation + // + // Coefficients of the isotherm model of component 1 + // + c_1[1] = a0_1[1] + a1_1[1] / T_adsorpt + "Coefficients of isotherm model"; + c_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_1[3] = a0_1[2] + a1_1[2] / T_adsorpt + "Coefficients of isotherm model"; + c_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 2 + // + c_2[1] = a0_2[1] + a1_2[1] / T_adsorpt + "Coefficients of isotherm model"; + c_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_2[3] = a0_2[2] + a1_2[2] / T_adsorpt + "Coefficients of isotherm model"; + c_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the IAST for two components. +<br/><br/> +As an example, this tester increases the independent mole fractions with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> +over the variable <i>p_adsorpt</i>. The simulation time is correctly preset +(Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_mole_fractions; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..36b267d6692ab8a946556c42ce77f65293e59d22 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_pressure.mo @@ -0,0 +1,139 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.IAST_N2; +model Test_changing_pressure + "Tester for all functions of the IAST for two components: Changing pressure" + + // + // Definition of parameters of component 1 + // + parameter SorpLib.Units.Uptake[2] a0_1 = {1.468 * 0.04401, 7.891 * 0.04401} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_1(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_1(each unit="1/Pa") = {0.024e-6, 0.001645e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_1(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 + // + parameter SorpLib.Units.Uptake[2] a0_2 = {2.847 * 0.044097, 2.223 * 0.044097} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_2(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_2(each unit="1/Pa") = {0.028e-6, 1.228e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_2(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMultiIAST_N2( + final p_adsorpt_der=10000, + final y_i_der={0}, + final T_adsorpt_der=0, + final p_adsorpt_start=100, + final y_i_start={0.5}, + final T_adsorpt_start=293.15, + final no_components=2, + final M_i={0.04401,0.044097}, + final no_coefficients_1=4, + final no_coefficients_2=4, + redeclare final package IsothermModelComponent1 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent2 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + num(IASTAlgorithm=SorpLib.Choices.IASTAlgorithm.NewtonRaphson), + num_comp_1(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_2(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2)); + +equation + // + // Coefficients of the isotherm model of component 1 + // + c_1[1] = a0_1[1] + a1_1[1] / T_adsorpt + "Coefficients of isotherm model"; + c_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_1[3] = a0_1[2] + a1_1[2] / T_adsorpt + "Coefficients of isotherm model"; + c_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 2 + // + c_2[1] = a0_2[1] + a1_2[1] / T_adsorpt + "Coefficients of isotherm model"; + c_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_2[3] = a0_2[2] + a1_2[2] / T_adsorpt + "Coefficients of isotherm model"; + c_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the IAST for two components. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..2937ccad186e5e6acb3ed57e74a8971cdf7732a2 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/Test_changing_temperature.mo @@ -0,0 +1,139 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.IAST_N2; +model Test_changing_temperature + "Tester for all functions of the IAST for two components: Changing temperature" + + // + // Definition of parameters of component 1 + // + parameter SorpLib.Units.Uptake[2] a0_1 = {1.468 * 0.04401, 7.891 * 0.04401} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_1(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_1(each unit="1/Pa") = {0.024e-6, 0.001645e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_1(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 + // + parameter SorpLib.Units.Uptake[2] a0_2 = {2.847 * 0.044097, 2.223 * 0.044097} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_2(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_2(each unit="1/Pa") = {0.028e-6, 1.228e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_2(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMultiIAST_N2( + final p_adsorpt_der=0, + final y_i_der={0}, + final T_adsorpt_der=80/100, + final p_adsorpt_start=1000, + final y_i_start={0.5}, + final T_adsorpt_start=293.15, + final no_components=2, + final M_i={0.04401,0.044097}, + final no_coefficients_1=4, + final no_coefficients_2=4, + redeclare final package IsothermModelComponent1 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent2 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + num(IASTAlgorithm=SorpLib.Choices.IASTAlgorithm.NewtonRaphson), + num_comp_1(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_2(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2)); + +equation + // + // Coefficients of the isotherm model of component 1 + // + c_1[1] = a0_1[1] + a1_1[1] / T_adsorpt + "Coefficients of isotherm model"; + c_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_1[3] = a0_1[2] + a1_1[2] / T_adsorpt + "Coefficients of isotherm model"; + c_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 2 + // + c_2[1] = a0_2[1] + a1_2[1] / T_adsorpt + "Coefficients of isotherm model"; + c_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_2[3] = a0_2[2] + a1_2[2] / T_adsorpt + "Coefficients of isotherm model"; + c_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the IAST for two components. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a28962f2b3f4b894a5334466327d4d29b46e521b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers; +package IAST_N2 "Models ot test and varify functions of the IAST for two components" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the IAST for two +components. The test models check the implementation of the functions and enable +verification of the function behavior. Four test models are implemented, in which the +pressure, mole fractions of independent components in the gas or vapor phase, and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end IAST_N2; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..2df476354b8eaa401829535ab36ad77b4471614c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N2/package.order @@ -0,0 +1,4 @@ +Test_changing_pressure +Test_changing_mole_fractions +Test_changing_temperature +Test_changing_everything diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_everything.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_everything.mo new file mode 100644 index 0000000000000000000000000000000000000000..c4ec17227c6ef57ba6d7f9924d9452c6e1ed2ddb --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_everything.mo @@ -0,0 +1,190 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.IAST_N3; +model Test_changing_everything + "Tester for all functions of the IAST for three components: Changing pressure, independent mole fractions, and temperature" + + // + // Definition of parameters of component 1 + // + parameter SorpLib.Units.Uptake[2] a0_1 = {1.468 * 0.04401, 7.891 * 0.04401} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_1(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_1(each unit="1/Pa") = {0.024e-6, 0.001645e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_1(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 + // + parameter SorpLib.Units.Uptake[2] a0_2 = {2.847 * 0.044097, 2.223 * 0.044097} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_2(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_2(each unit="1/Pa") = {0.028e-6, 1.228e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_2(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 3 + // + parameter SorpLib.Units.Uptake[2] a0_3 = {2.581 * 0.042081, 2.901 * 0.042081} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_3(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_3(each unit="1/Pa") = {0.84e-6, 0.021e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_3(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMultiIAST_N3( + final p_adsorpt_der=10000, + final y_i_der={-0.9/100,0.9/100/2}, + final T_adsorpt_der=80/100, + final p_adsorpt_start=100, + final y_i_start={0.95,0.025}, + final T_adsorpt_start=293.15, + final no_components=3, + final M_i={0.04401,0.044097,0.042081}, + final no_coefficients_1=4, + final no_coefficients_2=4, + final no_coefficients_3=4, + redeclare final package IsothermModelComponent1 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent2 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent3 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + num(IASTAlgorithm=SorpLib.Choices.IASTAlgorithm.NewtonRaphson), + num_comp_1(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_2(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_3(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2)); + +equation + // + // Coefficients of the isotherm model of component 1 + // + c_1[1] = a0_1[1] + a1_1[1] / T_adsorpt + "Coefficients of isotherm model"; + c_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_1[3] = a0_1[2] + a1_1[2] / T_adsorpt + "Coefficients of isotherm model"; + c_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 2 + // + c_2[1] = a0_2[1] + a1_2[1] / T_adsorpt + "Coefficients of isotherm model"; + c_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_2[3] = a0_2[2] + a1_2[2] / T_adsorpt + "Coefficients of isotherm model"; + c_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 3 + // + c_3[1] = a0_3[1] + a1_3[1] / T_adsorpt + "Coefficients of isotherm model"; + c_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_3[3] = a0_3[2] + a1_3[2] / T_adsorpt + "Coefficients of isotherm model"; + c_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_3[1] = a0_3[1] + a1_3[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_3[3] = a0_3[2] + a1_3[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_3[1] = a0_3[1] + a1_3[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_3[3] = a0_3[2] + a1_3[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the IAST for three components. +<br/><br/> +As an example, this tester increases the pressure, independent mole fractions, and +temperature with time. To see the behavior of all functions, plot the variables +<i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and +<i>dx_adsorpt_dT_adsorpt</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_everything; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_mole_fractions.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_mole_fractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..7c2ea9f75291c4debe48b2bccc14ef2591b25548 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_mole_fractions.mo @@ -0,0 +1,190 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.IAST_N3; +model Test_changing_mole_fractions + "Tester for all functions of the IAST for three components: Changing independent mole fractions" + + // + // Definition of parameters of component 1 + // + parameter SorpLib.Units.Uptake[2] a0_1 = {1.468 * 0.04401, 7.891 * 0.04401} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_1(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_1(each unit="1/Pa") = {0.024e-6, 0.001645e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_1(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 + // + parameter SorpLib.Units.Uptake[2] a0_2 = {2.847 * 0.044097, 2.223 * 0.044097} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_2(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_2(each unit="1/Pa") = {0.028e-6, 1.228e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_2(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 3 + // + parameter SorpLib.Units.Uptake[2] a0_3 = {2.581 * 0.042081, 2.901 * 0.042081} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_3(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_3(each unit="1/Pa") = {0.84e-6, 0.021e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_3(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMultiIAST_N3( + final p_adsorpt_der=0, + final y_i_der={-0.97/100,0.97/100/2}, + final T_adsorpt_der=0, + final p_adsorpt_start=100000, + final y_i_start={0.98,0.01}, + final T_adsorpt_start=293.15, + final no_components=3, + final M_i={0.04401,0.044097,0.042081}, + final no_coefficients_1=4, + final no_coefficients_2=4, + final no_coefficients_3=4, + redeclare final package IsothermModelComponent1 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent2 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent3 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + num(IASTAlgorithm=SorpLib.Choices.IASTAlgorithm.NewtonRaphson), + num_comp_1(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_2(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_3(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2)); + +equation + // + // Coefficients of the isotherm model of component 1 + // + c_1[1] = a0_1[1] + a1_1[1] / T_adsorpt + "Coefficients of isotherm model"; + c_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_1[3] = a0_1[2] + a1_1[2] / T_adsorpt + "Coefficients of isotherm model"; + c_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 2 + // + c_2[1] = a0_2[1] + a1_2[1] / T_adsorpt + "Coefficients of isotherm model"; + c_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_2[3] = a0_2[2] + a1_2[2] / T_adsorpt + "Coefficients of isotherm model"; + c_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 3 + // + c_3[1] = a0_3[1] + a1_3[1] / T_adsorpt + "Coefficients of isotherm model"; + c_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_3[3] = a0_3[2] + a1_3[2] / T_adsorpt + "Coefficients of isotherm model"; + c_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_3[1] = a0_3[1] + a1_3[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_3[3] = a0_3[2] + a1_3[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_3[1] = a0_3[1] + a1_3[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_3[3] = a0_3[2] + a1_3[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the IAST for three components. +<br/><br/> +As an example, this tester increases the independent mole fractions with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> +over the variable <i>y_i</i>. The simulation time is correctly preset +(Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_mole_fractions; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..f3a0b810f0efd95a6fd89355c4b483420e05a24c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_pressure.mo @@ -0,0 +1,189 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.IAST_N3; +model Test_changing_pressure + "Tester for all functions of the IAST for three components: Changing pressure" + + // + // Definition of parameters of component 1 + // + parameter SorpLib.Units.Uptake[2] a0_1 = {1.468 * 0.04401, 7.891 * 0.04401} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_1(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_1(each unit="1/Pa") = {0.024e-6, 0.001645e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_1(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 + // + parameter SorpLib.Units.Uptake[2] a0_2 = {2.847 * 0.044097, 2.223 * 0.044097} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_2(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_2(each unit="1/Pa") = {0.028e-6, 1.228e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_2(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 3 + // + parameter SorpLib.Units.Uptake[2] a0_3 = {2.581 * 0.042081, 2.901 * 0.042081} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_3(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_3(each unit="1/Pa") = {0.84e-6, 0.021e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_3(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMultiIAST_N3( + final p_adsorpt_der=10000, + final y_i_der={0,0}, + final T_adsorpt_der=0, + final p_adsorpt_start=100, + final y_i_start={0.5,0.25}, + final T_adsorpt_start=293.15, + final no_components=3, + final M_i={0.04401,0.044097,0.042081}, + final no_coefficients_1=4, + final no_coefficients_2=4, + final no_coefficients_3=4, + redeclare final package IsothermModelComponent1 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent2 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent3 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + num(IASTAlgorithm=SorpLib.Choices.IASTAlgorithm.NewtonRaphson), + num_comp_1(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_2(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_3(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2)); + +equation + // + // Coefficients of the isotherm model of component 1 + // + c_1[1] = a0_1[1] + a1_1[1] / T_adsorpt + "Coefficients of isotherm model"; + c_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_1[3] = a0_1[2] + a1_1[2] / T_adsorpt + "Coefficients of isotherm model"; + c_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 2 + // + c_2[1] = a0_2[1] + a1_2[1] / T_adsorpt + "Coefficients of isotherm model"; + c_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_2[3] = a0_2[2] + a1_2[2] / T_adsorpt + "Coefficients of isotherm model"; + c_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 3 + // + c_3[1] = a0_3[1] + a1_3[1] / T_adsorpt + "Coefficients of isotherm model"; + c_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_3[3] = a0_3[2] + a1_3[2] / T_adsorpt + "Coefficients of isotherm model"; + c_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_3[1] = a0_3[1] + a1_3[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_3[3] = a0_3[2] + a1_3[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_3[1] = a0_3[1] + a1_3[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_3[3] = a0_3[2] + a1_3[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the IAST for three components. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..70b936fe04620bb2aa3a684f0fcc46407d0df902 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/Test_changing_temperature.mo @@ -0,0 +1,189 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.IAST_N3; +model Test_changing_temperature + "Tester for all functions of the IAST for three components: Changing temperature" + + // + // Definition of parameters of component 1 + // + parameter SorpLib.Units.Uptake[2] a0_1 = {1.468 * 0.04401, 7.891 * 0.04401} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_1(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_1(each unit="1/Pa") = {0.024e-6, 0.001645e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_1(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 + // + parameter SorpLib.Units.Uptake[2] a0_2 = {2.847 * 0.044097, 2.223 * 0.044097} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_2(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_2(each unit="1/Pa") = {0.028e-6, 1.228e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_2(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 3 + // + parameter SorpLib.Units.Uptake[2] a0_3 = {2.581 * 0.042081, 2.901 * 0.042081} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] a1_3(each unit="kg.K/kg") = {-1e-2, -1e-2} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] b0_3(each unit="1/Pa") = {0.84e-6, 0.021e-6} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[2] Delta_H_ads_3(each unit="J/mol") = {-2e4, -2e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMultiIAST_N3( + final p_adsorpt_der=0, + final y_i_der={0,0}, + final T_adsorpt_der=80/100, + final p_adsorpt_start=1000, + final y_i_start={0.5,0.25}, + final T_adsorpt_start=293.15, + final no_components=3, + final M_i={0.04401,0.044097,0.042081}, + final no_coefficients_1=4, + final no_coefficients_2=4, + final no_coefficients_3=4, + redeclare final package IsothermModelComponent1 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent2 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + redeclare final package IsothermModelComponent3 = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + num(IASTAlgorithm=SorpLib.Choices.IASTAlgorithm.NewtonRaphson), + num_comp_1(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_2(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2), + num_comp_3(tolerance_p_adsorpt=1e-6, tolerance_pi=1e-2)); + +equation + // + // Coefficients of the isotherm model of component 1 + // + c_1[1] = a0_1[1] + a1_1[1] / T_adsorpt + "Coefficients of isotherm model"; + c_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_1[3] = a0_1[2] + a1_1[2] / T_adsorpt + "Coefficients of isotherm model"; + c_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_1[1] = a0_1[1] + a1_1[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[2] = b0_1[1]*exp(-Delta_H_ads_1[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_1[3] = a0_1[2] + a1_1[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_1[4] = b0_1[2]*exp(-Delta_H_ads_1[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 2 + // + c_2[1] = a0_2[1] + a1_2[1] / T_adsorpt + "Coefficients of isotherm model"; + c_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_2[3] = a0_2[2] + a1_2[2] / T_adsorpt + "Coefficients of isotherm model"; + c_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_2[1] = a0_2[1] + a1_2[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[2] = b0_2[1]*exp(-Delta_H_ads_2[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_2[3] = a0_2[2] + a1_2[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_2[4] = b0_2[2]*exp(-Delta_H_ads_2[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Coefficients of the isotherm model of component 3 + // + c_3[1] = a0_3[1] + a1_3[1] / T_adsorpt + "Coefficients of isotherm model"; + c_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + c_3[3] = a0_3[2] + a1_3[2] / T_adsorpt + "Coefficients of isotherm model"; + c_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * T_adsorpt)) + "Coefficients of isotherm model"; + + c_pdT_3[1] = a0_3[1] + a1_3[1] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + c_pdT_3[3] = a0_3[2] + a1_3[2] / (T_adsorpt+dT) + "Coefficients of isotherm model"; + c_pdT_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * (T_adsorpt+dT))) + "Coefficients of isotherm model"; + + c_mdT_3[1] = a0_3[1] + a1_3[1] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_3[2] = b0_3[1]*exp(-Delta_H_ads_3[1] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + c_mdT_3[3] = a0_3[2] + a1_3[2] / (T_adsorpt-dT) + "Coefficients of isotherm model"; + c_mdT_3[4] = b0_3[2]*exp(-Delta_H_ads_3[2] / (Modelica.Constants.R * (T_adsorpt-dT))) + "Coefficients of isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 14, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the IAST for three components. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>T_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a9e52d0dcdbf52cbcb90d193a9b8b428b7bc30fd --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers; +package IAST_N3 "Models ot test and varify functions of the IAST for two components" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the IAST for three +components. The test models check the implementation of the functions and enable +verification of the function behavior. Four test models are implemented, in which the +pressure, mole fractions of independent components in the gas or vapor phase, and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end IAST_N3; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/package.order new file mode 100644 index 0000000000000000000000000000000000000000..2df476354b8eaa401829535ab36ad77b4471614c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/IAST_N3/package.order @@ -0,0 +1,4 @@ +Test_changing_pressure +Test_changing_mole_fractions +Test_changing_temperature +Test_changing_everything diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_everything.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_everything.mo new file mode 100644 index 0000000000000000000000000000000000000000..51dc3131930c7946a961918f8aa97dd7863286c7 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_everything.mo @@ -0,0 +1,98 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Langmuir; +model Test_changing_everything + "Tester for all functions of the extended Langmuir isotherm model: Changing pressure, independent mole fractions, and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] a0 = {0.35, 0.25, 0.15} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] a1(each unit="kg.K/kg") = {1e-4, 1e-4, 1e-4} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b0(each unit="1/Pa") = {5e-8, 5e-8, 5e-8} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Delta_H_ads(each unit="J/mol") = {-2e4, -3e4, -1e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 1400, + final y_i_der = {0.97/100/3*2,0.97/100/3*1}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 1, + final y_i_start = {1e-2,1e-2}, + final T_adsorpt_start = 298.15, + final no_components = 3, + final no_coefficients = 2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/T_adsorpt + "Coefficients of isotherm model"; + c[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*T_adsorpt)) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -a1[ind_comp]/T_adsorpt^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = Delta_H_ads[ind_comp]/(Modelica.Constants.R*T_adsorpt^2) * + c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/(T_adsorpt+dT) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*(T_adsorpt+dT))) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/(T_adsorpt-dT) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*(T_adsorpt-dT))) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Langmuir isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure, independent mole fractions, and +temperature with time. To see the behavior of all functions, plot the variables +<i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and +<i>dx_adsorpt_dT_adsorpt</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_everything; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_mole_fractions.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_mole_fractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..543e50b2f433a201a06e11c6334e15e16dc0900f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_mole_fractions.mo @@ -0,0 +1,99 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Langmuir; +model Test_changing_mole_fractions + "Tester for all functions of the extended Langmuir isotherm model: Changing independent mole fractions" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] a0 = {0.35, 0.25} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] a1(each unit="kg.K/kg") = {1e-4, 1e-4} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b0(each unit="1/Pa") = {5e-8, 5e-8} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Delta_H_ads(each unit="J/mol") = {-2e4, -3e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0.98/100}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 10000, + final y_i_start = {1e-2}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir, + p_threshold_min = 0); + +equation + + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/T_adsorpt + "Coefficients of isotherm model"; + c[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*T_adsorpt)) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -a1[ind_comp]/T_adsorpt^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = Delta_H_ads[ind_comp]/(Modelica.Constants.R*T_adsorpt^2) * + c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/(T_adsorpt+dT) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*(T_adsorpt+dT))) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/(T_adsorpt-dT) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*(T_adsorpt-dT))) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Langmuir isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the independent mole fractions with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> +over the variable <i>p_adsorpt</i>. The simulation time is correctly preset +(Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_mole_fractions; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..765cad5a69adcf492f5c69ab8d4ec185f0f1d6ff --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_pressure.mo @@ -0,0 +1,97 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Langmuir; +model Test_changing_pressure + "Tester for all functions of the extended Langmuir isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] a0 = {0.35, 0.25} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] a1(each unit="kg.K/kg") = {1e-4, 1e-4} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b0(each unit="1/Pa") = {5e-8, 5e-8} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Delta_H_ads(each unit="J/mol") = {-2e4, -3e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 100, + final y_i_der = {0}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final y_i_start = {0.5}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/T_adsorpt + "Coefficients of isotherm model"; + c[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*T_adsorpt)) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -a1[ind_comp]/T_adsorpt^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = Delta_H_ads[ind_comp]/(Modelica.Constants.R*T_adsorpt^2) * + c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/(T_adsorpt+dT) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*(T_adsorpt+dT))) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/(T_adsorpt-dT) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*(T_adsorpt-dT))) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 9, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Langmuir isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..d7c5c924dd39168c422d319da3f07eec4aafa160 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/Test_changing_temperature.mo @@ -0,0 +1,97 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Langmuir; +model Test_changing_temperature + "Tester for all functions of the extended Langmuir isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] a0 = {0.35, 0.25} + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] a1(each unit="kg.K/kg") = {1e-4, 1e-4} + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b0(each unit="1/Pa") = {5e-8, 5e-8} + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Delta_H_ads(each unit="J/mol") = {-2e4, -3e4} + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 10000, + final y_i_start = {0.5}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Langmuir, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/T_adsorpt + "Coefficients of isotherm model"; + c[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*T_adsorpt)) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -a1[ind_comp]/T_adsorpt^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = Delta_H_ads[ind_comp]/(Modelica.Constants.R*T_adsorpt^2) * + c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/(T_adsorpt+dT) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*(T_adsorpt+dT))) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = a0[ind_comp] + a1[ind_comp]/(T_adsorpt-dT) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b0[ind_comp]*exp(-Delta_H_ads[ind_comp]/ + (Modelica.Constants.R*(T_adsorpt-dT))) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 7, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Langmuir isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9e414e49cc69d4160f11e953d19a3f1c7d424e82 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers; +package Langmuir "Models ot test and varify functions of the extended Langmuir isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the extended Langmuir +isotherm model. The test models check the implementation of the functions and enable +verification of the function behavior. Four test models are implemented, in which the +pressure, mole fractions of independent components in the gas or vapor phase, and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Langmuir; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/package.order new file mode 100644 index 0000000000000000000000000000000000000000..2df476354b8eaa401829535ab36ad77b4471614c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Langmuir/package.order @@ -0,0 +1,4 @@ +Test_changing_pressure +Test_changing_mole_fractions +Test_changing_temperature +Test_changing_everything diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_everything.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_everything.mo new file mode 100644 index 0000000000000000000000000000000000000000..e1d38568af2051c2cb054a8d4fa6934533903147 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_everything.mo @@ -0,0 +1,321 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.MechanisticTothGAB; +model Test_changing_everything + "Tester for all functions of the mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Changing pressure, independent mole fractions, and temperature" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 4.86 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.209 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = 0.5823 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 2.85e-21 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_dry_CO2(unit="J/mol") = -117798 + "Parameter describing the isosteric enthalpy of adsorption under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_wet_CO2(unit="J/mol") = -130155 + "Parameter describing the isosteric enthalpy of adsorption under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Phi_max(unit="1") = 1 + "Maximal possible amine efficiency" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Phi_dry(unit="1") = 1 + "Amine efficiency under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real f_blocked_max(unit="1") = 0.433 + "Maximal fraction of blocked adsorption sited" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_CO2(unit="kg/kg") = 1.535 * 0.018015267 + "Critical water uptake" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_CO2(unit="kg/kg") = 0.795 / 0.018015267 + "First parameter describing change of fraction of blocked adsorption sites" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real n_CO2(unit="1") = 1.425 + "Second parameter describing change of fraction of blocked adsorption sites" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 3.63 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_H2O(unit="J/mol") = 47110 + "First parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D_H2O(unit="1/K") = 0.023744 + "Second parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F_H2O(unit="J/mol") = 57706 + "First parameter of the adsorption enthalpy of the layers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G_H2O(unit="J/(mol.K)") = -47.814 + "Second parameter of the adsorption enthalpy of the ayers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I_H2O(unit="J/mol") = 57220 + "First parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real J_H2O(unit="J/(mol.K)") = -44.38 + "Second parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = (1e5-12349)/100, + final y_i_der = {0}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 1, + final y_i_start = {1-0.5*12349/1e5}, + final T_adsorpt_start = 273.15+25, + final no_components = 2, + final no_coefficients = 11, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Second coefficient of the Toth isotherm model"; + c[3,1] = Phi_max + 1e-6 * (T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = Phi_dry + 1e-6 * (T_adsorpt) + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = f_blocked_max + 1e-6 * (T_adsorpt) + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = C_CO2 + 1e-6 * (T_adsorpt) + "Sixth coefficient of the Toth isotherm model"; + c[7,1] = k_CO2 + 1e-6 * (T_adsorpt) + "Seventh coefficient of the Toth isotherm model"; + c[8,1] = n_CO2 + 1e-6 * (T_adsorpt) + "Eigth coefficient of the Toth isotherm model"; + c[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt) + "Ninth coefficient of the Toth isotherm model"; + c[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt) + "Tenth coefficient of the Toth isotherm model"; + c[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt) + "Eleventh coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * T_adsorpt)) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * T_adsorpt) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2 / T_ref_CO2 * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = 1e-6 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 1e-6 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 1e-6 + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = 1e-6 + "Sixth coefficient of the Toth isotherm model"; + dc_dT[7,1] = 1e-6 + "Seventh coefficient of the Toth isotherm model"; + dc_dT[8,1] = 1e-6 + "Eigth coefficient of the Toth isotherm model"; + dc_dT[9,1] = 1e-6 + "Ninth coefficient of the Toth isotherm model"; + dc_dT[10,1] = 1e-6 + "Tenth coefficient of the Toth isotherm model"; + dc_dT[11,1] = 1e-6 + "Eleventh coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -((D_H2O*T_adsorpt - 1) * exp(D_H2O*T_adsorpt) - I_H2O + C_H2O) / + (Modelica.Constants.R*T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = (I_H2O - F_H2O) / (Modelica.Constants.R*T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + dc_dT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + dc_dT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + dc_dT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + dc_dT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + dc_dT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = Phi_max + 1e-6 * (T_adsorpt+dT) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = Phi_dry + 1e-6 * (T_adsorpt+dT) + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = f_blocked_max + 1e-6 * (T_adsorpt+dT) + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = C_CO2 + 1e-6 * (T_adsorpt+dT) + "Sixth coefficient of the Toth isotherm model"; + c_pdT[7,1] = k_CO2 + 1e-6 * (T_adsorpt+dT) + "Seventh coefficient of the Toth isotherm model"; + c_pdT[8,1] = n_CO2 + 1e-6 * (T_adsorpt+dT) + "Eigth coefficient of the Toth isotherm model"; + c_pdT[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt+dT) + "Ninth coefficient of the Toth isotherm model"; + c_pdT[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt+dT) + "Tenth coefficient of the Toth isotherm model"; + c_pdT[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt+dT) + "Eleventh coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt+dT))) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt+dT)) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_pdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c_pdT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c_pdT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c_pdT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c_pdT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = Phi_max + 1e-6 * (T_adsorpt-dT) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = Phi_dry + 1e-6 * (T_adsorpt-dT) + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = f_blocked_max + 1e-6 * (T_adsorpt-dT) + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = C_CO2 + 1e-6 * (T_adsorpt-dT) + "Sixth coefficient of the Toth isotherm model"; + c_mdT[7,1] = k_CO2 + 1e-6 * (T_adsorpt-dT) + "Seventh coefficient of the Toth isotherm model"; + c_mdT[8,1] = n_CO2 + 1e-6 * (T_adsorpt-dT) + "Eigth coefficient of the Toth isotherm model"; + c_mdT[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt-dT) + "Ninth coefficient of the Toth isotherm model"; + c_mdT[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt-dT) + "Tenth coefficient of the Toth isotherm model"; + c_mdT[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt-dT) + "Eleventh coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt-dT))) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt-dT)) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_mdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c_mdT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c_mdT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c_mdT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c_mdT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 1, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the mechanistic Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure, independent mole fractions, and +temperature with time. To see the behavior of all functions, plot the variables +<i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and +<i>dx_adsorpt_dT_adsorpt</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_everything; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_mole_fractions.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_mole_fractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..800472474233fa3a805943a529206eaace995280 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_mole_fractions.mo @@ -0,0 +1,321 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.MechanisticTothGAB; +model Test_changing_mole_fractions + "Tester for all functions of the mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Changing independent mole fractions" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 4.86 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.209 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = 0.5823 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 2.85e-21 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_dry_CO2(unit="J/mol") = -117798 + "Parameter describing the isosteric enthalpy of adsorption under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_wet_CO2(unit="J/mol") = -130155 + "Parameter describing the isosteric enthalpy of adsorption under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Phi_max(unit="1") = 1 + "Maximal possible amine efficiency" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Phi_dry(unit="1") = 1 + "Amine efficiency under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real f_blocked_max(unit="1") = 0.433 + "Maximal fraction of blocked adsorption sited" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_CO2(unit="kg/kg") = 1.535 * 0.018015267 + "Critical water uptake" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_CO2(unit="kg/kg") = 0.795 / 0.018015267 + "First parameter describing change of fraction of blocked adsorption sites" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real n_CO2(unit="1") = 1.425 + "Second parameter describing change of fraction of blocked adsorption sites" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 3.63 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_H2O(unit="J/mol") = 47110 + "First parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D_H2O(unit="1/K") = 0.023744 + "Second parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F_H2O(unit="J/mol") = 57706 + "First parameter of the adsorption enthalpy of the layers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G_H2O(unit="J/(mol.K)") = -47.814 + "Second parameter of the adsorption enthalpy of the ayers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I_H2O(unit="J/mol") = 57220 + "First parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real J_H2O(unit="J/(mol.K)") = -44.38 + "Second parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0.96/100}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 25000, + final y_i_start = {0.02}, + final T_adsorpt_start = 273.15+75, + final no_components = 2, + final no_coefficients = 11, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Second coefficient of the Toth isotherm model"; + c[3,1] = Phi_max + 1e-6 * (T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = Phi_dry + 1e-6 * (T_adsorpt) + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = f_blocked_max + 1e-6 * (T_adsorpt) + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = C_CO2 + 1e-6 * (T_adsorpt) + "Sixth coefficient of the Toth isotherm model"; + c[7,1] = k_CO2 + 1e-6 * (T_adsorpt) + "Seventh coefficient of the Toth isotherm model"; + c[8,1] = n_CO2 + 1e-6 * (T_adsorpt) + "Eigth coefficient of the Toth isotherm model"; + c[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt) + "Ninth coefficient of the Toth isotherm model"; + c[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt) + "Tenth coefficient of the Toth isotherm model"; + c[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt) + "Eleventh coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * T_adsorpt)) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * T_adsorpt) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2 / T_ref_CO2 * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = 1e-6 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 1e-6 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 1e-6 + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = 1e-6 + "Sixth coefficient of the Toth isotherm model"; + dc_dT[7,1] = 1e-6 + "Seventh coefficient of the Toth isotherm model"; + dc_dT[8,1] = 1e-6 + "Eigth coefficient of the Toth isotherm model"; + dc_dT[9,1] = 1e-6 + "Ninth coefficient of the Toth isotherm model"; + dc_dT[10,1] = 1e-6 + "Tenth coefficient of the Toth isotherm model"; + dc_dT[11,1] = 1e-6 + "Eleventh coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -((D_H2O*T_adsorpt - 1) * exp(D_H2O*T_adsorpt) - I_H2O + C_H2O) / + (Modelica.Constants.R*T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = (I_H2O - F_H2O) / (Modelica.Constants.R*T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + dc_dT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + dc_dT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + dc_dT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + dc_dT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + dc_dT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = Phi_max + 1e-6 * (T_adsorpt+dT) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = Phi_dry + 1e-6 * (T_adsorpt+dT) + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = f_blocked_max + 1e-6 * (T_adsorpt+dT) + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = C_CO2 + 1e-6 * (T_adsorpt+dT) + "Sixth coefficient of the Toth isotherm model"; + c_pdT[7,1] = k_CO2 + 1e-6 * (T_adsorpt+dT) + "Seventh coefficient of the Toth isotherm model"; + c_pdT[8,1] = n_CO2 + 1e-6 * (T_adsorpt+dT) + "Eigth coefficient of the Toth isotherm model"; + c_pdT[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt+dT) + "Ninth coefficient of the Toth isotherm model"; + c_pdT[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt+dT) + "Tenth coefficient of the Toth isotherm model"; + c_pdT[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt+dT) + "Eleventh coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt+dT))) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt+dT)) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_pdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c_pdT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c_pdT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c_pdT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c_pdT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = Phi_max + 1e-6 * (T_adsorpt-dT) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = Phi_dry + 1e-6 * (T_adsorpt-dT) + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = f_blocked_max + 1e-6 * (T_adsorpt-dT) + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = C_CO2 + 1e-6 * (T_adsorpt-dT) + "Sixth coefficient of the Toth isotherm model"; + c_mdT[7,1] = k_CO2 + 1e-6 * (T_adsorpt-dT) + "Seventh coefficient of the Toth isotherm model"; + c_mdT[8,1] = n_CO2 + 1e-6 * (T_adsorpt-dT) + "Eigth coefficient of the Toth isotherm model"; + c_mdT[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt-dT) + "Ninth coefficient of the Toth isotherm model"; + c_mdT[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt-dT) + "Tenth coefficient of the Toth isotherm model"; + c_mdT[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt-dT) + "Eleventh coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt-dT))) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt-dT)) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_mdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c_mdT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c_mdT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c_mdT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c_mdT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 1, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the mechanistic Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the independent mole fractions with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> +over the variable <i>p_adsorpt</i>. The simulation time is correctly preset +(Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_mole_fractions; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..0303dd20a7bd1f5b477145b8e17e0ff45d50de3f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_pressure.mo @@ -0,0 +1,320 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.MechanisticTothGAB; +model Test_changing_pressure + "Tester for all functions of the mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Changing pressure" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 4.86 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.209 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = 0.5823 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 2.85e-21 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_dry_CO2(unit="J/mol") = -117798 + "Parameter describing the isosteric enthalpy of adsorption under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_wet_CO2(unit="J/mol") = -130155 + "Parameter describing the isosteric enthalpy of adsorption under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Phi_max(unit="1") = 1 + "Maximal possible amine efficiency" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Phi_dry(unit="1") = 1 + "Amine efficiency under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real f_blocked_max(unit="1") = 0.433 + "Maximal fraction of blocked adsorption sited" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_CO2(unit="kg/kg") = 1.535 * 0.018015267 + "Critical water uptake" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_CO2(unit="kg/kg") = 0.795 / 0.018015267 + "First parameter describing change of fraction of blocked adsorption sites" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real n_CO2(unit="1") = 1.425 + "Second parameter describing change of fraction of blocked adsorption sites" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 3.63 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_H2O(unit="J/mol") = 47110 + "First parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D_H2O(unit="1/K") = 0.023744 + "Second parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F_H2O(unit="J/mol") = 57706 + "First parameter of the adsorption enthalpy of the layers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G_H2O(unit="J/(mol.K)") = -47.814 + "Second parameter of the adsorption enthalpy of the ayers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I_H2O(unit="J/mol") = 57220 + "First parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real J_H2O(unit="J/(mol.K)") = -44.38 + "Second parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = (0.6e5-12349)/100, + final y_i_der = {0}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 12349, + final y_i_start = {1-0.5*12349/0.6e5}, + final T_adsorpt_start = 273.15+50, + final no_components = 2, + final no_coefficients = 11, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Second coefficient of the Toth isotherm model"; + c[3,1] = Phi_max + 1e-6 * (T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = Phi_dry + 1e-6 * (T_adsorpt) + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = f_blocked_max + 1e-6 * (T_adsorpt) + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = C_CO2 + 1e-6 * (T_adsorpt) + "Sixth coefficient of the Toth isotherm model"; + c[7,1] = k_CO2 + 1e-6 * (T_adsorpt) + "Seventh coefficient of the Toth isotherm model"; + c[8,1] = n_CO2 + 1e-6 * (T_adsorpt) + "Eigth coefficient of the Toth isotherm model"; + c[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt) + "Ninth coefficient of the Toth isotherm model"; + c[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt) + "Tenth coefficient of the Toth isotherm model"; + c[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt) + "Eleventh coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * T_adsorpt)) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * T_adsorpt) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2 / T_ref_CO2 * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = 1e-6 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 1e-6 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 1e-6 + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = 1e-6 + "Sixth coefficient of the Toth isotherm model"; + dc_dT[7,1] = 1e-6 + "Seventh coefficient of the Toth isotherm model"; + dc_dT[8,1] = 1e-6 + "Eigth coefficient of the Toth isotherm model"; + dc_dT[9,1] = 1e-6 + "Ninth coefficient of the Toth isotherm model"; + dc_dT[10,1] = 1e-6 + "Tenth coefficient of the Toth isotherm model"; + dc_dT[11,1] = 1e-6 + "Eleventh coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -((D_H2O*T_adsorpt - 1) * exp(D_H2O*T_adsorpt) - I_H2O + C_H2O) / + (Modelica.Constants.R*T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = (I_H2O - F_H2O) / (Modelica.Constants.R*T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + dc_dT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + dc_dT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + dc_dT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + dc_dT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + dc_dT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = Phi_max + 1e-6 * (T_adsorpt+dT) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = Phi_dry + 1e-6 * (T_adsorpt+dT) + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = f_blocked_max + 1e-6 * (T_adsorpt+dT) + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = C_CO2 + 1e-6 * (T_adsorpt+dT) + "Sixth coefficient of the Toth isotherm model"; + c_pdT[7,1] = k_CO2 + 1e-6 * (T_adsorpt+dT) + "Seventh coefficient of the Toth isotherm model"; + c_pdT[8,1] = n_CO2 + 1e-6 * (T_adsorpt+dT) + "Eigth coefficient of the Toth isotherm model"; + c_pdT[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt+dT) + "Ninth coefficient of the Toth isotherm model"; + c_pdT[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt+dT) + "Tenth coefficient of the Toth isotherm model"; + c_pdT[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt+dT) + "Eleventh coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt+dT))) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt+dT)) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_pdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c_pdT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c_pdT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c_pdT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c_pdT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = Phi_max + 1e-6 * (T_adsorpt-dT) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = Phi_dry + 1e-6 * (T_adsorpt-dT) + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = f_blocked_max + 1e-6 * (T_adsorpt-dT) + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = C_CO2 + 1e-6 * (T_adsorpt-dT) + "Sixth coefficient of the Toth isotherm model"; + c_mdT[7,1] = k_CO2 + 1e-6 * (T_adsorpt-dT) + "Seventh coefficient of the Toth isotherm model"; + c_mdT[8,1] = n_CO2 + 1e-6 * (T_adsorpt-dT) + "Eigth coefficient of the Toth isotherm model"; + c_mdT[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt-dT) + "Ninth coefficient of the Toth isotherm model"; + c_mdT[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt-dT) + "Tenth coefficient of the Toth isotherm model"; + c_mdT[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt-dT) + "Eleventh coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt-dT))) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt-dT)) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_mdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c_mdT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c_mdT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c_mdT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c_mdT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 1, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the mechanistic Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..4aaf2e345067b4268efdcd9ee7928c296575b1bc --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/Test_changing_temperature.mo @@ -0,0 +1,320 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.MechanisticTothGAB; +model Test_changing_temperature + "Tester for all functions of the mechanistic Toth-GAB isotherm model developed by Young et al. (2021): Changing temperature" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 4.86 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.209 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = 0.5823 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 2.85e-21 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_dry_CO2(unit="J/mol") = -117798 + "Parameter describing the isosteric enthalpy of adsorption under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_wet_CO2(unit="J/mol") = -130155 + "Parameter describing the isosteric enthalpy of adsorption under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Phi_max(unit="1") = 1 + "Maximal possible amine efficiency" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Phi_dry(unit="1") = 1 + "Amine efficiency under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real f_blocked_max(unit="1") = 0.433 + "Maximal fraction of blocked adsorption sited" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_CO2(unit="kg/kg") = 1.535 * 0.018015267 + "Critical water uptake" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_CO2(unit="kg/kg") = 0.795 / 0.018015267 + "First parameter describing change of fraction of blocked adsorption sites" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real n_CO2(unit="1") = 1.425 + "Second parameter describing change of fraction of blocked adsorption sites" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 3.63 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_H2O(unit="J/mol") = 47110 + "First parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D_H2O(unit="1/K") = 0.023744 + "Second parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F_H2O(unit="J/mol") = 57706 + "First parameter of the adsorption enthalpy of the layers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G_H2O(unit="J/(mol.K)") = -47.814 + "Second parameter of the adsorption enthalpy of the ayers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I_H2O(unit="J/mol") = 57220 + "First parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real J_H2O(unit="J/(mol.K)") = -44.38 + "Second parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0}, + final T_adsorpt_der = 50/100, + final p_adsorpt_start = 0.6e5, + final y_i_start = {1-0.5*12349/0.6e5}, + final T_adsorpt_start = 273.15+50, + final no_components = 2, + final no_coefficients = 11, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.MechanisticTothGAB, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Second coefficient of the Toth isotherm model"; + c[3,1] = Phi_max + 1e-6 * (T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = Phi_dry + 1e-6 * (T_adsorpt) + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = f_blocked_max + 1e-6 * (T_adsorpt) + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = C_CO2 + 1e-6 * (T_adsorpt) + "Sixth coefficient of the Toth isotherm model"; + c[7,1] = k_CO2 + 1e-6 * (T_adsorpt) + "Seventh coefficient of the Toth isotherm model"; + c[8,1] = n_CO2 + 1e-6 * (T_adsorpt) + "Eigth coefficient of the Toth isotherm model"; + c[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt) + "Ninth coefficient of the Toth isotherm model"; + c[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt) + "Tenth coefficient of the Toth isotherm model"; + c[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt) + "Eleventh coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * T_adsorpt)) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * T_adsorpt) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2 / T_ref_CO2 * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = 1e-6 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 1e-6 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 1e-6 + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = 1e-6 + "Sixth coefficient of the Toth isotherm model"; + dc_dT[7,1] = 1e-6 + "Seventh coefficient of the Toth isotherm model"; + dc_dT[8,1] = 1e-6 + "Eigth coefficient of the Toth isotherm model"; + dc_dT[9,1] = 1e-6 + "Ninth coefficient of the Toth isotherm model"; + dc_dT[10,1] = 1e-6 + "Tenth coefficient of the Toth isotherm model"; + dc_dT[11,1] = 1e-6 + "Eleventh coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -((D_H2O*T_adsorpt - 1) * exp(D_H2O*T_adsorpt) - I_H2O + C_H2O) / + (Modelica.Constants.R*T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = (I_H2O - F_H2O) / (Modelica.Constants.R*T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + dc_dT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + dc_dT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + dc_dT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + dc_dT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + dc_dT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = Phi_max + 1e-6 * (T_adsorpt+dT) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = Phi_dry + 1e-6 * (T_adsorpt+dT) + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = f_blocked_max + 1e-6 * (T_adsorpt+dT) + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = C_CO2 + 1e-6 * (T_adsorpt+dT) + "Sixth coefficient of the Toth isotherm model"; + c_pdT[7,1] = k_CO2 + 1e-6 * (T_adsorpt+dT) + "Seventh coefficient of the Toth isotherm model"; + c_pdT[8,1] = n_CO2 + 1e-6 * (T_adsorpt+dT) + "Eigth coefficient of the Toth isotherm model"; + c_pdT[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt+dT) + "Ninth coefficient of the Toth isotherm model"; + c_pdT[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt+dT) + "Tenth coefficient of the Toth isotherm model"; + c_pdT[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt+dT) + "Eleventh coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt+dT))) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt+dT)) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_pdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c_pdT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c_pdT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c_pdT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c_pdT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = Phi_max + 1e-6 * (T_adsorpt-dT) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = Phi_dry + 1e-6 * (T_adsorpt-dT) + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = f_blocked_max + 1e-6 * (T_adsorpt-dT) + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = C_CO2 + 1e-6 * (T_adsorpt-dT) + "Sixth coefficient of the Toth isotherm model"; + c_mdT[7,1] = k_CO2 + 1e-6 * (T_adsorpt-dT) + "Seventh coefficient of the Toth isotherm model"; + c_mdT[8,1] = n_CO2 + 1e-6 * (T_adsorpt-dT) + "Eigth coefficient of the Toth isotherm model"; + c_mdT[9,1] = b_ref_CO2 + 1e-6 * (T_adsorpt-dT) + "Ninth coefficient of the Toth isotherm model"; + c_mdT[10,1] = DH_dry_CO2 + 1e-6 * (T_adsorpt-dT) + "Tenth coefficient of the Toth isotherm model"; + c_mdT[11,1] = DH_wet_CO2 + 1e-6 * (T_adsorpt-dT) + "Eleventh coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt-dT))) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt-dT)) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_mdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + c_mdT[8,2] = 0 + "Eigth coefficient of the GAB isotherm model"; + c_mdT[9,2] = 0 + "Ninth coefficient of the GAB isotherm model"; + c_mdT[10,2] = 0 + "Tenth coefficient of the GAB isotherm model"; + c_mdT[11,2] = 0 + "Eleventh coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 1, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the mechanistic Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..1f8af965822b381a7b9d6679f0bdebba124f77b0 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers; +package MechanisticTothGAB "Models to test and varify functions of the mechanistic Toth-GAB isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the mechanistic Toth-GAB +isotherm model. The test models check the implementation of the functions and enable +verification of the function behavior. Four test models are implemented, in which the +pressure, mole fractions of independent components in the gas or vapor phase, and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + August 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end MechanisticTothGAB; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/package.order new file mode 100644 index 0000000000000000000000000000000000000000..2df476354b8eaa401829535ab36ad77b4471614c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/MechanisticTothGAB/package.order @@ -0,0 +1,4 @@ +Test_changing_pressure +Test_changing_mole_fractions +Test_changing_temperature +Test_changing_everything diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_everything.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_everything.mo new file mode 100644 index 0000000000000000000000000000000000000000..61011bfb7c365ca22ded348aaee8216dc2019fd1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_everything.mo @@ -0,0 +1,121 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Sips; +model Test_changing_everything + "Tester for all functions of the extended Sips isotherm model: Changing pressure, independent mole fractions, and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] x_ref = {0.32, 0.22, 0.11} + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] chi(each unit="1") = {0, 0.1, 0.2} + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b_ref(each unit="1/Pa") = {1.075e-4, 1.075e-4, 1.075e-4} + "Sips coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Q(each unit="J/mol") = {28.752e3, 28.752e3, 28.752e3} + "Parameter describing the change of the Sips coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] n_ref(each unit="1") = {2.312, 2.812, 2.812} + "Sips exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] alpha(each unit="1") = {0.5559, 0.5559, 0.5559} + "Parameter describing the change of the Sips exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature[no_components] T_ref = {283, 283, 283} + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 1400, + final y_i_der = {0.97/100/3*2, 0.97/100/3*1}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 1, + final y_i_start = {1e-2, 1e-2}, + final T_adsorpt_start = 298.15, + final no_components = 3, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - T_adsorpt/T_ref[ind_comp])) + "Coefficients of isotherm model"; + c[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/T_adsorpt - 1)) + "Coefficients of isotherm model"; + c[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/T_adsorpt)) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -chi[ind_comp]/T_ref[ind_comp] * c[1,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = -Q[ind_comp]/Modelica.Constants.R/T_adsorpt^2 * c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[3,ind_comp] = -T_ref[ind_comp]*alpha[ind_comp]/T_adsorpt^2 / + (1/n_ref[ind_comp] + alpha[ind_comp] * (1 - T_ref[ind_comp]/T_adsorpt))^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt+dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt+dT) - 1)) + "Coefficients of isotherm model: T + dT K"; + c_pdT[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt+dT))) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt-dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt-dT) - 1)) + "Coefficients of isotherm model: T - dT K"; + c_mdT[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt-dT))) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 9, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Sips isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure, independent mole fractions, and +temperature with time. To see the behavior of all functions, plot the variables +<i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and +<i>dx_adsorpt_dT_adsorpt</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_everything; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_mole_fractions.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_mole_fractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..c3af008fd7439a1d17504560896d8e555987cdf2 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_mole_fractions.mo @@ -0,0 +1,121 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Sips; +model Test_changing_mole_fractions + "Tester for all functions of the extended Sips isotherm model: Changing independent mole fractions" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] x_ref = {0.32, 0.22} + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] chi(each unit="1") = {0, 0.1} + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b_ref(each unit="1/Pa") = {1.075e-4, 1.075e-4} + "Sips coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Q(each unit="J/mol") = {28.752e3, 28.752e3} + "Parameter describing the change of the Sips coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] n_ref(each unit="1") = {2.312, 2.812} + "Sips exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] alpha(each unit="1") = {0.5559, 0.5559} + "Parameter describing the change of the Sips exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature[no_components] T_ref = {283, 283} + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0.98/100}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 100000, + final y_i_start = {1e-2}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - T_adsorpt/T_ref[ind_comp])) + "Coefficients of isotherm model"; + c[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/T_adsorpt - 1)) + "Coefficients of isotherm model"; + c[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/T_adsorpt)) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -chi[ind_comp]/T_ref[ind_comp] * c[1,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = -Q[ind_comp]/Modelica.Constants.R/T_adsorpt^2 * c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[3,ind_comp] = -T_ref[ind_comp]*alpha[ind_comp]/T_adsorpt^2 / + (1/n_ref[ind_comp] + alpha[ind_comp] * (1 - T_ref[ind_comp]/T_adsorpt))^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt+dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt+dT) - 1)) + "Coefficients of isotherm model: T + dT K"; + c_pdT[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt+dT))) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt-dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt-dT) - 1)) + "Coefficients of isotherm model: T - dT K"; + c_mdT[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt-dT))) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 9, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Sips isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the independent mole fractions with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> +over the variable <i>p_adsorpt</i>. The simulation time is correctly preset +(Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_mole_fractions; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..1be28b113ede9f1e098f814c032c000a63b4eceb --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_pressure.mo @@ -0,0 +1,120 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Sips; +model Test_changing_pressure + "Tester for all functions of the extended Sips isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] x_ref = {0.32, 0.22} + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] chi(each unit="1") = {0, 0.1} + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b_ref(each unit="1/Pa") = {1.075e-4, 1.075e-4} + "Sips coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Q(each unit="J/mol") = {28.752e3, 28.752e3} + "Parameter describing the change of the Sips coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] n_ref(each unit="1") = {2.312, 2.812} + "Sips exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] alpha(each unit="1") = {0.5559, 0.5559} + "Parameter describing the change of the Sips exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature[no_components] T_ref = {283, 283} + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 1400, + final y_i_der = {0}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final y_i_start = {0.5}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - T_adsorpt/T_ref[ind_comp])) + "Coefficients of isotherm model"; + c[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/T_adsorpt - 1)) + "Coefficients of isotherm model"; + c[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/T_adsorpt)) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -chi[ind_comp]/T_ref[ind_comp] * c[1,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = -Q[ind_comp]/Modelica.Constants.R/T_adsorpt^2 * c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[3,ind_comp] = -T_ref[ind_comp]*alpha[ind_comp]/T_adsorpt^2 / + (1/n_ref[ind_comp] + alpha[ind_comp] * (1 - T_ref[ind_comp]/T_adsorpt))^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt+dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt+dT) - 1)) + "Coefficients of isotherm model: T + dT K"; + c_pdT[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt+dT))) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt-dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt-dT) - 1)) + "Coefficients of isotherm model: T - dT K"; + c_mdT[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt-dT))) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 9, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Sips isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..4c36e7843cb86f4c908905f0ce292fdbba36f9a8 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/Test_changing_temperature.mo @@ -0,0 +1,120 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Sips; +model Test_changing_temperature + "Tester for all functions of the extended Sips isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] x_ref = {0.32, 0.22} + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] chi(each unit="1") = {0, 0.1} + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b_ref(each unit="1/Pa") = {1.075e-4, 1.075e-4} + "Sips coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Q(each unit="J/mol") = {28.752e3, 28.752e3} + "Parameter describing the change of the Sips coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] n_ref(each unit="1") = {2.312, 2.812} + "Sips exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] alpha(each unit="1") = {0.5559, 0.5559} + "Parameter describing the change of the Sips exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature[no_components] T_ref = {283, 283} + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 100000, + final y_i_start = {0.5}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Sips, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - T_adsorpt/T_ref[ind_comp])) + "Coefficients of isotherm model"; + c[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/T_adsorpt - 1)) + "Coefficients of isotherm model"; + c[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/T_adsorpt)) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -chi[ind_comp]/T_ref[ind_comp] * c[1,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = -Q[ind_comp]/Modelica.Constants.R/T_adsorpt^2 * c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[3,ind_comp] = -T_ref[ind_comp]*alpha[ind_comp]/T_adsorpt^2 / + (1/n_ref[ind_comp] + alpha[ind_comp] * (1 - T_ref[ind_comp]/T_adsorpt))^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt+dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt+dT) - 1)) + "Coefficients of isotherm model: T + dT K"; + c_pdT[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt+dT))) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt-dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt-dT) - 1)) + "Coefficients of isotherm model: T - dT K"; + c_mdT[3,ind_comp] = 1 / (1/n_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt-dT))) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 9, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Sips isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5e4a22263490bb4b4eb7b06818d03a150995a221 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers; +package Sips "Models ot test and varify functions of the extended Sips isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the extended Sips +isotherm model. The test models check the implementation of the functions and enable +verification of the function behavior. Four test models are implemented, in which the +pressure, mole fractions of independent components in the gas or vapor phase, and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Sips; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/package.order new file mode 100644 index 0000000000000000000000000000000000000000..2df476354b8eaa401829535ab36ad77b4471614c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Sips/package.order @@ -0,0 +1,4 @@ +Test_changing_pressure +Test_changing_mole_fractions +Test_changing_temperature +Test_changing_everything diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_everything.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_everything.mo new file mode 100644 index 0000000000000000000000000000000000000000..7cbee3797a0435445db0f145838280ca5d73c7b2 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_everything.mo @@ -0,0 +1,119 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Toth; +model Test_changing_everything + "Tester for all functions of the extended Toth isotherm model: Changing pressure, independent mole fractions, and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] x_ref = {0.38, 0.28, 0.18} + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] chi(each unit="1") = {0, 0.1, 0.2} + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b_ref(each unit="1/Pa") = {10.54e-3, 10.54e-3, 10.54e-3} + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Q(each unit="J/mol") = {46.093e3, 36.093e3, 26.093e3} + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] t_ref(each unit="1") = {0.2842, 0.2842, 0.2842} + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] alpha(each unit="1") = {0.284, 0.284, 0.284} + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature[no_components] T_ref = {283, 283, 283} + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 1400, + final y_i_der = {0.97/100/3*2, 0.97/100/3*1}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 1, + final y_i_start = {1e-2, 1e-2}, + final T_adsorpt_start = 298.15, + final no_components = 3, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - T_adsorpt/T_ref[ind_comp])) + "Coefficients of isotherm model"; + c[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/T_adsorpt - 1)) + "Coefficients of isotherm model"; + c[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * (1 - T_ref[ind_comp]/T_adsorpt) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -chi[ind_comp]/T_ref[ind_comp] * c[1,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = -Q[ind_comp]/Modelica.Constants.R/T_adsorpt^2 * c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[3,ind_comp] = T_ref[ind_comp]*alpha[ind_comp]/T_adsorpt^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt+dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt+dT) - 1)) + "Coefficients of isotherm model: T + dT K"; + c_pdT[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt+dT)) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt-dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt-dT) - 1)) + "Coefficients of isotherm model: T - dT K"; + c_mdT[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt-dT)) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 8, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Toth isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure, independent mole fractions, and +temperature with time. To see the behavior of all functions, plot the variables +<i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and +<i>dx_adsorpt_dT_adsorpt</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_everything; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_mole_fractions.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_mole_fractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..5eecab25f9a6b38e3921b3e040b977f4083317b0 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_mole_fractions.mo @@ -0,0 +1,119 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Toth; +model Test_changing_mole_fractions + "Tester for all functions of the extended Toth isotherm model: Changing independent mole fractions" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] x_ref = {0.38, 0.28} + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] chi(each unit="1") = {0, 0.1} + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b_ref(each unit="1/Pa") = {10.54e-3, 10.54e-3} + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Q(each unit="J/mol") = {46.093e3, 36.093e3} + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] t_ref(each unit="1") = {0.2842, 0.2842} + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] alpha(each unit="1") = {0.284, 0.284} + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature[no_components] T_ref = {283, 283} + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0.98/100}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 100000, + final y_i_start = {1e-2}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - T_adsorpt/T_ref[ind_comp])) + "Coefficients of isotherm model"; + c[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/T_adsorpt - 1)) + "Coefficients of isotherm model"; + c[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * (1 - T_ref[ind_comp]/T_adsorpt) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -chi[ind_comp]/T_ref[ind_comp] * c[1,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = -Q[ind_comp]/Modelica.Constants.R/T_adsorpt^2 * c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[3,ind_comp] = T_ref[ind_comp]*alpha[ind_comp]/T_adsorpt^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt+dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt+dT) - 1)) + "Coefficients of isotherm model: T + dT K"; + c_pdT[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt+dT)) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt-dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt-dT) - 1)) + "Coefficients of isotherm model: T - dT K"; + c_mdT[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt-dT)) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 8, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Toth isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the independent mole fractions with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> +over the variable <i>p_adsorpt</i>. The simulation time is correctly preset +(Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_mole_fractions; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..b1322ef501311aa0d72d407779dfb834130bb1ba --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_pressure.mo @@ -0,0 +1,118 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Toth; +model Test_changing_pressure + "Tester for all functions of the extended Toth isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] x_ref = {0.38, 0.28} + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] chi(each unit="1") = {0, 0.1} + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b_ref(each unit="1/Pa") = {10.54e-3, 10.54e-3} + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Q(each unit="J/mol") = {46.093e3, 36.093e3} + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] t_ref(each unit="1") = {0.2842, 0.2842} + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] alpha(each unit="1") = {0.284, 0.284} + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature[no_components] T_ref = {283, 283} + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 1400, + final y_i_der = {0}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final y_i_start = {0.5}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - T_adsorpt/T_ref[ind_comp])) + "Coefficients of isotherm model"; + c[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/T_adsorpt - 1)) + "Coefficients of isotherm model"; + c[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * (1 - T_ref[ind_comp]/T_adsorpt) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -chi[ind_comp]/T_ref[ind_comp] * c[1,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = -Q[ind_comp]/Modelica.Constants.R/T_adsorpt^2 * c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[3,ind_comp] = T_ref[ind_comp]*alpha[ind_comp]/T_adsorpt^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt+dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt+dT) - 1)) + "Coefficients of isotherm model: T + dT K"; + c_pdT[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt+dT)) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt-dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt-dT) - 1)) + "Coefficients of isotherm model: T - dT K"; + c_mdT[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt-dT)) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 8, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Toth isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..a1264225a926baeb25d3dc4438cb231a54021e46 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/Test_changing_temperature.mo @@ -0,0 +1,118 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.Toth; +model Test_changing_temperature + "Tester for all functions of the extended Toth isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake[no_components] x_ref = {0.38, 0.28} + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] chi(each unit="1") = {0, 0.1} + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] b_ref(each unit="1/Pa") = {10.54e-3, 10.54e-3} + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] Q(each unit="J/mol") = {46.093e3, 36.093e3} + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] t_ref(each unit="1") = {0.2842, 0.2842} + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real[no_components] alpha(each unit="1") = {0.284, 0.284} + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature[no_components] T_ref = {283, 283} + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 100000, + final y_i_start = {0.5}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth, + p_threshold_min = 0); + +equation + for ind_comp in 1:no_components loop + // + // Coefficients of the isotherm model + // + c[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - T_adsorpt/T_ref[ind_comp])) + "Coefficients of isotherm model"; + c[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/T_adsorpt - 1)) + "Coefficients of isotherm model"; + c[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * (1 - T_ref[ind_comp]/T_adsorpt) + "Coefficients of isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,ind_comp] = -chi[ind_comp]/T_ref[ind_comp] * c[1,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[2,ind_comp] = -Q[ind_comp]/Modelica.Constants.R/T_adsorpt^2 * c[2,ind_comp] + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + dc_dT[3,ind_comp] = T_ref[ind_comp]*alpha[ind_comp]/T_adsorpt^2 + "Partial derivative of coefficients of isotherm model w.r.t. temperature"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt+dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T + dT K"; + c_pdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt+dT) - 1)) + "Coefficients of isotherm model: T + dT K"; + c_pdT[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt+dT)) + "Coefficients of isotherm model: T + dT K"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,ind_comp] = x_ref[ind_comp] * exp(chi[ind_comp] * + (1 - (T_adsorpt-dT)/T_ref[ind_comp])) + "Coefficients of isotherm model: T - dT K"; + c_mdT[2,ind_comp] = b_ref[ind_comp] * exp(Q[ind_comp]/Modelica.Constants.R/T_ref[ind_comp] * + (T_ref[ind_comp]/(T_adsorpt-dT) - 1)) + "Coefficients of isotherm model: T - dT K"; + c_mdT[3,ind_comp] = t_ref[ind_comp] + alpha[ind_comp] * + (1 - T_ref[ind_comp]/(T_adsorpt-dT)) + "Coefficients of isotherm model: T - dT K"; + end for; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 8, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the extended Toth isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d32606ca5ca7d886ee802f9fd5f9e1cfa041b8b8 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers; +package Toth "Models ot test and varify functions of the extended Toth isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the extended Toth +isotherm model. The test models check the implementation of the functions and enable +verification of the function behavior. Four test models are implemented, in which the +pressure, mole fractions of independent components in the gas or vapor phase, and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Toth; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/package.order new file mode 100644 index 0000000000000000000000000000000000000000..2df476354b8eaa401829535ab36ad77b4471614c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/Toth/package.order @@ -0,0 +1,4 @@ +Test_changing_pressure +Test_changing_mole_fractions +Test_changing_temperature +Test_changing_everything diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_everything.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_everything.mo new file mode 100644 index 0000000000000000000000000000000000000000..174c84b91520e059c93c6fb3e24bf6cbd533a01a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_everything.mo @@ -0,0 +1,224 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.TothGAB_Schellevis; +model Test_changing_everything + "Tester for all functions of the Toth-GAB isotherm model developed by Schellevis (2023): Changing pressure, independent mole fractions, and temperature" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 3.40 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 93e-5 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_CO2(unit="J/mol") = 95.3e3 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.37 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = 0.33 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real beta_CO2(unit="1") = 2.05 + "First coefficient of the enhancement factor" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real gamma_CO2(unit="kg/kg") = -0.85 / 0.018015267 + "Second coefficient of the enhancement factor" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 353.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 5.55 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real c_ref_H2O(unit="1") = 100 + "First affinity coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_c_CO2(unit="J/mol") = -8.69e3 + "Parameter describing the change of the first affinity coefficient with + temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_ref_H2O(unit="1") = 0.92 + "Second affinity coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_k_CO2(unit="J/mol") = -0.82e3 + "Parameter describing the change of the second affinity coefficient with + temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 353.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 100, + final y_i_der = {-0.90/100}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 1, + final y_i_start = {0.95}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the Toth isotherm model"; + c[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / T_adsorpt - 1)) + "Third coefficient of the Toth isotherm model"; + c[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = -chi_CO2 / T_ref_CO2 * c[2,1] + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = -Q_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[3,1] + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 0 + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = 0 + "Sixth coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -Q_c_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = -Q_k_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt+dT) - 1)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt-dT) - 1)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure, independent mole fractions, and +temperature with time. To see the behavior of all functions, plot the variables +<i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and +<i>dx_adsorpt_dT_adsorpt</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_everything; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_mole_fractions.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_mole_fractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..0dd5fbf1433ed6278d3b74b51bf4839402d609b3 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_mole_fractions.mo @@ -0,0 +1,224 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.TothGAB_Schellevis; +model Test_changing_mole_fractions + "Tester for all functions of the Toth-GAB isotherm model developed by Schellevis (2023): Changing independent mole fractions" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 3.40 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 93e-5 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_CO2(unit="J/mol") = 95.3e3 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.37 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = 0.33 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real beta_CO2(unit="1") = 2.05 + "First coefficient of the enhancement factor" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real gamma_CO2(unit="kg/kg") = -0.85 / 0.018015267 + "Second coefficient of the enhancement factor" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 353.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 5.55 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real c_ref_H2O(unit="1") = 100 + "First affinity coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_c_CO2(unit="J/mol") = -8.69e3 + "Parameter describing the change of the first affinity coefficient with + temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_ref_H2O(unit="1") = 0.92 + "Second affinity coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_k_CO2(unit="J/mol") = -0.82e3 + "Parameter describing the change of the second affinity coefficient with + temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 353.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0.98/100}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 10000, + final y_i_start = {1e-2}, + final T_adsorpt_start = 323.15, + final no_components = 2, + final no_coefficients = 6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the Toth isotherm model"; + c[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / T_adsorpt - 1)) + "Third coefficient of the Toth isotherm model"; + c[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = -chi_CO2 / T_ref_CO2 * c[2,1] + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = -Q_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[3,1] + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 0 + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = 0 + "Sixth coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -Q_c_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = -Q_k_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt+dT) - 1)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt-dT) - 1)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the independent mole fractions with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> +over the variable <i>p_adsorpt</i>. The simulation time is correctly preset +(Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_mole_fractions; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..09d9f61778b1d6c5130fd12b10c1daa0d5081d3a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_pressure.mo @@ -0,0 +1,223 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.TothGAB_Schellevis; +model Test_changing_pressure + "Tester for all functions of the Toth-GAB isotherm model developed by Schellevis (2023): Changing pressure" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 3.40 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 93e-5 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_CO2(unit="J/mol") = 95.3e3 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.37 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = 0.33 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real beta_CO2(unit="1") = 2.05 + "First coefficient of the enhancement factor" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real gamma_CO2(unit="kg/kg") = -0.85 / 0.018015267 + "Second coefficient of the enhancement factor" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 353.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 5.55 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real c_ref_H2O(unit="1") = 100 + "First affinity coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_c_CO2(unit="J/mol") = -8.69e3 + "Parameter describing the change of the first affinity coefficient with + temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_ref_H2O(unit="1") = 0.92 + "Second affinity coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_k_CO2(unit="J/mol") = -0.82e3 + "Parameter describing the change of the second affinity coefficient with + temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 353.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 100, + final y_i_der = {0}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final y_i_start = {0.75}, + final T_adsorpt_start = 273.15 + 35, + final no_components = 2, + final no_coefficients = 6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the Toth isotherm model"; + c[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / T_adsorpt - 1)) + "Third coefficient of the Toth isotherm model"; + c[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = -chi_CO2 / T_ref_CO2 * c[2,1] + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = -Q_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[3,1] + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 0 + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = 0 + "Sixth coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -Q_c_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = -Q_k_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt+dT) - 1)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt-dT) - 1)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..9f19e78ce3828f604a0817bd59ab3bfa3c6cb7ef --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/Test_changing_temperature.mo @@ -0,0 +1,223 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.TothGAB_Schellevis; +model Test_changing_temperature + "Tester for all functions of the Toth-GAB isotherm model developed by Schellevis (2023): Changing temperature" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 3.40 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 93e-5 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_CO2(unit="J/mol") = 95.3e3 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.37 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = 0.33 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real beta_CO2(unit="1") = 2.05 + "First coefficient of the enhancement factor" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real gamma_CO2(unit="kg/kg") = -0.85 / 0.018015267 + "Second coefficient of the enhancement factor" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 353.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 5.55 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real c_ref_H2O(unit="1") = 100 + "First affinity coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_c_CO2(unit="J/mol") = -8.69e3 + "Parameter describing the change of the first affinity coefficient with + temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_ref_H2O(unit="1") = 0.92 + "Second affinity coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_k_CO2(unit="J/mol") = -0.82e3 + "Parameter describing the change of the second affinity coefficient with + temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 353.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 10000, + final y_i_start = {0.9}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the Toth isotherm model"; + c[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / T_adsorpt - 1)) + "Third coefficient of the Toth isotherm model"; + c[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = -chi_CO2 / T_ref_CO2 * c[2,1] + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = -Q_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[3,1] + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 0 + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = 0 + "Sixth coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -Q_c_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = -Q_k_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt+dT) - 1)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt-dT) - 1)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = gamma_CO2 + "Sixth coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = c_ref_H2O * Modelica.Math.exp(Q_c_CO2/ + (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = k_ref_H2O * Modelica.Math.exp(Q_k_CO2/ + (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..3342118f7cc3ddf8eaaa290548acf6753b4a915b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers; +package TothGAB_Schellevis "Models to test and varify functions of the Toth-GAB isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Toth-GAB +isotherm model. The test models check the implementation of the functions and enable +verification of the function behavior. Four test models are implemented, in which the +pressure, mole fractions of independent components in the gas or vapor phase, and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + August 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end TothGAB_Schellevis; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/package.order new file mode 100644 index 0000000000000000000000000000000000000000..2df476354b8eaa401829535ab36ad77b4471614c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_Schellevis/package.order @@ -0,0 +1,4 @@ +Test_changing_pressure +Test_changing_mole_fractions +Test_changing_temperature +Test_changing_everything diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_everything.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_everything.mo new file mode 100644 index 0000000000000000000000000000000000000000..579d8a048e95e5434d94f2638488e6668bc6472b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_everything.mo @@ -0,0 +1,194 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.TothGAB_StampiBombelli; +model Test_changing_everything + "Tester for all functions of the Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Changing pressure, independent mole fractions, and temperature" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 2.38 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 0.07074 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_CO2(unit="J/mol") = -57047 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.4148 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = -1.6060 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake gamma_CO2 = 0.0061 / 0.0440098 + "Enhancement factor for saturation uptake" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake beta_CO2 = 28.907 / 0.0440098 + "Enhancement factor for Toth coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 296 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 36.48 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real c_H2O(unit="1") = 0.1489 + "First affinity coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_H2O(unit="1") = 0.5751 + "Second affinity coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 296 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 100, + final y_i_der = {-0.90/100}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 1, + final y_i_start = {0.95}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 5, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / T_adsorpt - 1)) + "Second coefficient of the Toth isotherm model"; + c[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2 / T_ref_CO2 * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = -Q_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[2,1] + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 0 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 0 + "Fivth coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = 0 + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = 0 + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt+dT) - 1)) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt-dT) - 1)) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + July 31, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure, independent mole fractions, and +temperature with time. To see the behavior of all functions, plot the variables +<i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and +<i>dx_adsorpt_dT_adsorpt</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_everything; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_mole_fractions.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_mole_fractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..f611844e00835cecf5158687e16bf3e2f882d3af --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_mole_fractions.mo @@ -0,0 +1,194 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.TothGAB_StampiBombelli; +model Test_changing_mole_fractions + "Tester for all functions of the Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Changing independent mole fractions" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 2.38 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 0.07074 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_CO2(unit="J/mol") = -57047 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.4148 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = -1.6060 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake gamma_CO2 = 0.0061 / 0.0440098 + "Enhancement factor for saturation uptake" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake beta_CO2 = 28.907 / 0.0440098 + "Enhancement factor for Toth coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 296 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 36.48 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real c_H2O(unit="1") = 0.1489 + "First affinity coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_H2O(unit="1") = 0.5751 + "Second affinity coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 296 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0.98/100}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 10000, + final y_i_start = {1e-2}, + final T_adsorpt_start = 323.15, + final no_components = 2, + final no_coefficients = 5, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / T_adsorpt - 1)) + "Second coefficient of the Toth isotherm model"; + c[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2 / T_ref_CO2 * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = -Q_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[2,1] + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 0 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 0 + "Fivth coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = 0 + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = 0 + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt+dT) - 1)) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt-dT) - 1)) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + July 31, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the independent mole fractions with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> +over the variable <i>p_adsorpt</i>. The simulation time is correctly preset +(Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_mole_fractions; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..b1fb1468ee18011577c0d424a49b8c0bf14267ab --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_pressure.mo @@ -0,0 +1,193 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.TothGAB_StampiBombelli; +model Test_changing_pressure + "Tester for all functions of the Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Changing pressure" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 2.38 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 0.07074 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_CO2(unit="J/mol") = -57047 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.4148 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = -1.6060 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake gamma_CO2 = 0.0061 / 0.0440098 + "Enhancement factor for saturation uptake" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake beta_CO2 = 28.907 / 0.0440098 + "Enhancement factor for Toth coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 296 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 36.48 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real c_H2O(unit="1") = 0.1489 + "First affinity coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_H2O(unit="1") = 0.5751 + "Second affinity coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 296 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 100, + final y_i_der = {0}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final y_i_start = {0.9}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 5, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / T_adsorpt - 1)) + "Second coefficient of the Toth isotherm model"; + c[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2 / T_ref_CO2 * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = -Q_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[2,1] + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 0 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 0 + "Fivth coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = 0 + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = 0 + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt+dT) - 1)) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt-dT) - 1)) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + July 31, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..48657604b9508520c21f8bbc990cce9b0c7cb319 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/Test_changing_temperature.mo @@ -0,0 +1,193 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.TothGAB_StampiBombelli; +model Test_changing_temperature + "Tester for all functions of the Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Changing temperature" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2 = 2.38 * 0.0440098 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2(unit="1/Pa") = 0.07074 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_CO2(unit="J/mol") = -57047 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2(unit="1") = 0.4148 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2(unit="1") = -1.6060 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake gamma_CO2 = 0.0061 / 0.0440098 + "Enhancement factor for saturation uptake" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake beta_CO2 = 28.907 / 0.0440098 + "Enhancement factor for Toth coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2 = 296 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 36.48 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real c_H2O(unit="1") = 0.1489 + "First affinity coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real k_H2O(unit="1") = 0.5751 + "Second affinity coefficient" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 296 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 10000, + final y_i_start = {0.9}, + final T_adsorpt_start = 298.15, + final no_components = 2, + final no_coefficients = 5, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - (T_adsorpt / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / T_adsorpt - 1)) + "Second coefficient of the Toth isotherm model"; + c[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2 / T_ref_CO2 * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = -Q_CO2 / (Modelica.Constants.R * T_adsorpt^2) * c[2,1] + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = alpha_CO2 * T_ref_CO2 / T_adsorpt^2 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 0 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = 0 + "Fivth coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = 0 + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = 0 + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt+dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt+dT) - 1)) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt+dT)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2 * Modelica.Math.exp(chi_CO2 * (1 - ((T_adsorpt-dT) / T_ref_CO2))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = b_ref_CO2 * Modelica.Math.exp(Q_CO2 / + (Modelica.Constants.R * T_ref_CO2) *(T_ref_CO2 / (T_adsorpt-dT) - 1)) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = t_ref_CO2 + alpha_CO2 * (1 - T_ref_CO2 / (T_adsorpt-dT)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = gamma_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = beta_CO2 + "Fivth coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = c_H2O + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = k_H2O + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + July 31, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth-GAB isotherm +model. Additionally, the implemented functions for the partial derivarives 'dx_dp,' +'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2b8e3203008ddfa4252c674d108095748853a557 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers; +package TothGAB_StampiBombelli "Models to test and varify functions of the Toth-GAB isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Toth-GAB +isotherm model. The test models check the implementation of the functions and enable +verification of the function behavior. Four test models are implemented, in which the +pressure, mole fractions of independent components in the gas or vapor phase, and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end TothGAB_StampiBombelli; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/package.order new file mode 100644 index 0000000000000000000000000000000000000000..2df476354b8eaa401829535ab36ad77b4471614c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/TothGAB_StampiBombelli/package.order @@ -0,0 +1,4 @@ +Test_changing_pressure +Test_changing_mole_fractions +Test_changing_temperature +Test_changing_everything diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_everything.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_everything.mo new file mode 100644 index 0000000000000000000000000000000000000000..886d514362343b9271964a1a861d091305fa1990 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_everything.mo @@ -0,0 +1,278 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.WeightedAverageDualSiteTothGAB; +model Test_changing_everything + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Changing pressure, independent mole fractions, and temperature" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2_dry = 4.86 * 0.0440098 + "Saturation uptake at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2_dry(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature + under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2_dry(unit="1/Pa") = 2.85e-21 + "Toth coefficient at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_CO2_dry(unit="J/mol") = -117798 + "Parameter describing the isosteric enthalpy of adsorption under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2_dry(unit="1") = 0.209 + "Toth exponent at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2_dry(unit="1") = 0.5823 + "Parameter describing the change of the Toth exponent with temperature under + dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2_dry = 298.15 + "Reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + + parameter Real C_CO2(unit="kg/kg") = 1.532 * 0.018015267 + "Critical water uptake" + annotation (Dialog(tab="General", group="Parameters")); + + parameter SorpLib.Units.Uptake x_ref_CO2_wet = 9.035 * 0.0440098 + "Saturation uptake at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2_wet(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature + under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2_wet(unit="1/Pa") = 1.230e-18 + "Toth coefficient at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_CO2_wet(unit="J/mol") = -203687 + "Parameter describing the isosteric enthalpy of adsorption under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2_wet(unit="1") = 0.053 + "Toth exponent at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2_wet(unit="1") = 0.053 + "Parameter describing the change of the Toth exponent with temperature under + wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2_wet = 298.15 + "Reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 3.63 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_H2O(unit="J/mol") = 47110 + "First parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D_H2O(unit="1/K") = 0.023744 + "Second parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F_H2O(unit="J/mol") = 57706 + "First parameter of the adsorption enthalpy of the layers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G_H2O(unit="J/(mol.K)") = -47.814 + "Second parameter of the adsorption enthalpy of the ayers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I_H2O(unit="J/mol") = 57220 + "First parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real J_H2O(unit="J/(mol.K)") = -44.38 + "Second parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = (1e5-12349)/100, + final y_i_der = {0}, + final T_adsorpt_der = 75/100, + final p_adsorpt_start = 1, + final y_i_start = {1-0.5*12349/1e5}, + final T_adsorpt_start = 273.15+25, + final no_components = 2, + final no_coefficients = 7, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - (T_adsorpt / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * T_adsorpt)) + "Second coefficient of the Toth isotherm model"; + c[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - (T_adsorpt / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * T_adsorpt)) + "Sixth coefficient of the Toth isotherm model"; + c[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / T_adsorpt) + "Seventh coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * T_adsorpt)) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * T_adsorpt) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2_dry / T_ref_CO2_dry * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = DH_CO2_dry * c[2,1] / (Modelica.Constants.R * T_adsorpt^2) + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = alpha_CO2_dry * T_ref_CO2_dry / T_adsorpt^2 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 0 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = -chi_CO2_wet / T_ref_CO2_wet * c[5,1] + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = DH_CO2_wet * c[6,1] / (Modelica.Constants.R * T_adsorpt^2) + "Sixth coefficient of the Toth isotherm model"; + dc_dT[7,1] = alpha_CO2_wet * T_ref_CO2_wet / T_adsorpt^2 + "Seventh coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -((D_H2O*T_adsorpt - 1) * exp(D_H2O*T_adsorpt) - I_H2O + C_H2O) / + (Modelica.Constants.R*T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = (I_H2O - F_H2O) / (Modelica.Constants.R*T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + dc_dT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - ((T_adsorpt+dT) / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * (T_adsorpt+dT))) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / (T_adsorpt+dT)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - ((T_adsorpt+dT) / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * (T_adsorpt+dT))) + "Sixth coefficient of the Toth isotherm model"; + c_pdT[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / (T_adsorpt+dT)) + "Seventh coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt+dT))) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt+dT)) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_pdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - ((T_adsorpt-dT) / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * (T_adsorpt-dT))) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / (T_adsorpt-dT)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - ((T_adsorpt-dT) / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * (T_adsorpt-dT))) + "Sixth coefficient of the Toth isotherm model"; + c_mdT[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / (T_adsorpt-dT)) + "Seventh coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt-dT))) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt-dT)) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_mdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 2, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the weighted-average dual site +Toth-GAB isotherm model. Additionally, the implemented functions for the partial +derivarives 'dx_dp,' 'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure, independent mole fractions, and +temperature with time. To see the behavior of all functions, plot the variables +<i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and +<i>dx_adsorpt_dT_adsorpt</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_everything; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_mole_fractions.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_mole_fractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..b9dfc2f7813ff1c0c75cbf102ffd73cc233558ee --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_mole_fractions.mo @@ -0,0 +1,278 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.WeightedAverageDualSiteTothGAB; +model Test_changing_mole_fractions + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Changing independent mole fractions" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2_dry = 4.86 * 0.0440098 + "Saturation uptake at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2_dry(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature + under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2_dry(unit="1/Pa") = 2.85e-21 + "Toth coefficient at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_CO2_dry(unit="J/mol") = -117798 + "Parameter describing the isosteric enthalpy of adsorption under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2_dry(unit="1") = 0.209 + "Toth exponent at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2_dry(unit="1") = 0.5823 + "Parameter describing the change of the Toth exponent with temperature under + dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2_dry = 298.15 + "Reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + + parameter Real C_CO2(unit="kg/kg") = 1.532 * 0.018015267 + "Critical water uptake" + annotation (Dialog(tab="General", group="Parameters")); + + parameter SorpLib.Units.Uptake x_ref_CO2_wet = 9.035 * 0.0440098 + "Saturation uptake at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2_wet(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature + under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2_wet(unit="1/Pa") = 1.230e-18 + "Toth coefficient at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_CO2_wet(unit="J/mol") = -203687 + "Parameter describing the isosteric enthalpy of adsorption under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2_wet(unit="1") = 0.053 + "Toth exponent at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2_wet(unit="1") = 0.053 + "Parameter describing the change of the Toth exponent with temperature under + wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2_wet = 298.15 + "Reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 3.63 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_H2O(unit="J/mol") = 47110 + "First parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D_H2O(unit="1/K") = 0.023744 + "Second parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F_H2O(unit="J/mol") = 57706 + "First parameter of the adsorption enthalpy of the layers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G_H2O(unit="J/(mol.K)") = -47.814 + "Second parameter of the adsorption enthalpy of the ayers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I_H2O(unit="J/mol") = 57220 + "First parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real J_H2O(unit="J/(mol.K)") = -44.38 + "Second parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0.96/100}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 25000, + final y_i_start = {0.02}, + final T_adsorpt_start = 273.15+75, + final no_components = 2, + final no_coefficients = 7, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - (T_adsorpt / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * T_adsorpt)) + "Second coefficient of the Toth isotherm model"; + c[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - (T_adsorpt / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * T_adsorpt)) + "Sixth coefficient of the Toth isotherm model"; + c[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / T_adsorpt) + "Seventh coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * T_adsorpt)) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * T_adsorpt) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2_dry / T_ref_CO2_dry * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = DH_CO2_dry * c[2,1] / (Modelica.Constants.R * T_adsorpt^2) + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = alpha_CO2_dry * T_ref_CO2_dry / T_adsorpt^2 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 0 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = -chi_CO2_wet / T_ref_CO2_wet * c[5,1] + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = DH_CO2_wet * c[6,1] / (Modelica.Constants.R * T_adsorpt^2) + "Sixth coefficient of the Toth isotherm model"; + dc_dT[7,1] = alpha_CO2_wet * T_ref_CO2_wet / T_adsorpt^2 + "Seventh coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -((D_H2O*T_adsorpt - 1) * exp(D_H2O*T_adsorpt) - I_H2O + C_H2O) / + (Modelica.Constants.R*T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = (I_H2O - F_H2O) / (Modelica.Constants.R*T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + dc_dT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - ((T_adsorpt+dT) / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * (T_adsorpt+dT))) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / (T_adsorpt+dT)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - ((T_adsorpt+dT) / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * (T_adsorpt+dT))) + "Sixth coefficient of the Toth isotherm model"; + c_pdT[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / (T_adsorpt+dT)) + "Seventh coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt+dT))) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt+dT)) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_pdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - ((T_adsorpt-dT) / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * (T_adsorpt-dT))) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / (T_adsorpt-dT)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - ((T_adsorpt-dT) / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * (T_adsorpt-dT))) + "Sixth coefficient of the Toth isotherm model"; + c_mdT[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / (T_adsorpt-dT)) + "Seventh coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt-dT))) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt-dT)) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_mdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 2, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the weighted-average dual site +Toth-GAB isotherm model. Additionally, the implemented functions for the partial +derivarives 'dx_dp,' 'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the independent mole fractions with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> +over the variable <i>p_adsorpt</i>. The simulation time is correctly preset +(Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_mole_fractions; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..4d98ed2261b36044c00b69c9ad53363d7ae4a833 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_pressure.mo @@ -0,0 +1,277 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.WeightedAverageDualSiteTothGAB; +model Test_changing_pressure + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Changing pressure" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2_dry = 4.86 * 0.0440098 + "Saturation uptake at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2_dry(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature + under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2_dry(unit="1/Pa") = 2.85e-21 + "Toth coefficient at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_CO2_dry(unit="J/mol") = -117798 + "Parameter describing the isosteric enthalpy of adsorption under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2_dry(unit="1") = 0.209 + "Toth exponent at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2_dry(unit="1") = 0.5823 + "Parameter describing the change of the Toth exponent with temperature under + dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2_dry = 298.15 + "Reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + + parameter Real C_CO2(unit="kg/kg") = 1.532 * 0.018015267 + "Critical water uptake" + annotation (Dialog(tab="General", group="Parameters")); + + parameter SorpLib.Units.Uptake x_ref_CO2_wet = 9.035 * 0.0440098 + "Saturation uptake at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2_wet(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature + under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2_wet(unit="1/Pa") = 1.230e-18 + "Toth coefficient at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_CO2_wet(unit="J/mol") = -203687 + "Parameter describing the isosteric enthalpy of adsorption under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2_wet(unit="1") = 0.053 + "Toth exponent at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2_wet(unit="1") = 0.053 + "Parameter describing the change of the Toth exponent with temperature under + wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2_wet = 298.15 + "Reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 3.63 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_H2O(unit="J/mol") = 47110 + "First parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D_H2O(unit="1/K") = 0.023744 + "Second parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F_H2O(unit="J/mol") = 57706 + "First parameter of the adsorption enthalpy of the layers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G_H2O(unit="J/(mol.K)") = -47.814 + "Second parameter of the adsorption enthalpy of the ayers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I_H2O(unit="J/mol") = 57220 + "First parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real J_H2O(unit="J/(mol.K)") = -44.38 + "Second parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = (0.6e5-12349)/100, + final y_i_der = {0}, + final T_adsorpt_der = 0, + final p_adsorpt_start = 12349, + final y_i_start = {1-0.55*12349/0.6e5}, + final T_adsorpt_start = 273.15+50, + final no_components = 2, + final no_coefficients = 7, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - (T_adsorpt / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * T_adsorpt)) + "Second coefficient of the Toth isotherm model"; + c[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - (T_adsorpt / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * T_adsorpt)) + "Sixth coefficient of the Toth isotherm model"; + c[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / T_adsorpt) + "Seventh coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * T_adsorpt)) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * T_adsorpt) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2_dry / T_ref_CO2_dry * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = DH_CO2_dry * c[2,1] / (Modelica.Constants.R * T_adsorpt^2) + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = alpha_CO2_dry * T_ref_CO2_dry / T_adsorpt^2 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 0 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = -chi_CO2_wet / T_ref_CO2_wet * c[5,1] + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = DH_CO2_wet * c[6,1] / (Modelica.Constants.R * T_adsorpt^2) + "Sixth coefficient of the Toth isotherm model"; + dc_dT[7,1] = alpha_CO2_wet * T_ref_CO2_wet / T_adsorpt^2 + "Seventh coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -((D_H2O*T_adsorpt - 1) * exp(D_H2O*T_adsorpt) - I_H2O + C_H2O) / + (Modelica.Constants.R*T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = (I_H2O - F_H2O) / (Modelica.Constants.R*T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + dc_dT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - ((T_adsorpt+dT) / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * (T_adsorpt+dT))) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / (T_adsorpt+dT)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - ((T_adsorpt+dT) / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * (T_adsorpt+dT))) + "Sixth coefficient of the Toth isotherm model"; + c_pdT[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / (T_adsorpt+dT)) + "Seventh coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt+dT))) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt+dT)) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_pdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - ((T_adsorpt-dT) / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * (T_adsorpt-dT))) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / (T_adsorpt-dT)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - ((T_adsorpt-dT) / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * (T_adsorpt-dT))) + "Sixth coefficient of the Toth isotherm model"; + c_mdT[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / (T_adsorpt-dT)) + "Seventh coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt-dT))) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt-dT)) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_mdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 2, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the weighted-average dual site +Toth-GAB isotherm model. Additionally, the implemented functions for the partial +derivarives 'dx_dp,' 'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..347e50761dbe1f334d4fadd9e800edda4941041c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/Test_changing_temperature.mo @@ -0,0 +1,277 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers.WeightedAverageDualSiteTothGAB; +model Test_changing_temperature + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Changing temperature" + + // + // Definition of parameters of component 1 (i.e., CO2) + // + parameter SorpLib.Units.Uptake x_ref_CO2_dry = 4.86 * 0.0440098 + "Saturation uptake at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2_dry(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature + under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2_dry(unit="1/Pa") = 2.85e-21 + "Toth coefficient at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_CO2_dry(unit="J/mol") = -117798 + "Parameter describing the isosteric enthalpy of adsorption under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2_dry(unit="1") = 0.209 + "Toth exponent at reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2_dry(unit="1") = 0.5823 + "Parameter describing the change of the Toth exponent with temperature under + dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2_dry = 298.15 + "Reference temperature under dry conditions" + annotation (Dialog(tab="General", group="Parameters")); + + parameter Real C_CO2(unit="kg/kg") = 1.532 * 0.018015267 + "Critical water uptake" + annotation (Dialog(tab="General", group="Parameters")); + + parameter SorpLib.Units.Uptake x_ref_CO2_wet = 9.035 * 0.0440098 + "Saturation uptake at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi_CO2_wet(unit="1") = 0 + "Parameter describing the change of the saturation uptake with temperature + under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref_CO2_wet(unit="1/Pa") = 1.230e-18 + "Toth coefficient at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real DH_CO2_wet(unit="J/mol") = -203687 + "Parameter describing the isosteric enthalpy of adsorption under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref_CO2_wet(unit="1") = 0.053 + "Toth exponent at reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha_CO2_wet(unit="1") = 0.053 + "Parameter describing the change of the Toth exponent with temperature under + wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_CO2_wet = 298.15 + "Reference temperature under wet conditions" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of parameters of component 2 (i.e., H20) + // + parameter SorpLib.Units.Uptake x_mon_H2O = 3.63 * 0.018015267 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_H2O(unit="J/mol") = 47110 + "First parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D_H2O(unit="1/K") = 0.023744 + "Second parameter of the adsorption enthalpy of the first layer" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F_H2O(unit="J/mol") = 57706 + "First parameter of the adsorption enthalpy of the layers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G_H2O(unit="J/(mol.K)") = -47.814 + "Second parameter of the adsorption enthalpy of the ayers 2 to 9" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I_H2O(unit="J/mol") = 57220 + "First parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real J_H2O(unit="J/(mol.K)") = -44.38 + "Second parameter of the enthalpy of vaporization" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref_H2O = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestMulti( + final p_adsorpt_der = 0, + final y_i_der = {0}, + final T_adsorpt_der = 50/100, + final p_adsorpt_start = 0.6e5, + final y_i_start = {1-0.5*12349/0.6e5}, + final T_adsorpt_start = 273.15+50, + final no_components = 2, + final no_coefficients = 7, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB, + p_threshold_min = 0); + +equation + // + // Coefficients of the isotherm model + // + c[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - (T_adsorpt / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * T_adsorpt)) + "Second coefficient of the Toth isotherm model"; + c[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / T_adsorpt) + "Third coefficient of the Toth isotherm model"; + c[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - (T_adsorpt / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * T_adsorpt)) + "Sixth coefficient of the Toth isotherm model"; + c[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / T_adsorpt) + "Seventh coefficient of the Toth isotherm model"; + + c[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + c[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * T_adsorpt)) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Third coefficient of the GAB isotherm model"; + c[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * T_adsorpt) - + (J_H2O * T_adsorpt + I_H2O)) / (Modelica.Constants.R * T_adsorpt)) + "Fourth coefficient of the GAB isotherm model"; + c[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1,1] = -chi_CO2_dry / T_ref_CO2_dry * c[1,1] + "First coefficient of the Toth isotherm model"; + dc_dT[2,1] = DH_CO2_dry * c[2,1] / (Modelica.Constants.R * T_adsorpt^2) + "Second coefficient of the Toth isotherm model"; + dc_dT[3,1] = alpha_CO2_dry * T_ref_CO2_dry / T_adsorpt^2 + "Third coefficient of the Toth isotherm model"; + dc_dT[4,1] = 0 + "Fourth coefficient of the Toth isotherm model"; + dc_dT[5,1] = -chi_CO2_wet / T_ref_CO2_wet * c[5,1] + "Fivth coefficient of the Toth isotherm model"; + dc_dT[6,1] = DH_CO2_wet * c[6,1] / (Modelica.Constants.R * T_adsorpt^2) + "Sixth coefficient of the Toth isotherm model"; + dc_dT[7,1] = alpha_CO2_wet * T_ref_CO2_wet / T_adsorpt^2 + "Seventh coefficient of the Toth isotherm model"; + + dc_dT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "First coefficient of the GAB isotherm model"; + dc_dT[2,2] = 0 + "Second coefficient of the GAB isotherm model"; + dc_dT[3,2] = -((D_H2O*T_adsorpt - 1) * exp(D_H2O*T_adsorpt) - I_H2O + C_H2O) / + (Modelica.Constants.R*T_adsorpt^2) * c[3,2] + "Third coefficient of the GAB isotherm model"; + dc_dT[4,2] = (I_H2O - F_H2O) / (Modelica.Constants.R*T_adsorpt^2) * c[4,2] + "Fourth coefficient of the GAB isotherm model"; + dc_dT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + dc_dT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + dc_dT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T + dT K + // + c_pdT[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - ((T_adsorpt+dT) / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c_pdT[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * (T_adsorpt+dT))) + "Second coefficient of the Toth isotherm model"; + c_pdT[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / (T_adsorpt+dT)) + "Third coefficient of the Toth isotherm model"; + c_pdT[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_pdT[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - ((T_adsorpt+dT) / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c_pdT[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * (T_adsorpt+dT))) + "Sixth coefficient of the Toth isotherm model"; + c_pdT[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / (T_adsorpt+dT)) + "Seventh coefficient of the Toth isotherm model"; + + c_pdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "First coefficient of the GAB isotherm model"; + c_pdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_pdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt+dT))) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Third coefficient of the GAB isotherm model"; + c_pdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt+dT)) - + (J_H2O * (T_adsorpt+dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt+dT))) + "Fourth coefficient of the GAB isotherm model"; + c_pdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_pdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_pdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Coefficients of the isotherm model: T - dT K + // + c_mdT[1,1] = x_ref_CO2_dry * + Modelica.Math.exp(chi_CO2_dry * (1 - ((T_adsorpt-dT) / T_ref_CO2_dry))) + "First coefficient of the Toth isotherm model"; + c_mdT[2,1] = b_ref_CO2_dry * + Modelica.Math.exp(-DH_CO2_dry / (Modelica.Constants.R * (T_adsorpt-dT))) + "Second coefficient of the Toth isotherm model"; + c_mdT[3,1] = t_ref_CO2_dry + alpha_CO2_dry * (1 - T_ref_CO2_dry / (T_adsorpt-dT)) + "Third coefficient of the Toth isotherm model"; + c_mdT[4,1] = C_CO2 + "Fourth coefficient of the Toth isotherm model"; + c_mdT[5,1] = x_ref_CO2_wet * + Modelica.Math.exp(chi_CO2_wet * (1 - ((T_adsorpt-dT) / T_ref_CO2_wet))) + "Fivth coefficient of the Toth isotherm model"; + c_mdT[6,1] = b_ref_CO2_wet * + Modelica.Math.exp(-DH_CO2_wet / (Modelica.Constants.R * (T_adsorpt-dT))) + "Sixth coefficient of the Toth isotherm model"; + c_mdT[7,1] = t_ref_CO2_wet + alpha_CO2_wet * (1 - T_ref_CO2_wet / (T_adsorpt-dT)) + "Seventh coefficient of the Toth isotherm model"; + + c_mdT[1,2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "First coefficient of the GAB isotherm model"; + c_mdT[2,2] = x_mon_H2O + "Second coefficient of the GAB isotherm model"; + c_mdT[3,2] = Modelica.Math.exp(((C_H2O - Modelica.Math.exp(D_H2O * (T_adsorpt-dT))) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Third coefficient of the GAB isotherm model"; + c_mdT[4,2] = Modelica.Math.exp(((F_H2O + G_H2O * (T_adsorpt-dT)) - + (J_H2O * (T_adsorpt-dT) + I_H2O)) / (Modelica.Constants.R * (T_adsorpt-dT))) + "Fourth coefficient of the GAB isotherm model"; + c_mdT[5,2] = 0 + "Fivth coefficient of the GAB isotherm model"; + c_mdT[6,2] = 0 + "Sixth coefficient of the GAB isotherm model"; + c_mdT[7,2] = 0 + "Seventh coefficient of the GAB isotherm model"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + August 2, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the weighted-average dual site +Toth-GAB isotherm model. Additionally, the implemented functions for the partial +derivarives 'dx_dp,' 'dx_dy,' and 'dx_dT' are checked via numerical calculations. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dy_i</i>, and <i>dx_adsorpt_dT_adsorpt</i> over the variable +<i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9eb74bb1f78bfc556c22f576cf9a33753902281a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/package.mo @@ -0,0 +1,22 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Testers; +package WeightedAverageDualSiteTothGAB "Models to test and varify functions of the weighted-average dual site Toth-GAB isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the weighted-average +dual site Toth-GAB isotherm model. The test models check the implementation of the +functions and enable verification of the function behavior. Four test models are +implemented, in which the pressure, mole fractions of independent components in the +gas or vapor phase, and temperature change over time. In addition, the test models +demonstrate the functions' general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + August 2, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end WeightedAverageDualSiteTothGAB; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/package.order new file mode 100644 index 0000000000000000000000000000000000000000..2df476354b8eaa401829535ab36ad77b4471614c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/WeightedAverageDualSiteTothGAB/package.order @@ -0,0 +1,4 @@ +Test_changing_pressure +Test_changing_mole_fractions +Test_changing_temperature +Test_changing_everything diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..15bec77c67fbf3f0bb05abaeaad8888dc4b99e1f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents; +package Testers "This package contains test models to check and varify multi-component isotherm models" +extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented isotherm models. Each +isotherm model has its test models saved in a separate package. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..63b2987bf2ae3884a3693f22be9a6aa4453f2595 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Testers/package.order @@ -0,0 +1,9 @@ +Langmuir +Sips +Toth +TothGAB_StampiBombelli +TothGAB_Schellevis +MechanisticTothGAB +WeightedAverageDualSiteTothGAB +IAST_N2 +IAST_N3 diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/calc_p_i_num_i_den_i.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/calc_p_i_num_i_den_i.mo new file mode 100644 index 0000000000000000000000000000000000000000..261620fe1a659647484a03b9f60dcf104ac9b186 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/calc_p_i_num_i_den_i.mo @@ -0,0 +1,82 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.Internals; +function calc_p_i_num_i_den_i + "Extended Toth isotherm model: Corrected partial pressures, numerators, denominators of the isotherm model" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real[:,:] c + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_threshold_min = 0 + "Threshold for partial pressures of all components: If a partial pressure is + below the threshold, its value is set to the threshold" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[size(c,2)] p_i_regulated + "Regulated equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Real[size(c,2)] den_i + "Individual denominator for each component of the isotherm model" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real den_tmp + "Identical temporary denominator for all components of the isotherm model"; + +algorithm + den_tmp := 1 + "Start value of the temporary denominator"; + + for ind_comp in 1:size(c,2) loop + p_i_regulated[ind_comp] := max(p_i[ind_comp], p_threshold_min) + "Limiter of partial pressures to increase numerical stability"; + + num_i[ind_comp] := c[1,ind_comp] * c[2,ind_comp] * p_i_regulated[ind_comp] + "Individual numerators"; + + den_tmp := den_tmp + (c[2,ind_comp] * p_i_regulated[ind_comp]) ^ c[3,ind_comp] + "Identical temporary denominator"; + end for; + + for ind_comp in 1:size(c,2) loop + den_i[ind_comp] := den_tmp ^ (1/c[3,ind_comp]) + "Individual denominators"; + end for; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function regulates the equilibrium pressures <i>p_i</i> (i.e., partial +pressures) so that they are equal or greater than <i>p_threshold_min</i>. Further, +this function calculates the numerators <i>num_i</i> and denominators <i>den_i</i> +of the extended Toth isotherm model. For full details of the extended Toth +isotherm mode, check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + November 8, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end calc_p_i_num_i_den_i; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/p_i_xT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/p_i_xT.mo new file mode 100644 index 0000000000000000000000000000000000000000..467d2e998bc56e15d44e2531e59d4daf9c4cf07a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/p_i_xT.mo @@ -0,0 +1,86 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.Internals; +function p_i_xT + "Extended Toth isotherm model: Partial pressures as function of uptakes and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real[size(c,2), size(c,2)] A + "Matrix A of A*zz = -x_adsorpt"; + Real[size(c,2)] zz + "Vector zz of A*zz = -x_adsorpt (i.e., zz = second substitution)"; + Real[size(c,2)] z + "Vector z (i.e., z = first substitution)"; + + SorpLib.Units.Uptake[size(c,2)] x_adsorpt_pow_c3 + "Equilibrium uptakes of the adsorpt phase to the power of coefficient c3"; + +algorithm + // + // Set up matrix A and solve system of linear equations: + // + // To calculate the invesere function of the extended Toth isotherm regarding + // the equilibrium pressure and mole fractions of the independent components of + // the gas or vapor phase, the term ' c[2,ind] * p_i[ind]' is substituted by 'z,' + // and the term 'z ^ c[3,ind] is substituted by 'zz.' Thus, a system of linear + // equations is created that canbe solved. Re-substitution allows to calculate + // partial pressures p_i and,thus, the equilibrium pressure and mole fractions. + // + for ind_comp in 1:size(c,2) loop + x_adsorpt_pow_c3[ind_comp] := x_adsorpt[ind_comp] ^ c[3, ind_comp] + "First, calculate equilibrium uptakes of the adsorpt phase to the power of + coefficient c3"; + A[ind_comp,:] := fill(x_adsorpt_pow_c3[ind_comp], size(c,2)) + "Second, fill row with correct uptake"; + A[ind_comp,ind_comp] := x_adsorpt_pow_c3[ind_comp] - c[1,ind_comp] ^ c[3,ind_comp] + "Third, correct diagonale"; + end for; + + zz := Modelica.Math.Matrices.solve(A, -1 .* x_adsorpt_pow_c3) + "Fourth, solve the system of linear equations"; + + for ind_comp in 1:size(c,2) loop + z[ind_comp] := zz[ind_comp] ^ (1/c[3, ind_comp]) + "Re-substituate values and consider threshold if necessary"; + p_i[ind_comp] := max(z[ind_comp] / c[2,ind_comp], p_threshold_min) + "Re-substituate values and consider threshold if necessary"; + end for; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium pressures <i>p_i</i> (i.e., partial +pressures) as function of the equilibrium uptakes <i>x_adsorpt</i> and the +equilibrium temperature <i>T_adsorpt</i>. Thus, this function is a inverse of the +function 'x_pyT.' For full details of the original function 'x_pyT,' check the +documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + November 8, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end p_i_xT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a133d03ff6f3b07e050301ffb97a4afca28b2206 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth; +package Internals "Internal functions used to avoid redundancy" + extends Modelica.Icons.InternalPackage; + + annotation (Documentation(info="<html> +<p> +This package contains functions used for various functions of the extended Sips isotherm +model. Thus, redundancy of code shall be avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + November 9, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Internals; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c25a70b729113de56f4b34924d20b1a78ece64bd --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/Internals/package.order @@ -0,0 +1,2 @@ +calc_p_i_num_i_den_i +p_i_xT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d9b24491aab9262e8c8974b07ccea890d6f22351 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/package.mo @@ -0,0 +1,457 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents; +package Toth "Package containing all functions regarding the extended Toth isotherm" + extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponents; + + // + // Internal package + // + redeclare final function extends x_pyT + "Extended Toth isotherm model: Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real[size(c,2)] den_i + "Individual denominator for each component of the isotherm model"; + + algorithm + (p_i,num_i,den_i) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.Internals.calc_p_i_num_i_den_i( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + x_adsorpt := num_i ./ den_i + "Calculate equilibrium uptakes of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end x_pyT; + + redeclare final function extends p_xyT + "Extended Toth isotherm model: Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.Internals.p_i_xT( + x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min) + "Partial pressures"; + + p_adsorpt := sum(p_i) + "Equilibrium pressure"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end p_xyT; + + redeclare final function extends y_pxT + "Extended Toth isotherm model: Mole fractions of independent gas phase components as function of uptakes, pressure, and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.Internals.p_i_xT( + x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min) + "Partial pressures"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / max(p_adsorpt, p_threshold_min) + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance)), + Documentation(info="<html> +<p> +This function is the inverse function of the function 'x_pyT.' For full details +of the original function 'x_pyT,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.x_pyT</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 8, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); + end y_pxT; + + redeclare final function extends py_xT + "Extended Toth isotherm model: Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.Internals.p_i_xT( + x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min) + "Partial pressures"; + + p_adsorpt := max(sum(p_i), p_threshold_min) + "Equilibrium pressure"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / p_adsorpt + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + redeclare final function extends dx_dp + "Extended Toth isotherm model: Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real[size(c,2)] den_i + "Individual denominator for each component of the isotherm model"; + + Real[size(c,2)] dnum_i_dp_adsorpt + "Partial derivatives of the numerators w.r.t. the equilibrium pressure"; + Real[size(c,2)] dden_i_dp_adsorpt + "Partial derivatives of the denominators w.r.t. the equilbrium pressure"; + + Real den_tmp + "Identical temporary denominator for all components of the isotherm model"; + Real dden_tmp_dp_adsorpt + "Identical temporary partial derivative of the denominator w.r.t. the + equilbrium pressure for all components of the isotherm model"; + + algorithm + (p_i,num_i,den_i) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.Internals.calc_p_i_num_i_den_i( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + // + // Calculate partial derivatives + // + den_tmp := 1 + "Start value of the temporary denominator"; + dden_tmp_dp_adsorpt := 0 + "Start value of the temporary derivative of the denominator w.r.t. + equilbrium pressure"; + + for ind_comp in 1:size(c,2) loop + dnum_i_dp_adsorpt[ind_comp] := c[1,ind_comp] * c[2,ind_comp] * y_i_[ind_comp] + "Partial derivatives of numerators w.r.t. equilibrium pressure"; + + den_tmp := den_tmp + (c[2,ind_comp] * p_i[ind_comp]) ^ c[3,ind_comp] + "Identical temporary denominator"; + + dden_tmp_dp_adsorpt := dden_tmp_dp_adsorpt + c[3,ind_comp] * + (c[2,ind_comp] * p_i[ind_comp]) ^ c[3,ind_comp] / p_i[ind_comp] * y_i_[ind_comp] + "Identical partial derivative of the denominator w.r.t. equilibrium + pressure for all components"; + end for; + + for ind_comp in 1:size(c,2) loop + dden_i_dp_adsorpt[ind_comp] := 1 / c[3,ind_comp] * + den_tmp ^ (1 / c[3,ind_comp] - 1) * dden_tmp_dp_adsorpt + "Partial derivatives of the denominators w.r.t. the equilbrium pressure"; + end for; + + // + // Calculate derivatives of loadings w.r.t. equilibrium pressure + // + dx_adsorpt_dp_adsorpt := + (dnum_i_dp_adsorpt .* den_i .- num_i .* dden_i_dp_adsorpt) ./ den_i.^2 + "Calculation of the partial derivatives of the equilibrium uptakes w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + end dx_dp; + + redeclare final function extends dx_dy + "Extended Toth isotherm model: Partial derivative of uptakes w.r.t. mole fractions of independent gas phase components at constant pressure and temperature" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real[size(c,2)] den_i + "Individual denominator for each component of the isotherm model"; + + Real[size(c,2),size(c,2)-1] dnum_i_dy_i + "Partial derivatives of the numerators w.r.t. the mole fractions of independent + gas phase components"; + Real[size(c,2),size(c,2)-1] dden_i_dy_i + "Partial derivatives of the denominators w.r.t. the mole fractions of independent + gas phase components"; + + Real den_tmp = 1 + "Identical temporary denominator for all components of the isotherm model"; + Real[size(c,2)-1] dden_tmp_dy_i + "Temporary partial derivatives of the temporary denominator w.r.t. the + independent gas phase components"; + + algorithm + (p_i,num_i,den_i) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.Internals.calc_p_i_num_i_den_i( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + // + // Calculate partial derivatives of numerators, which varies with components and + // mole fractions of independent components + // + dnum_i_dy_i:=zeros(size(c, 2), size(c, 2) - 1) + "Partial derivatives of the numerators w.r.t. the mole fractions of independent + gas phase components"; + + for ind_comp in 1:size(c,2) loop + if ind_comp < size(c,2) then + // Partial derivatives of independent components + // + dnum_i_dy_i[ind_comp,ind_comp] := c[1,ind_comp] * c[2,ind_comp] * p_adsorpt + "Partial derivatives of numerators w.r.t. the mole fractions of independent + gas phase components"; + + else + // Partial derivatives of dependent component + // + for ind_y_i in 1:size(c,2)-1 loop + dnum_i_dy_i[ind_comp,ind_y_i] := c[1,ind_comp] * c[2,ind_comp] * (-p_adsorpt) + "Partial derivatives of numerators w.r.t. the mole fractions of independent + gas phase components"; + + end for; + end if; + end for; + + // + // Calculate partial derivatives of the denominator, which varies with + // components and mole fractions of independent components + // + dden_i_dy_i:=zeros(size(c, 2), size(c, 2) - 1) + "Partial derivatives of the denominators w.r.t. the mole fractions of independent + gas phase components"; + dden_tmp_dy_i:=zeros(size(c, 2) - 1) + "Temporary partial derivatives of the temporary denominator w.r.t. the + independent gas phase components"; + + for ind_comp in 1:size(c,2) loop + den_tmp := den_tmp + (c[2,ind_comp] * p_i[ind_comp]) ^ c[3,ind_comp] + "Identical temporary denominator"; + end for; + + for ind_y_i in 1:size(c,2)-1 loop + dden_tmp_dy_i[ind_y_i] := c[3,ind_y_i] * (c[2,ind_y_i] * p_i[ind_y_i]) ^ + (c[3,ind_y_i] - 1) * c[2,ind_y_i] * p_adsorpt + + c[3,size(c,2)] * (c[2,size(c,2)] * p_i[size(c,2)]) ^ + (c[3,size(c,2)] - 1) * c[2,size(c,2)] * (-p_adsorpt) + "Temporary partial derivatives of the temporary denominator w.r.t. the + independent gas phase components"; + end for; + + for ind_comp in 1:size(c,2) loop + for ind_y_i in 1:size(c,2)-1 loop + dden_i_dy_i[ind_comp,ind_y_i] := 1/c[3,ind_comp] * den_tmp ^ + (1/c[3,ind_comp] - 1) * dden_tmp_dy_i[ind_y_i] + "Partial derivatives of the denominators w.r.t. the mole fractions of + independent gas phase components"; + end for; + end for; + + // + // Calculate partial derivatives of uptakes w.r.t. mole fractions of independent + // gas phase components + // + for ind_comp in 1:size(c,2) loop + for ind_y_i in 1:size(c,2)-1 loop + dx_adsorpt_dy_i[ind_comp,ind_y_i] := + (dnum_i_dy_i[ind_comp,ind_y_i] * den_i[ind_comp] - + num_i[ind_comp] * dden_i_dy_i[ind_comp,ind_y_i]) ./ den_i[ind_comp]^2 + "Partial derivatives of the uptakes w.r.t. the mole fractions of independent + gas phase components at constant pressure and temperature"; + end for; + end for; + end dx_dy; + + redeclare final function extends dx_dT + "Extended Toth isotherm model: Partial derivative of uptakes w.r.t. temperature at constant pressure and mole fractions" + + // + // Definition of variables + // +protected + Real[size(c,2)] num_i + "Individual numerator for each component of the isotherm model"; + Real[size(c,2)] den_i + "Individual denominator for each component of the isotherm model"; + + Real[size(c,2)] dnum_i_dT_adsorpt + "Derivatives of the numerators w.r.t. the equilibrium temperature"; + Real[size(c,2)] dden_i_dT_adsorpt + "Derivatives of the denominators w.r.t. the equilbrium temperature"; + + Real den_tmp + "Identical temporary denominator for all components of the isotherm model"; + Real dden_tmp_dT_adsorpt + "Identical temporary partial derivative of the denominator w.r.t. the + equilbrium temperature for all components of the isotherm model"; + + algorithm + (p_i,num_i,den_i) := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.Toth.Internals.calc_p_i_num_i_den_i( + p_i=p_i, c=c, p_threshold_min=p_threshold_min) + "Regulated partial pressures and isotherm models' numerators and denominator"; + + // + // Calculate partial derivatives + // + den_tmp := 1 + "Start value of the temporary denominator"; + dden_tmp_dT_adsorpt := 0 + "Start value of the temporary derivative of the denominator w.r.t. + equilbrium pressure"; + + for ind_comp in 1:size(c,2) loop + den_tmp := den_tmp + (c[2,ind_comp] * p_i[ind_comp]) ^ c[3,ind_comp] + "Identical temporary denominator"; + + dden_tmp_dT_adsorpt := dden_tmp_dT_adsorpt + + (c[3,ind_comp] / c[2,ind_comp] * (c[2,ind_comp] * p_i[ind_comp]) ^ c[3,ind_comp]) * + dc_dT_adsorpt[2,ind_comp] + + ((c[2,ind_comp] * p_i[ind_comp]) ^ c[3,ind_comp] * log(c[2,ind_comp] * p_i[ind_comp])) * + dc_dT_adsorpt[3,ind_comp] + "Identical temporary partial derivative of the denominator w.r.t. the + equilbrium temperature"; + + end for; + + for ind_comp in 1:size(c,2) loop + dnum_i_dT_adsorpt[ind_comp] := + (c[2,ind_comp] * p_i[ind_comp]) * dc_dT_adsorpt[1,ind_comp] + + (c[1,ind_comp] * p_i[ind_comp]) * dc_dT_adsorpt[2,ind_comp] + "Derivatives of numerators w.r.t. equilibrium temperature"; + + dden_i_dT_adsorpt[ind_comp] := den_i[ind_comp] * + ((1/den_tmp * dden_tmp_dT_adsorpt) * (1/c[3,ind_comp]) + + log(den_tmp) * (-1/c[3,ind_comp]^2 * dc_dT_adsorpt[3,ind_comp])) + "Derivatives of the denominators w.r.t. the equilbrium temperature"; + end for; + + // + // Calculate derivatives of uptakes wrt. total pressure + // + dx_adsorpt_dT_adsorpt := + (dnum_i_dT_adsorpt .* den_i .- num_i .* dden_i_dT_adsorpt) ./ den_i.^2 + "Calculation of the partial derivatives of the equilibrium uptakes w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + end dx_dT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 8, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The extended Toth isotherm model calculates equilibrium uptakes <i>x_adsorpt</i> +as a function of the equilibrium pressure <i>p_adsorpt</i>, mole fractions of +independent components in the gas or vapor phase <i>y_i</i>, and the equilibrium +temperature <i>T_adsorpt</i>. Each component of the extended Toth isotherm model +has three parameters. +</p> + +<h4>Main equations</h4> +<p> +The extended Toth isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt,<i>i</i></sub> = x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) * b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,<i>i</i></sub> / ((1 + ∑[(b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,<i>i</i></sub>) ^ t<sub><i>i</i></sub>(T<sub>adsorpt</sub>)]) ^ (1/t<sub><i>i</i></sub>(T<sub>adsorpt</sub>))); +</pre> +<p> +Herein, for each component <i>i</i<>, <i>x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>)</i> +is the saturation uptake, <i>b<sub><i>i</i></sub>(T<sub>adsorpt</sub>)</i> is the Toth +coefficient, and <i>t<sub><i>i</i></sub>(T<sub>adsorpt</sub>)</i> is the Toth exponent. +Typical temperature dependencies may have the following forms: +</p> +</p> +<pre> + x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) = x<sub>ref,<i>i</i></sub> * <strong>exp</strong>(Χ<sub><i>i</i></sub>( * (1 - T<sub>adsorpt</sub>/T<sub>ref,<i>i</i></sub>)); +</pre> +<pre> + b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) = b<sub>ref,<i>i</i></sub> * <strong>exp</strong>(Q<sub><i>i</i></sub>(/(R * T<sub>ref,<i>i</i></sub>) * (T<sub>ref,<i>i</i></sub>/T<sub>adsorpt</sub> - 1)); +</pre> +<pre> + t<sub><i>i</i></sub>(T<sub>adsorpt</sub>) = t<sub>ref,<i>i</i></sub> + α<sub><i>i</i></sub>( * (1 - T<sub>ref,<i>i</i></sub>/T<sub>adsorpt</sub>); +</pre> +<p> +Herein, for each component <i>i</i<>, <i>x<sub>ref,<i>i</i></sub></i> is the saturation +uptake at reference temperature <i>T<sub>ref,<i>i</i></sub></i>, <i>b<sub>ref,<i>i</i></sub></i> +is the Toth coefficient at reference temperature, and <i>t<sub>ref,<i>i</i></sub></i> is +the Toth exponent at reference temperature. The parameter <i>Q<sub><i>i</i></i> is a measure +for the isosteric adsorption enthalpy at a fractional loading of <i>x<sub>adsorpt,<i>i</i></sub>/ +x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) = 0.0</i>, the parameter <i>Χ<sub><i>i</i></i> +describes the change of the saturation uptake with temperature, and the parameter +<i>α<sub><i>i</i></i> describes the change of the Toth exponent with temperature. +All seven parameters can be used as fitting parameters. +<br/><br/> +Note that the Toth exponent <i>t<sub><i>i</i></sub>(T<sub>adsorpt</sub>)</i> is typically +lower than unity. For <i>t<sub><i>i</i></sub>(T<sub>adsorpt</sub>) = 1</i>, the Toth +isotherm becomes the Langmuir isotherm. Hence, the Toth exponent <i>t<sub><i>i</i></sub>(T<sub>adsorpt</sub>)</i> +can be interpreted as a parameter describing the heterogeneity of the adsorption system. +</p> + +<h4>Required parameter order in function input c[:,no_components]:</h4> +<p> +For each component <i>i</i>, the required parameter order in the function input <i>c</i> +is as follows: +</p> +<ul> + <li> + c[1,<i>i</i>] = x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[2,<i>i</i>] = b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) in 1/Pa + </li> + <li> + c[3,<i>i</i>] = t<sub><i>i</i></sub>(T<sub>adsorpt</sub>) in - + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the extended Toth isotherm model for one parameter set +and two components. In the upper sub-figure, the equilibrium pressure changes with +time. In the centre sub-figure, the independent mole fractions change with time. +In the lower sub-figure, the equilibrium temperature changes with time. The left +side shows the uptake of component 1, and the right side shows the uptake of +component 2. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_multi_toth.png\" alt=\"media_functions_equilibria_multi_toth.png\"> + +</html>")); +end Toth; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6d0f8d93aba1f8e0f67c45861309e4734531ccf1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/Toth/package.order @@ -0,0 +1,8 @@ +Internals +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/p_i_xT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/p_i_xT.mo new file mode 100644 index 0000000000000000000000000000000000000000..eaa991bdcc478c851810b5c1ac6860e52b5b5a42 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/p_i_xT.mo @@ -0,0 +1,214 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals; +function p_i_xT + "Toth-GAB isotherm model developed by Schellevis (2023): Partial pressures as function of uptakes and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt_lb_start = 1 + "Lower bound of equilibrium pressure (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Modelica.Units.SI.Pressure p_adsorpt_ub_start = 10 + "Upper bound of equilibrium pressure (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for numerical calculation (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of functions + // +protected + function func_p_CO2_num + "Function used to find root (i.e., p_adsorpt_CO2) numerically" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input Real c[:,:] + "Coefficients of isotherm model"; + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature"; + input Modelica.Units.SI.Pressure p_adsorpt_H2O + "Equilibrium pressure of component 2 (i.e., H2O)"; + input SorpLib.Units.Uptake x_adsorpt_CO2 + "Equilibrium uptake of component 1 (i.e., CO2)"; + + input Modelica.Units.SI.Pressure p_threshold_min + "Threshold for partial pressure of all components: If a partial pressure is + below the threshold, its value is set to the threshold"; + algorithm + y := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals.x_CO2_pT( + p_i=cat(1, {u}, {p_adsorpt_H2O}), + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) - x_adsorpt_CO2 + "Function '0 = x(p_adsorpt_CO2, p_adsorpt_H2O, T_adsorpt, c) - x_adsorpt_CO2' + used to find root (i.e., p_adsorpt) numerically"; + end func_p_CO2_num; + + // + // Definition of variables + // + Boolean bound_ok = false + "= true, if bounds are found such that func_p_CO2_num(lb) < 0 and + func_p_CO2_num(ub) > 0"; + + Modelica.Units.SI.Pressure p_adsorpt_CO2_lb = p_adsorpt_lb_start + "Current best lower bound of equilibrium pressure"; + Modelica.Units.SI.Pressure p_adsorpt_CO2_ub = p_adsorpt_ub_start + "Current best upper bound of equilibrium pressure"; + + SorpLib.Units.Uptake x_adsorpt_CO2_lb + "Equilibrium uptake at current best lower bound of equilibrium pressure"; + SorpLib.Units.Uptake x_adsorpt_CO2_ub + "Equilibrium uptake at current best upper bound of equilibrium pressure"; + Integer no=0; +algorithm + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // First, calculte the equilibrium pressure of component 2 (i.e., H2O) + // + // + p_i[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.p_xT( + x_adsorpt=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium pressure of H2O"; + + p_i[2] := max(p_i[2], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Second, find start values such that func_p_CO2_num(lb) < 0 and func_p_CO2_num(ub) > 0 + // + // Reducing p_adsorpt_CO2 reduces x_adsorpt_CO2 -> func_p_CO2_num(p_adsorpt_CO2) + // can become < 0 + // Increasing p_adsorpt_CO2 increases x_adsorpt_CO2 -> func_p_CO2_num(p_adsorpt_CO2) + // can become > 0 + // + x_adsorpt_CO2_lb:= + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals.x_CO2_pT( + p_i=cat( + 1, + {p_adsorpt_CO2_lb}, + {p_i[2]}), + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Equilibrium uptake at current best lower bound of equilibrium pressure"; + x_adsorpt_CO2_ub:= + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals.x_CO2_pT( + p_i=cat( + 1, + {p_adsorpt_CO2_ub}, + {p_i[2]}), + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Equilibrium uptake at current best upper bound of equilibrium pressure"; + + while not bound_ok loop + if Modelica.Math.isEqual(s1=x_adsorpt_CO2_lb, s2=x_adsorpt[1], eps=tolerance) then + p_i[1] := max(p_adsorpt_CO2_lb, p_threshold_min); + bound_ok := true; + return; + + elseif Modelica.Math.isEqual(s1=x_adsorpt_CO2_ub, s2=x_adsorpt[1], eps=tolerance) then + p_i[1] := max(p_adsorpt_CO2_ub, p_threshold_min); + bound_ok := true; + return; + + elseif x_adsorpt_CO2_lb-x_adsorpt[1] < 0 and x_adsorpt_CO2_ub-x_adsorpt[1] < 0 then + p_adsorpt_CO2_lb := p_adsorpt_CO2_ub; + x_adsorpt_CO2_lb := x_adsorpt_CO2_ub; + + p_adsorpt_CO2_ub := p_adsorpt_CO2_ub*10; + x_adsorpt_CO2_ub := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals.x_CO2_pT( + p_i=cat(1, {p_adsorpt_CO2_ub}, {p_i[2]}), + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min); + + elseif x_adsorpt_CO2_lb-x_adsorpt[1] > 0 and x_adsorpt_CO2_ub-x_adsorpt[1] > 0 then + p_adsorpt_CO2_ub := p_adsorpt_CO2_lb; + x_adsorpt_CO2_ub := x_adsorpt_CO2_lb; + + p_adsorpt_CO2_lb := if p_adsorpt_CO2_lb > Modelica.Constants.small then + p_adsorpt_CO2_lb*0.1 else 0; + x_adsorpt_CO2_lb := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals.x_CO2_pT( + p_i=cat(1, {p_adsorpt_CO2_lb}, {p_i[2]}), + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min); + + else + bound_ok := true; + + end if; + end while; + + // + // Third, find root in the interval lb <= root <= up + // + p_i[1] := Modelica.Math.Nonlinear.solveOneNonlinearEquation( + function func_p_CO2_num( + c=c, + T_adsorpt=T_adsorpt, + p_adsorpt_H2O=p_i[2], + x_adsorpt_CO2=x_adsorpt[1], + p_threshold_min=p_threshold_min), + p_adsorpt_CO2_lb, + p_adsorpt_CO2_ub, + tolerance) + "Calculation of the equilibrium pressure of the adsorpt phase"; + + p_i[1] := max(p_i[1], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium pressures <i>p_i</i> (i.e., partial +pressures) as function of the equilibrium uptakes <i>x_adsorpt</i> and the +equilibrium temperature <i>T_adsorpt</i>. Thus, this function is a inverse of the +function 'x_pyT.' For full details of the original function 'x_pyT,' check the +documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + August 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end p_i_xT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..81afefd2b1fb2d7b749eef4c4bb4852d6e26b598 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis; +package Internals "Internal functions used to avoid redundancy" + extends Modelica.Icons.InternalPackage; + + annotation (Documentation(info="<html> +<p> +This package contains functions used for various functions of the Toth-GAB isotherm +model. Thus, redundancy of code shall be avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + August 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Internals; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/package.order new file mode 100644 index 0000000000000000000000000000000000000000..0d4f5b91e7acd91bce426af5e11f53d3e67ad90b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/package.order @@ -0,0 +1,3 @@ +p_i_xT +x_CO2_pT +x_H20_pT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/x_CO2_pT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/x_CO2_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..64ca324a13b0614c56aa1071cedcfa1cb73dad1f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/x_CO2_pT.mo @@ -0,0 +1,74 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals; +function x_CO2_pT + "Toth-GAB isotherm model developed by Schellevis (2023): Equilibrium uptake of component 1 (i.e., CO2) as function of partial pessures and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake x_adsorpt_CO2 + "Equilibrium uptake of component 1 (i.e., CO2)" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_CO2_dry + "Equilibrium uptake of component 1 (i.e., CO2) under dry conditions"; + +algorithm + // + // Calculate equilibrium uptake + // + x_adsorpt_CO2_dry := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[2,1], + c[3,1], + c[4,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of CO2 under dry conditions"; + + x_adsorpt_CO2 := (1 + c[5,1] * Modelica.Math.exp(c[6,1] * x_adsorpt_CO2_dry) * + min(max(p_i[2], p_threshold_min) / max(c[1,1], p_threshold_min), 1)) * + x_adsorpt_CO2_dry + "Calculate equilibrium uptake of CO2"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium uptake of component 1 (i.e., CO2) +<i>x_adsorpt_CO2</i> as function of the partial equilibrium pressures <i>p_i</i>, +and the equilibrium temperature <i>T_adsorpt</i>. For full details of the isotherm +model, check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + August 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_CO2_pT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/x_H20_pT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/x_H20_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..188e3c8f0c5bed9659d876e60565e8537a594ebe --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/Internals/x_H20_pT.mo @@ -0,0 +1,86 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals; +function x_H20_pT + "Toth-GAB isotherm model developed by Schellevis (2023): Equilibrium uptake of component 2 (i.e., H2O) as function of partial pessure and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_H2O + "Equilibrium pressure of H2O of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptake of component 2 (i.e., H2O)" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O_max= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.x_pT( + p_adsorpt=max(c[1,2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Maximal equilibrium uptake of H2O achieved at relative humidity of 1 (i.e., + p_adsorpt_H2O = p_sat_H2O"; + +algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the equilibrium uptake of component 1 (i.e., CO2) + // + // + x_adsorpt_H2O := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.x_pT( + p_adsorpt=max(p_H2O, p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of H2O"; + + x_adsorpt_H2O := min(x_adsorpt_H2O, x_adsorpt_H2O_max) + "Limit equilibrium uptake of H2O to its maximal equilibrium uptake"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium uptake of component 2 (i.e., H2O) +<i>x_adsorpt_H2O</i> as function of the partial equilibrium pressure of H2O <i>p_H2O</i> +and the equilibrium temperature <i>T_adsorpt</i>. For full details of the isotherm +model, check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + August 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_H20_pT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c6632324b0c829db9db152951e8b073aab4d0817 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/package.mo @@ -0,0 +1,678 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents; +package TothGAB_Schellevis "Package containing all functions regarding the Toth-GAB isotherm developed by Schellevis (2023) for adsorption of CO2 & H2O" + extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponents; + + // + // Internal package + // + redeclare final function extends x_pyT + "Toth-GAB isotherm model developed by Schellevis (2023): Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + algorithm + // + // First, calculate the equilibrium uptake of component 1 (i.e., CO2) + // + x_adsorpt[1] := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals.x_CO2_pT( + p_i=p_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of CO2"; + + // + // Second, calculte the equilibrium uptake of component 2 (i.e., H2O) + // + x_adsorpt[2] := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals.x_H20_pT( + p_H2O=p_i[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end x_pyT; + + redeclare final function extends p_xyT + "Toth-GAB isotherm model developed by Schellevis (2023): Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + algorithm + // + // First, calculte the equilibrium pressure of component 2 (i.e., H2O) + // + p_i[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.p_xT( + x_adsorpt=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium pressure of H2O"; + + p_i[2] := max(p_i[2], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Second, calculte the equilibrium pressure of component 1 (i.e., CO2) + // + p_i[1] := y_i[1] * (p_i[2] / (1-y_i[1])) + "Calculate equilibrium pressure of CO2"; + + p_i[1] := max(p_i[1], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Third, calculate the equilibrium pressure + // + p_adsorpt := sum(p_i) + "Equilibrium pressure"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end p_xyT; + + redeclare final function extends y_pxT + "Toth-GAB isotherm model developed by Schellevis (2023): Mole fractions of independent gas phase components as function of uptakes, pressure, and temperature" + algorithm + // + // First, calculte the equilibrium pressure of component 2 (i.e., H2O) + // + p_i[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.p_xT( + x_adsorpt=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium pressure of H2O"; + + p_i[2] := max(p_i[2], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Second, calculte the equilibrium pressure of component 1 (i.e., CO2) + // + p_i[1] := (1 - p_i[2] / max(p_adsorpt, p_threshold_min)) * max(p_adsorpt, p_threshold_min) + "Calculate equilibrium pressure of CO2"; + + p_i[1] := max(p_i[1], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Third, calculate the independent mole fractions (i.e., mole fraction of + // component 1) + // + y_i[1] := p_i[1] / max(p_adsorpt, p_threshold_min) + "Mole fractions of independent component in the gas or vapor phase"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end y_pxT; + + redeclare final function extends py_xT + "Toth-GAB isotherm model developed by Schellevis (2023): Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_Schellevis.Internals.p_i_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min, + p_adsorpt_lb_start=p_adsorpt_lb_start, + p_adsorpt_ub_start=p_adsorpt_ub_start, + tolerance=tolerance) + "Partial pressures"; + + p_adsorpt := max(sum(p_i), p_threshold_min) + "Equilibrium pressure"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / p_adsorpt + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + redeclare final function extends dx_dp + "Toth-GAB isotherm model developed by Schellevis (2023): Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_CO2_dry + "Equilibrium uptake of component 1 (i.e., CO2) under dry conditions"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_CO2_dry_dp_adsorpt + "Partial derivative of the equilibrium uptake of component 1 (i.e., CO2) + w.r.t. the equilibrium pressure"; + + Real EF_CO2(unit="1") + "Enhancement factor of the CO2 uptake"; + Real dEF_CO2_dp_adsorpt_H2O(unit="1/Pa") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium pressure of component 2 (i.e., H2O)"; + Real dEF_CO2_dx_adsorpt_CO2_dry(unit="kg/kg") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium uptake of component 1 (i.e., CO2)"; + Real dEF_CO2_dp_adsorpt(unit="1/Pa") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium pressure"; + + algorithm + // + // The existing derivative function of the Toth isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // equilibrium pressure (i.e., y_i_[1]). + // + x_adsorpt_CO2_dry := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[2,1], + c[3,1], + c[4,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of CO2 under dry conditions"; + dx_adsorpt_CO2_dry_dp_adsorpt := y_i_[1]* + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dp( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[2,1], + c[3,1], + c[4,1]}) + "Partial derivative of first component's equilibrium uptake w.r.t. the + equilibrium pressure"; + + EF_CO2 := 1 + c[5,1] * Modelica.Math.exp(c[6,1] * x_adsorpt_CO2_dry) * + min(max(p_i[2], p_threshold_min) / max(c[1,1], p_threshold_min), 1) + "Enhancement factor of the CO2 uptake"; + dEF_CO2_dp_adsorpt_H2O :=c[5, 1] * Modelica.Math.exp(c[6, 1] * x_adsorpt_CO2_dry) / + max(c[1,1], p_threshold_min) + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium pressure of component 2 (i.e., H2O)"; + dEF_CO2_dx_adsorpt_CO2_dry := c[6,1] * c[5,1] * + Modelica.Math.exp(c[6,1] * x_adsorpt_CO2_dry) * + min(max(p_i[2], p_threshold_min) / max(c[1,1], p_threshold_min), 1) + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium uptake of component 1 (i.e., CO2)"; + dEF_CO2_dp_adsorpt := + dEF_CO2_dp_adsorpt_H2O * y_i_[2] + + dEF_CO2_dx_adsorpt_CO2_dry * dx_adsorpt_CO2_dry_dp_adsorpt + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium pressure"; + + dx_adsorpt_dp_adsorpt[1] := + dEF_CO2_dp_adsorpt * x_adsorpt_CO2_dry + + EF_CO2 * dx_adsorpt_CO2_dry_dp_adsorpt + "Partial derivative of first component's equilibrium uptake w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + + // + // The existing derivative function of the GAB isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // equilibrium pressure (i.e., y_i_[2]). + // + dx_adsorpt_dp_adsorpt[2] := y_i_[2] * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dp( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + end dx_dp; + + redeclare final function extends dx_dy + "Toth-GAB isotherm model developed by Schellevis (2023): Partial derivative of uptakes w.r.t. mole fractions of independent gas phase components at constant pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_CO2_dry + "Equilibrium uptake of component 1 (i.e., CO2) under dry conditions"; + SorpLib.Units.DerUptakeByMolarFraction dx_adsorpt_CO2_dry_dy_i + "Partial derivative of the equilibrium uptake of component 1 (i.e., CO2) + w.r.t. the independent mole fraction"; + + Real EF_CO2(unit="1") + "Enhancement factor of the CO2 uptake"; + Real dEF_CO2_dp_adsorpt_H2O(unit="1/Pa") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium pressure of component 2 (i.e., H2O)"; + Real dEF_CO2_dx_adsorpt_CO2_dry(unit="kg/kg") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium uptake of component 1 (i.e., CO2)"; + Real dEF_CO2_dy_i(unit="mol/mol") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + independent mole fraction"; + + algorithm + // + // The existing derivative function of the Toth isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // independent mole fraction (i.e., p_adsorpt). + // + x_adsorpt_CO2_dry := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[2,1], + c[3,1], + c[4,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of CO2 under dry conditions"; + dx_adsorpt_CO2_dry_dy_i := p_adsorpt* + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dp( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[2,1], + c[3,1], + c[4,1]}) + "Partial derivative of first component's equilibrium uptake w.r.t. the + independent mole fraction"; + + EF_CO2 := 1 + c[5,1] * Modelica.Math.exp(c[6,1] * x_adsorpt_CO2_dry) * + min(max(p_i[2], p_threshold_min) / max(c[1,1], p_threshold_min), 1) + "Enhancement factor of the CO2 uptake"; + dEF_CO2_dp_adsorpt_H2O := c[5, 1] * Modelica.Math.exp(c[6, 1] * x_adsorpt_CO2_dry) / + max(c[1,1], p_threshold_min) + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium pressure of component 2 (i.e., H2O)"; + dEF_CO2_dx_adsorpt_CO2_dry := c[6,1] * c[5,1] * + Modelica.Math.exp(c[6,1] * x_adsorpt_CO2_dry) * + min(max(p_i[2], p_threshold_min) / max(c[1,1], p_threshold_min), 1) + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium uptake of component 1 (i.e., CO2)"; + dEF_CO2_dy_i := + dEF_CO2_dp_adsorpt_H2O * (-p_adsorpt) + + dEF_CO2_dx_adsorpt_CO2_dry * dx_adsorpt_CO2_dry_dy_i + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + independent mole fraction"; + + dx_adsorpt_dy_i[1,1] := + dEF_CO2_dy_i * x_adsorpt_CO2_dry + + EF_CO2 * dx_adsorpt_CO2_dry_dy_i + "Partial derivative of first component's equilibrium uptake w.r.t. the + independent mole fraction at constant pressure and temperature"; + + // + // The existing derivative function of the GAB isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // independent mole fractions (i.e., -p_adsorpt) + // + dx_adsorpt_dy_i[2,1] := -p_adsorpt * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dp( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + independent mole fractions at constant pressure and temperature"; + end dx_dy; + + redeclare final function extends dx_dT + "Toth-GAB isotherm model developed by Schellevis (2023): Partial derivative of uptakes w.r.t. temperature at constant pressure and mole fractions" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_CO2_dry + "Equilibrium uptake of component 1 (i.e., CO2) under dry conditions"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_CO2_dry_dT_adsorpt + "Partial derivative of the equilibrium uptake of component 1 (i.e., CO2) + w.r.t. the equilibrium temperature"; + + Real EF_CO2(unit="1") + "Enhancement factor of the CO2 uptake"; + Real dEF_CO2_dc1(unit="1/Pa") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + first coefficient of the Toth isotherm model"; + Real dEF_CO2_dc5(unit="1") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + fivth coefficient of the Toth isotherm model"; + Real dEF_CO2_dc6(unit="kg/kg") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + sixth coefficient of the Toth isotherm model"; + Real dEF_CO2_dx_adsorpt_CO2_dry(unit="kg/kg") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium uptake of component 1 (i.e., CO2)"; + Real dEF_CO2_dT_adsorpt(unit="1/K") + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium temperature"; + + algorithm + // + // The existing derivative functions of the Toth and GAB isotherm models + // correspond to partial derivatives w.r.t. the equilibrium temperature. Note + // that for component 1, the uptake is enhanced by an enhancement factor. Thus, + // the correct partial derivative w.r.t. the equilibrium temperature must be + // calculated. + // + x_adsorpt_CO2_dry := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[2,1], + c[3,1], + c[4,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of CO2 under dry conditions"; + dx_adsorpt_CO2_dry_dT_adsorpt := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[2,1], + c[3,1], + c[4,1]}, + dc_dT_adsorpt={dc_dT_adsorpt[2,1], + dc_dT_adsorpt[3,1], + dc_dT_adsorpt[4,1]}) + "Partial derivative of first component's equilibrium uptake w.r.t. the + equilibrium temperature"; + + EF_CO2 := 1 + c[5,1] * Modelica.Math.exp(c[6,1] * x_adsorpt_CO2_dry) * + min(max(p_i[2], p_threshold_min) / max(c[1,1], p_threshold_min), 1) + "Enhancement factor of the CO2 uptake"; + dEF_CO2_dc1 := -c[5,1] * Modelica.Math.exp(c[6,1] * x_adsorpt_CO2_dry) * + max(p_i[2], p_threshold_min) / max(c[1,1], p_threshold_min)^2 + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + first coefficient of the Toth isotherm model"; + dEF_CO2_dc5 := Modelica.Math.exp(c[6,1] * x_adsorpt_CO2_dry) * + min(max(p_i[2], p_threshold_min) / max(c[1,1], p_threshold_min), 1) + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + fivth coefficient of the Toth isotherm model"; + dEF_CO2_dc6 := c[5,1] * Modelica.Math.exp(c[6,1] * x_adsorpt_CO2_dry) * + min(max(p_i[2], p_threshold_min) / max(c[1,1], p_threshold_min), 1) * + x_adsorpt_CO2_dry + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + sixth coefficient of the Toth isotherm model"; + dEF_CO2_dx_adsorpt_CO2_dry := c[6,1] * c[5,1] * + Modelica.Math.exp(c[6,1] * x_adsorpt_CO2_dry) * + min(max(p_i[2], p_threshold_min) / max(c[1,1], p_threshold_min), 1) + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium uptake of component 1 (i.e., CO2)"; + dEF_CO2_dT_adsorpt := + dEF_CO2_dc1 * dc_dT_adsorpt[1,1] + + dEF_CO2_dc5 * dc_dT_adsorpt[5,1] + + dEF_CO2_dc6 * dc_dT_adsorpt[6,1] + + dEF_CO2_dx_adsorpt_CO2_dry * dx_adsorpt_CO2_dry_dT_adsorpt + "Partial derivative of the enhancement factor of the CO2 uptake w.r.t. the + equilibrium temperature"; + //Modelica.Utilities.Streams.print(String(dEF_CO2_dx_adsorpt_CO2_dry)); + + dx_adsorpt_dT_adsorpt[1] := + dEF_CO2_dT_adsorpt * x_adsorpt_CO2_dry + + EF_CO2 * dx_adsorpt_CO2_dry_dT_adsorpt + "Partial derivative of first component's equilibrium uptake w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + + dx_adsorpt_dT_adsorpt[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dT( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + dc_dT_adsorpt={dc_dT_adsorpt[1,2], + dc_dT_adsorpt[2,2], + dc_dT_adsorpt[3,2], + dc_dT_adsorpt[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + end dx_dT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + August 5, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +The Toth-GAB isotherm model calculates equilibrium uptakes <i>x_adsorpt</i> of +CO<sub>2</sub> and H<sub>2</sub>O on amine-functionalized sorbents as a function +of the equilibrium pressure <i>p_adsorpt</i>, mole fractions of independent +components in the gas or vapor phase <i>y_i</i>, and the equilibrium temperature +<i>T_adsorpt</i>. The model was developed by Schellevis (2023) for modeling of +direct air capture systems. A modified Toth isotherm model describes the uptake +of CO<sub>2</sub>, while a GAB isotherm model describes the uptake of H<sub>2</sub>O. +</p> + +<h4>Main equations</h4> +<p> +The modified Toth isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt,CO<sub>2</sub></sub> = (1 + β<sub>H<sub>2</sub>O</sub> * <strong>exp</strong>(γ<sub>CO<sub>2</sub></sub> * x<sub>adsorpt,CO<sub>2</sub>,dry</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)) * x<sub>adsorpt,CO<sub>2</sub>,dry</sub>; +</pre> +<p> +with +</p> +<pre> + x<sub>adsorpt,CO<sub>2</sub>,dry</sub> = x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) * b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,CO<sub>2</sub></sub> / ((1 + (b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,CO<sub>2</sub></sub>) ^ t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)) ^ (1/t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>))); +</pre> +<pre> + φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = p<sub>adsorpt</sub>/p<sub>sat,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)</i> is the saturation +uptake, <i>b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)</i> is the Toth coefficient, +and <i>t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)</i> is the Toth exponent. The +coefficients <i>β<sub>CO<sub>2</sub></sub></i> and <i>γ<sub>H<sub>2</sub>O</sub></i> +describe the enhancement of the CO<sub>2</sub> uptake depending on the relative humidty +<i>φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i>. Typical temperature +dependencies may have the following forms: +</p> +<pre> + x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) = x<sub>ref,CO<sub>2</sub></sub> * <strong>exp</strong>(Χ<sub>CO<sub>2</sub></sub> * (1 - T<sub>adsorpt</sub>/T<sub>ref,CO<sub>2</sub></sub>)); +</pre> +<pre> + b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) = b<sub>ref,CO<sub>2</sub></sub> * <strong>exp</strong>(Q<sub>CO<sub>2</sub></sub>/(R * T<sub>ref,CO<sub>2</sub></sub>) * (T<sub>ref,CO<sub>2</sub></sub>/T<sub>adsorpt</sub> - 1)); +</pre> +<pre> + t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) = t<sub>ref,CO<sub>2</sub></sub> + α<sub>CO<sub>2</sub></sub> * (1 - T<sub>ref,CO<sub>2</sub></sub>/T<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>ref,CO<sub>2</sub></sub></i> is the saturation uptake at reference +temperature <i>T<sub>ref,CO<sub>2</sub></sub></i>, <i>b<sub>ref,CO<sub>2</sub></sub></i> +is the Toth coefficient at reference temperature, and <i>t<sub>ref,CO<sub>2</sub></sub></i> +is the Toth exponent at reference temperature. The parameter <i>Q<sub>CO<sub>2</sub></sub></i> +is a measure for the isosteric adsorption enthalpy at a fractional loading of +<i>x<sub>adsorpt,CO<sub>2</sub></sub>/x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) = 0.0</i>, the +parameter <i>Χ<sub>CO<sub>2</sub></sub></i> describes the change of the saturation +uptake with temperature, and the parameter <i>α<sub>CO<sub>2</sub></sub></i> +describes the change of the Toth exponent with temperature. All seven parameters +and the two enhancement factors <i>γ<sub>CO<sub>2</sub></sub></i> and +<i>β<sub>H<sub>2</sub>O</sub></i> can be used as fitting parameters. +<br/> +<p> +The GAB isotherm model has the following form: +</p> +</p> +<pre> + x<sub>adsorpt,H<sub>2</sub>O</sub> = x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) / ((1 - k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)) * (1 + (c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) - 1) * k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>))); +</pre> +<p> +with +</p> +<pre> + φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = p<sub>adsorpt</sub>/p<sub>sat,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> is the monolayer +uptake and <i>c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> and +<i>k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> are affinity coefficients of +the GAB isotherm model. These three parameters can be modeled independent of temperature. +When assuming these three parameters to be dependent on temperature, typical temperature +dependencies may have the following forms: +</p> +<pre> + x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = x<sub>mon,ref,H<sub>2</sub>O</sub> * <strong>exp</strong>(Χ<sub>H<sub>2</sub>O</sub> * (1 - T<sub>adsorpt</sub>/T<sub>ref,H<sub>2</sub>O</sub>)); +</pre> +<pre> + c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = <strong>exp</strong>((E<sub>1,H<sub>2</sub>O</sub> - E<sub>10+,H<sub>2</sub>O</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<pre> + k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = <strong>exp</strong>((E<sub>2-9,H<sub>2</sub>O</sub> - E<sub>10+,H<sub>2</sub>O</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + E<sub>1,H<sub>2</sub>O</sub> = C<sub>H<sub>2</sub>O</sub> - <strong>exp</strong>(D<sub>H<sub>2</sub>O</sub> * T<sub>adsorpt</sub>); +</pre> +<pre> + E<sub>2-9,H<sub>2</sub>O</sub> = F<sub>H<sub>2</sub>O</sub> + G<sub>H<sub>2</sub>O</sub> * T<sub>adsorpt</sub>; +</pre> +<pre> + E<sub>10+,H<sub>2</sub>O</sub> = Δh<sub>vap,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>mon,ref,H<sub>2</sub>O</sub></i> is the monolayer uptake at reference +temperature <i>T<sub>ref,H<sub>2</sub>O</sub></i> and <i>Χ<sub>H<sub>2</sub>O</sub></i> +describes the change of the monolayer uptake with temperature. The coefficient +<i>E<sub>1,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption of the first layer +and <i>E<sub>2-9,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption of layers +2-9: These enthalpies of adsorption can be modeled temperature-dependent as shown +in the example above, with the four fitting parameters <i>C<sub>H<sub>2</sub>O</sub></i>, +<i>D<sub>H<sub>2</sub>O</sub></i>, <i>E<sub>H<sub>2</sub>O</sub></i>, and <i>F<sub>H<sub>2</sub>O</sub></i>. +The coefficient <i>E<sub>10+,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption +for layer 10 or higher layers and is assumed to correspond to the temperature-dependent +enthalpy of vaporization <i>Δh<sub>vap,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i>. +</p> + +<h4>Required parameter order in function input c[:,no_components]:</h4> +<p> +For component 1 (i.e., CO<sub>2</sub>), the required parameter order in the function +input <i>c</i> is as follows: +</p> +<ul> + <li> + c[1,1] = p<sub>sat,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2,1] = x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[3,1] = b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) in 1/Pa + </li> + <li> + c[4,1] = t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[5,1] = β<sub>CO<sub>2</sub></sub> in - + </li> + <li> + c[6,1] = γ<sub>H<sub>2</sub>O</sub> in kg/kg + </li> +</ul> +<p> +For component 2 (i.e., H<sub>2</sub>0), the required parameter order in the function +input <i>c</i> is as follows: +</p> +<ul> + <li> + c[1,2] = p<sub>sat,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2,2] = x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[3,2] = c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[4,2] = k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[5,2] = 0 (i.e., not required) + </li> + <li> + c[6,2] = 0 (i.e., not required) + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the Toth-GAB isotherm model for one parameter set. In +the upper sub-figure, the equilibrium pressure changes with time. In the centre +sub-figure, the independent mole fractions change with time. In the lower sub-figure, +the equilibrium temperature changes with time. The left side shows the uptake of +component 1 (i.e., CO<sub>2</sub>), and the right side shows the uptake of component +2 (i.e., H<sub>2</sub>0). +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_multi_toth_gab_s.png\" alt=\"media_functions_equilibria_multi_toth_gab_s.png\"> + +<h4>References</h4> +<ul> + <li> + <li> + Schellevis, H. M. (2023). CO<sub>2</sub> from air: A process engineering approach, PhD thesis. DOI: http://doi.org/10.3990/1.9789036555852. + </li> +</ul> +</html>")); +end TothGAB_Schellevis; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6d0f8d93aba1f8e0f67c45861309e4734531ccf1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_Schellevis/package.order @@ -0,0 +1,8 @@ +Internals +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/dx_CO2_dp.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/dx_CO2_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..e4487acd21499253c4b2d5ce22ee1fbcbac23984 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/dx_CO2_dp.mo @@ -0,0 +1,63 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals; +function dx_CO2_dp + "Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Partial derivative of uptake w.r.t. pressure as function of pressure and temperature" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp; + + // + // Definition of inputs + // + input Real[:] dc_dp_adsorpt + "Partial derivatives of coefficients of isotherm model w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = c[2] * p_adsorpt / + ((1 + (c[2]*p_adsorpt)^c[3])^(1/c[3])) + "Derivative of uptake w.r.t. to first coefficient of Toth isotherm"; + Real dx_adsorpt_dc2 = c[1] * p_adsorpt * + ((c[2]*p_adsorpt)^c[3] + 1) ^ (-1/c[3] - 1) + "Derivative of uptake w.r.t. to second coefficient of Toth isotherm"; + Real dx_adsorpt_dc3 = c[1] * c[2] * p_adsorpt * + (log(1 + (c[2]*p_adsorpt)^c[3]) / c[3]^2 - + (c[2]*p_adsorpt)^c[3] * log(c[2]*p_adsorpt) / + (c[3] * (1 + (c[2]*p_adsorpt)^c[3]))) / + ((1 + (c[2]*p_adsorpt)^c[3])^(1/c[3])) + "Derivative of uptake w.r.t. to third coefficient of Toth isotherm"; + +algorithm + dx_adsorpt_dp_adsorpt := + c[1]*c[2] * ((c[2]*p_adsorpt)^c[3] + 1) ^ (-1/c[3] - 1) + + dx_adsorpt_dc1*dc_dp_adsorpt[1] + + dx_adsorpt_dc2*dc_dp_adsorpt[2] + + dx_adsorpt_dc3*dc_dp_adsorpt[3] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'x_pT' of the Toth isotherm +model with respect to the equilibrium pressure. For full details of the original function 'x_pT,' +check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT\">SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT</a>. +<br> +In contrast to the existing function 'dx_dp' of the Toth isotherm model, this function +recognises that the coefficients <i>c</i> can also depend on the equilibrium pressure. +Therefore, this function has the partial derivatives of the coefficients w.r.t. the +equilibrium pressure <i>dc_dp_adsorpt</i> as an additional input. +</p> +</html>", revisions="<html> +<ul> + <li> + July 31, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dx_CO2_dp; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/p_i_xT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/p_i_xT.mo new file mode 100644 index 0000000000000000000000000000000000000000..cf648e8bede0f3fad187c13f83c0ccdf0fd599a1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/p_i_xT.mo @@ -0,0 +1,85 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals; +function p_i_xT + "Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Partial pressures as function of uptakes and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + // + // First, calculate the equilibrium pressure of component 1 (i.e., CO2) + // + p_i[1] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.p_xT( + x_adsorpt=x_adsorpt[1], + T_adsorpt=T_adsorpt, + c={c[1,1] * (1 / (1 - c[4,1]*x_adsorpt[2])), + c[2,1] * (1 + c[5,1]*x_adsorpt[2]), + c[3,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium pressure of CO2"; + + p_i[1] := max(p_i[1], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Second, calculte the equilibrium pressure of component 2 (i.e., H2O) + // + // + p_i[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.p_xT( + x_adsorpt=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium pressure of H2O"; + + p_i[2] := max(p_i[2], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium pressures <i>p_i</i> (i.e., partial +pressures) as function of the equilibrium uptakes <i>x_adsorpt</i> and the +equilibrium temperature <i>T_adsorpt</i>. Thus, this function is a inverse of the +function 'x_pyT.' For full details of the original function 'x_pyT,' check the +documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + July 31, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end p_i_xT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f0a67aa6d0fe7f4f2b4ece665ae05e9230c1e607 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli; +package Internals "Internal functions used to avoid redundancy" + extends Modelica.Icons.InternalPackage; + + annotation (Documentation(info="<html> +<p> +This package contains functions used for various functions of the Toth-GAB isotherm +model. Thus, redundancy of code shall be avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + July 31, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Internals; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/package.order new file mode 100644 index 0000000000000000000000000000000000000000..54b2b5782fac298b13169d076ab45becf29995f8 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/package.order @@ -0,0 +1,3 @@ +dx_CO2_dp +p_i_xT +x_H20_pT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/x_H20_pT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/x_H20_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..cbf5d733cabd22ff18320bd215fcadb20d49c41c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/Internals/x_H20_pT.mo @@ -0,0 +1,86 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals; +function x_H20_pT + "Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Equilibrium uptake of component 2 (i.e., H2O) as function of partial pessures and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptakes of component 2 (i.e., H2O)" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O_max= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.x_pT( + p_adsorpt=max(c[1,2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Maximal equilibrium uptake of H2O achieved at relative humidity of 1 (i.e., + p_adsorpt_H2O = p_sat_H2O"; + +algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the equilibrium uptake of component 1 (i.e., CO2) + // + // + x_adsorpt_H2O := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.x_pT( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of H2O"; + + x_adsorpt_H2O := min(x_adsorpt_H2O, x_adsorpt_H2O_max) + "Limit equilibrium uptake of H2O to its maximal equilibrium uptake"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium uptake of component 2 (i.e., H2O) +<i>x_adsorpt_H2O</i> as function of the partial equilibrium pressures <i>p_i</i> +and the equilibrium temperature <i>T_adsorpt</i>. For full details of the isotherm +model, check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + July 31, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_H20_pT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..dfe71ede4d5536a8a6d67f2a2bf9bc31c0e098d8 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/package.mo @@ -0,0 +1,578 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents; +package TothGAB_StampiBombelli "Package containing all functions regarding the Toth-GAB isotherm developed by Stampi-Bombelli et al. (2020) for adsorption of CO2 & H2O" + extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponents; + + // + // Internal package + // + redeclare final function extends x_pyT + "Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the equilibrium uptake of component 1 (i.e., CO2) + // + x_adsorpt[2] := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals.x_H20_pT( + p_i=p_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate the equilibrium uptake of component 1 (i.e., CO2) + // + x_adsorpt[1] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1,1] * (1 / (1 - c[4,1]*x_adsorpt[2])), + c[2,1] * (1 + c[5,1]*x_adsorpt[2]), + c[3,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of CO2"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end x_pyT; + + redeclare final function extends p_xyT + "Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals.p_i_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) "Partial pressures"; + + p_adsorpt := sum(p_i) + "Equilibrium pressure"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end p_xyT; + + redeclare final function extends y_pxT + "Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Mole fractions of independent gas phase components as function of uptakes, pressure, and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals.p_i_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) "Partial pressures"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / max(p_adsorpt, p_threshold_min) + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end y_pxT; + + redeclare final function extends py_xT + "Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Pressure and mole fractions of independent gas phase components as function of uptakes and temperature" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals.p_i_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) "Partial pressures"; + + p_adsorpt := max(sum(p_i), p_threshold_min) + "Equilibrium pressure"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / p_adsorpt + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + redeclare final function extends dx_dp + "Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptakes of component 2 (i.e., H2O)"; + + Real dc_1_CO2_dp_adsorpt + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + Real dc_2_CO2_dp_adsorpt + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + Real dc_3_CO2_dp_adsorpt + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the partial derivative of the equilibrium uptake + // w.r.t. the equilibrium pressure of component 1 (i.e., CO2) + // + x_adsorpt_H2O := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals.x_H20_pT( + p_i=p_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate partial derivatives: + // + // The partial derivative of component 2 (i.e., H2O) must be calculated first + // because it is required to calculate the partial derivative of component 1 + // (i.e., CO2). + // + // The existing derivative function of the GAB isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // equilibrium pressure (i.e., y_i_[2]). + // + dx_adsorpt_dp_adsorpt[2] := y_i_[2] * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dp( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + + // + // Note that for component 1, the coefficients of the isotherm model are + // enhanced by the uptake of component 2. Hence, the parameters c depend also + // on the partial pressure of component 2 and, thus, on the equilibrium + // pressure. Note that all coefficients are devided by 'y_i_[1]' to compensate + // the multiplication by 'y_i_[1],' which is the partial derivative of the + // partial pressure of component 1 w.r.t. the equilibrium pressure. + // + dc_1_CO2_dp_adsorpt := c[1,1] * c[4,1] / (c[4,1] * x_adsorpt_H2O - 1) ^ 2 * + dx_adsorpt_dp_adsorpt[2] / y_i_[1] + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + dc_2_CO2_dp_adsorpt := c[2,1] * c[5,1] * dx_adsorpt_dp_adsorpt[2] / y_i_[1] + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + dc_3_CO2_dp_adsorpt := 0 / y_i_[1] + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + + dx_adsorpt_dp_adsorpt[1] := y_i_[1]* + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals.dx_CO2_dp( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1, 1]*(1/(1 - c[4, 1]*x_adsorpt_H2O)),c[2, 1]*(1 + c[5, 1]* + x_adsorpt_H2O),c[3, 1]}, + dc_dp_adsorpt={dc_1_CO2_dp_adsorpt,dc_2_CO2_dp_adsorpt,dc_3_CO2_dp_adsorpt}) + "Partial derivative of first component's equilibrium uptake w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + end dx_dp; + + redeclare final function extends dx_dy + "Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Partial derivative of uptakes w.r.t. mole fractions of independent gas phase components at constant pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptakes of component 2 (i.e., H2O)"; + + Real dc_1_CO2_dp_adsorpt + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + Real dc_2_CO2_dp_adsorpt + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + Real dc_3_CO2_dp_adsorpt + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the partial derivative of the equilibrium uptake + // w.r.t. the independent mole fractions of component 1 (i.e., CO2) + // + x_adsorpt_H2O := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals.x_H20_pT( + p_i=p_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate partial derivatives: + // + // The partial derivative of component 2 (i.e., H2O) must be calculated first + // because it is required to calculate the partial derivative of component 1 + // (i.e., CO2). + // + // The existing derivative function of the GAB isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // independent mole fractions (i.e., -p_adsorpt) + // + dx_adsorpt_dy_i[2,1] := -p_adsorpt * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dp( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + independent mole fractions at constant pressure and temperature"; + + // + // Note that for component 1, the coefficients of the isotherm model are + // enhanced by the uptake of component 2. Hence, the parameters c depend also + // on the partial pressure of component 2 and, thus, on the equilibrium + // pressure. Note that all coefficients are devided by 'p_adsorpt' to compensate + // the multiplication by 'p_adsorpt,' which is the partial derivative of the + // partial pressure of component 1 w.r.t. the equilibrium pressure. + // + dc_1_CO2_dp_adsorpt := c[1,1] * c[4,1] / (c[4,1] * x_adsorpt_H2O - 1) ^ 2 * + dx_adsorpt_dy_i[2,1] / p_adsorpt + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + dc_2_CO2_dp_adsorpt := c[2,1] * c[5,1] * dx_adsorpt_dy_i[2,1] / p_adsorpt + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + dc_3_CO2_dp_adsorpt := 0 / p_adsorpt + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium pressure"; + + dx_adsorpt_dy_i[1, 1] := p_adsorpt* + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals.dx_CO2_dp( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1, 1]*(1/(1 - c[4, 1]*x_adsorpt_H2O)),c[2, 1]*(1 + c[5, 1]* + x_adsorpt_H2O),c[3, 1]}, + dc_dp_adsorpt={dc_1_CO2_dp_adsorpt,dc_2_CO2_dp_adsorpt,dc_3_CO2_dp_adsorpt}) + "Partial derivative of first component's equilibrium uptake w.r.t. the + independent mole fractions at constant pressure and temperature"; + end dx_dy; + + redeclare final function extends dx_dT + "Toth-GAB isotherm model developed by Stampi-Bombelli et al. (2020): Partial derivative of uptakes w.r.t. temperature at constant pressure and mole fractions" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptakes of component 2 (i.e., H2O)"; + + Real dc_1_CO2_dT_adsorpt + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + Real dc_2_CO2_dT_adsorpt + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + Real dc_3_CO2_dT_adsorpt + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the partial derivative of the equilibrium uptake + // w.r.t. the equilibrium temperature of component 1 (i.e., CO2) + // + x_adsorpt_H2O := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.TothGAB_StampiBombelli.Internals.x_H20_pT( + p_i=p_i, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate partial derivatives: + // + // The existing derivative functions of the Toth and GAB isotherm models + // correspond to partial derivatives w.r.t. the equilibrium temperature. Again, + // the partial derivative of component 2 (i.e., H2O) must be calculated first + // because it is required to calculate the partial derivative of component 1 + // (i.e., CO2). + // + dx_adsorpt_dT_adsorpt[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dT( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + dc_dT_adsorpt={dc_dT_adsorpt[1,2], + dc_dT_adsorpt[2,2], + dc_dT_adsorpt[3,2], + dc_dT_adsorpt[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + + // + // Note that for component 1, the coefficients of the isotherm model are + // enhanced by the uptake of component 2. Hence, the parameter dc_dT cannot + // directly be passed to the existing derivative function of the Toth isotherm + // model. Instead, the the correct derivative must be calculated first. + // + dc_1_CO2_dT_adsorpt := dc_dT_adsorpt[1,1] * (1 / (1 - c[4,1] * x_adsorpt_H2O)) + + c[1,1] * (x_adsorpt_H2O / (c[4,1] * x_adsorpt_H2O - 1) ^ 2 * dc_dT_adsorpt[4,1] + + c[4,1] / (c[4,1] * x_adsorpt_H2O - 1) ^ 2 * dx_adsorpt_dT_adsorpt[2]) + "Partial derivative of first coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + dc_2_CO2_dT_adsorpt := dc_dT_adsorpt[2,1] * (1 + c[5,1] * x_adsorpt_H2O) + + c[2,1] * (x_adsorpt_H2O * dc_dT_adsorpt[5,1] + c[5,1] * dx_adsorpt_dT_adsorpt[2]) + "Partial derivative of second coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + dc_3_CO2_dT_adsorpt := dc_dT_adsorpt[3,1] + "Partial derivative of third coefficient of the Toth isotherm w.r.t. the + equilibrium temperature"; + + dx_adsorpt_dT_adsorpt[1] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1,1] * (1 / (1 - c[4,1] * x_adsorpt_H2O)), + c[2,1] * (1 + c[5,1] * x_adsorpt_H2O), + c[3,1]}, + dc_dT_adsorpt={dc_1_CO2_dT_adsorpt, + dc_2_CO2_dT_adsorpt, + dc_3_CO2_dT_adsorpt}) + "Partial derivative of first component's equilibrium uptake w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + end dx_dT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + July 31, 2024, by Mirko Engelpracht:<br/> + Adaptations (e.g., object-orientied approach) due to restructuring the library + and documentation. + </li> + <li> + September 1, 2021, by Patrik Postweiler:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +The Toth-GAB isotherm model calculates equilibrium uptakes <i>x_adsorpt</i> of +CO<sub>2</sub> and H<sub>2</sub>O on amine-functionalized sorbents as a function +of the equilibrium pressure <i>p_adsorpt</i>, mole fractions of independent +components in the gas or vapor phase <i>y_i</i>, and the equilibrium temperature +<i>T_adsorpt</i>. The model was developed by Stampi-Bombelli et al. (2020) for +modeling of direct air capture systems. A modified Toth isotherm model describes +the uptake of CO<sub>2</sub>, while a GAB isotherm model describes the uptake of +H<sub>2</sub>O. +</p> + +<h4>Main equations</h4> +<p> +The modified Toth isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt,CO<sub>2</sub></sub> = x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) * A<sub>CO<sub>2</sub></sub> * b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) * B<sub>CO<sub>2</sub></sub> * p<sub>adsorpt,CO<sub>2</sub></sub> / ((1 + (b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) * B<sub>CO<sub>2</sub></sub> * p<sub>adsorpt,CO<sub>2</sub></sub>) ^ t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)) ^ (1/t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>))); +</pre> +<p> +with +</p> +<pre> + A<sub>CO<sub>2</sub></sub> = (1 / (1 - γ<sub>CO<sub>2</sub></sub> * x<sub>adsorpt,H<sub>2</sub>O</sub>)); +</pre> +<pre> + B<sub>CO<sub>2</sub></sub> = (1 + β<sub>CO<sub>2</sub></sub>x<sub>adsorpt,H<sub>2</sub>O</sub>); +</pre> +<p> +Herein, <i>x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)</i> is the saturation +uptake, <i>b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)</i> is the Toth coefficient, +and <i>t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>)</i> is the Toth exponent. The +coefficients <i>γ<sub>CO<sub>2</sub></sub></i> and <i>β<sub>H<sub>2</sub>O</sub></i> +are enhancement factors of the saturation uptake and the Toth coeffient, respectively, both +multiplied by the uptake of water <i>x<sub>adsorpt,H<sub>2</sub>O</sub></i>. Typical +temperature dependencies may have the following forms: +</p> +<pre> + x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) = x<sub>ref,CO<sub>2</sub></sub> * <strong>exp</strong>(Χ<sub>CO<sub>2</sub></sub> * (1 - T<sub>adsorpt</sub>/T<sub>ref,CO<sub>2</sub></sub>)); +</pre> +<pre> + b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) = b<sub>ref,CO<sub>2</sub></sub> * <strong>exp</strong>(Q<sub>CO<sub>2</sub></sub>/(R * T<sub>ref,CO<sub>2</sub></sub>) * (T<sub>ref,CO<sub>2</sub></sub>/T<sub>adsorpt</sub> - 1)); +</pre> +<pre> + t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) = t<sub>ref,CO<sub>2</sub></sub> + α<sub>CO<sub>2</sub></sub> * (1 - T<sub>ref,CO<sub>2</sub></sub>/T<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>ref,CO<sub>2</sub></sub></i> is the saturation uptake at reference +temperature <i>T<sub>ref,CO<sub>2</sub></sub></i>, <i>b<sub>ref,CO<sub>2</sub></sub></i> +is the Toth coefficient at reference temperature, and <i>t<sub>ref,CO<sub>2</sub></sub></i> +is the Toth exponent at reference temperature. The parameter <i>Q<sub>CO<sub>2</sub></sub></i> +is a measure for the isosteric adsorption enthalpy at a fractional loading of +<i>x<sub>adsorpt,CO<sub>2</sub></sub>/x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) = 0.0</i>, the +parameter <i>Χ<sub>CO<sub>2</sub></sub></i> describes the change of the saturation +uptake with temperature, and the parameter <i>α<sub>CO<sub>2</sub></sub></i> +describes the change of the Toth exponent with temperature. All seven parameters +and the two enhancement factors <i>γ<sub>CO<sub>2</sub></sub></i> and +<i>β<sub>H<sub>2</sub>O</sub></i> can be used as fitting parameters. +<br/> +<p> +The GAB isotherm model has the following form: +</p> +</p> +<pre> + x<sub>adsorpt,H<sub>2</sub>O</sub> = x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) / ((1 - k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)) * (1 + (c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) - 1) * k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>))); +</pre> +<p> +with +</p> +<pre> + φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = p<sub>adsorpt</sub>/p<sub>sat,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> is the monolayer +uptake and <i>c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> and +<i>k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> are affinity coefficients of +the GAB isotherm model. These three parameters can be modeled independent of temperature. +When assuming these three parameters to be dependent on temperature, typical temperature +dependencies may have the following forms: +</p> +<pre> + x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = x<sub>mon,ref,H<sub>2</sub>O</sub> * <strong>exp</strong>(Χ<sub>H<sub>2</sub>O</sub> * (1 - T<sub>adsorpt</sub>/T<sub>ref,H<sub>2</sub>O</sub>)); +</pre> +<pre> + c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = <strong>exp</strong>((E<sub>1,H<sub>2</sub>O</sub> - E<sub>10+,H<sub>2</sub>O</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<pre> + k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = <strong>exp</strong>((E<sub>2-9,H<sub>2</sub>O</sub> - E<sub>10+,H<sub>2</sub>O</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + E<sub>1,H<sub>2</sub>O</sub> = C<sub>H<sub>2</sub>O</sub> - <strong>exp</strong>(D<sub>H<sub>2</sub>O</sub> * T<sub>adsorpt</sub>); +</pre> +<pre> + E<sub>2-9,H<sub>2</sub>O</sub> = F<sub>H<sub>2</sub>O</sub> + G<sub>H<sub>2</sub>O</sub> * T<sub>adsorpt</sub>; +</pre> +<pre> + E<sub>10+,H<sub>2</sub>O</sub> = Δh<sub>vap,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>mon,ref,H<sub>2</sub>O</sub></i> is the monolayer uptake at reference +temperature <i>T<sub>ref,H<sub>2</sub>O</sub></i> and <i>Χ<sub>H<sub>2</sub>O</sub></i> +describes the change of the monolayer uptake with temperature. The coefficient +<i>E<sub>1,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption of the first layer +and <i>E<sub>2-9,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption of layers +2-9: These enthalpies of adsorption can be modeled temperature-dependent as shown +in the example above, with the four fitting parameters <i>C<sub>H<sub>2</sub>O</sub></i>, +<i>D<sub>H<sub>2</sub>O</sub></i>, <i>E<sub>H<sub>2</sub>O</sub></i>, and <i>F<sub>H<sub>2</sub>O</sub></i>. +The coefficient <i>E<sub>10+,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption +for layer 10 or higher layers and is assumed to correspond to the temperature-dependent +enthalpy of vaporization <i>Δh<sub>vap,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i>. +</p> + +<h4>Required parameter order in function input c[:,no_components]:</h4> +<p> +For component 1 (i.e., CO<sub>2</sub>), the required parameter order in the function +input <i>c</i> is as follows: +</p> +<ul> + <li> + c[1,1] = x<sub>sat,CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[2,1] = b<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) in 1/Pa + </li> + <li> + c[3,1] = t<sub>CO<sub>2</sub></sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[4,1] = γ<sub>CO<sub>2</sub></sub> in kg/kg + </li> + <li> + c[5,1] = β<sub>H<sub>2</sub>O</sub> in kg/kg + </li> +</ul> +<p> +For component 2 (i.e., H<sub>2</sub>0), the required parameter order in the function +input <i>c</i> is as follows: +</p> +<ul> + <li> + c[1,2] = p<sub>sat,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2,2] = x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[3,2] = c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[4,2] = k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[5,2] = 0 (i.e., not required) + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the Toth-GAB isotherm model for one parameter set. In +the upper sub-figure, the equilibrium pressure changes with time. In the centre +sub-figure, the independent mole fractions change with time. In the lower sub-figure, +the equilibrium temperature changes with time. The left side shows the uptake of +component 1 (i.e., CO<sub>2</sub>), and the right side shows the uptake of component +2 (i.e., H<sub>2</sub>0). +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_multi_toth_gab_sb.png\" alt=\"media_functions_equilibria_multi_toth_gab_sb.png\"> + +<h4>References</h4> +<ul> + <li> + <li> + Stampi-Bombelli, V. and van der Spek, M. and Mazzotti, M. (2020). Analysis of direct capture of CO2 from ambient air via steamassisted temperature-vacuum swing adsorption, Adsorption, 26(7):1183–1197. DOI: http://doi.org/10.1007/s10450-020-00249-w. + </li> +</ul> +</html>")); +end TothGAB_StampiBombelli; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6d0f8d93aba1f8e0f67c45861309e4734531ccf1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/TothGAB_StampiBombelli/package.order @@ -0,0 +1,8 @@ +Internals +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/p_i_xT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/p_i_xT.mo new file mode 100644 index 0000000000000000000000000000000000000000..1330a6aff12f2cb8dab41474fd37a81628e6a118 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/p_i_xT.mo @@ -0,0 +1,205 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals; +function p_i_xT + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Partial pressures as function of uptakes and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptakes of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt_lb_start = 1 + "Lower bound of equilibrium pressure (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Modelica.Units.SI.Pressure p_adsorpt_ub_start = 10 + "Upper bound of equilibrium pressure (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for numerical calculation (i.e., root finding))" + annotation (Dialog(tab="General", group="Numerical inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[size(c,2)] p_i + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of functions + // +protected + function func_p_CO2_num + "Function used to find root (i.e., p_adsorpt_CO2) numerically" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input Real c[:,:] + "Coefficients of isotherm model"; + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature"; + input SorpLib.Units.Uptake[size(c,2)] x_adsorpt + "Equilibrium uptake"; + + input Modelica.Units.SI.Pressure p_threshold_min + "Threshold for partial pressure of all components: If a partial pressure is + below the threshold, its value is set to the threshold"; + algorithm + y := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.x_CO2_pTx( + p_CO2=u, + x_adsorpt_H2O=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) - x_adsorpt[1] + "Function '0 = x(p_adsorpt_CO2, x_adsorpt_H2O, T_adsorpt, c) - x_adsorpt_CO2' + used to find root (i.e., p_adsorpt) numerically"; + end func_p_CO2_num; + + // + // Definition of variables + // + Boolean bound_ok = false + "= true, if bounds are found such that func_p_CO2_num(lb) < 0 and + func_p_CO2_num(ub) > 0"; + + Modelica.Units.SI.Pressure p_adsorpt_CO2_lb = p_adsorpt_lb_start + "Current best lower bound of equilibrium pressure"; + Modelica.Units.SI.Pressure p_adsorpt_CO2_ub = p_adsorpt_ub_start + "Current best upper bound of equilibrium pressure"; + + SorpLib.Units.Uptake x_adsorpt_CO2_lb= + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.x_CO2_pTx( + p_CO2=p_adsorpt_CO2_lb, + x_adsorpt_H2O=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Equilibrium uptake at current best lower bound of equilibrium pressure"; + SorpLib.Units.Uptake x_adsorpt_CO2_ub= + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.x_CO2_pTx( + p_CO2=p_adsorpt_CO2_ub, + x_adsorpt_H2O=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Equilibrium uptake at current best upper bound of equilibrium pressure"; + +algorithm + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // First, calculte the equilibrium pressure of component 2 (i.e., H2O) + // + // + p_i[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.p_xT( + x_adsorpt=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium pressure of H2O"; + + p_i[2] := max(p_i[2], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Second, find start values such that func_p_CO2_num(lb) < 0 and func_p_CO2_num(ub) > 0 + // + // Reducing p_adsorpt_CO2 reduces x_adsorpt_CO2 -> func_p_CO2_num(p_adsorpt_CO2) + // can become < 0 + // Increasing p_adsorpt_CO2 increases x_adsorpt_CO2 -> func_p_CO2_num(p_adsorpt_CO2) + // can become > 0 + // + while not bound_ok loop + if Modelica.Math.isEqual(s1=x_adsorpt_CO2_lb, s2=x_adsorpt[1], eps=tolerance) then + p_i[1] := max(p_adsorpt_CO2_lb, p_threshold_min); + bound_ok := true; + return; + + elseif Modelica.Math.isEqual(s1=x_adsorpt_CO2_ub, s2=x_adsorpt[1], eps=tolerance) then + p_i[1] := max(p_adsorpt_CO2_ub, p_threshold_min); + bound_ok := true; + return; + + elseif x_adsorpt_CO2_lb-x_adsorpt[1] < 0 and x_adsorpt_CO2_ub-x_adsorpt[1] < 0 then + p_adsorpt_CO2_lb := p_adsorpt_CO2_ub; + x_adsorpt_CO2_lb := x_adsorpt_CO2_ub; + + p_adsorpt_CO2_ub := p_adsorpt_CO2_ub*10; + x_adsorpt_CO2_ub := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.x_CO2_pTx( + p_CO2=p_adsorpt_CO2_ub, + x_adsorpt_H2O=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min); + + elseif x_adsorpt_CO2_lb-x_adsorpt[1] > 0 and x_adsorpt_CO2_ub-x_adsorpt[1] > 0 then + p_adsorpt_CO2_ub := p_adsorpt_CO2_lb; + x_adsorpt_CO2_ub := x_adsorpt_CO2_lb; + + p_adsorpt_CO2_lb := if p_adsorpt_CO2_lb > Modelica.Constants.small then + p_adsorpt_CO2_lb*0.1 else 0; + x_adsorpt_CO2_lb := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.x_CO2_pTx( + p_CO2=p_adsorpt_CO2_lb, + x_adsorpt_H2O=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min); + + else + bound_ok := true; + + end if; + end while; + + // + // Third, find root in the interval lb <= root <= up + // + p_i[1] := Modelica.Math.Nonlinear.solveOneNonlinearEquation( + f=function func_p_CO2_num( + c=c, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + p_threshold_min=p_threshold_min), + u_min=p_adsorpt_CO2_lb, + u_max=p_adsorpt_CO2_ub, + tolerance=tolerance) + "Calculation of the equilibrium pressure of the adsorpt phase"; + + p_i[1] := max(p_i[1], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium pressures <i>p_i</i> (i.e., partial +pressures) as function of the equilibrium uptakes <i>x_adsorpt</i> and the +equilibrium temperature <i>T_adsorpt</i>. Thus, this function is a inverse of the +function 'x_pyT.' For full details of the original function 'x_pyT,' check the +documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + August 2, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end p_i_xT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a2c6953493153985029908a55db58542b29b25c0 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB; +package Internals "Internal functions used to avoid redundancy" + extends Modelica.Icons.InternalPackage; + + annotation (Documentation(info="<html> +<p> +This package contains functions used for various functions of the weighted- +average dual site Toth-GAB isotherm model. Thus, redundancy of code shall +be avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + August 2, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Internals; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/package.order new file mode 100644 index 0000000000000000000000000000000000000000..ed828e2e77014397c886f5c69de19adafa31d44a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/package.order @@ -0,0 +1,3 @@ +p_i_xT +x_CO2_pTx +x_H20_pT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/x_CO2_pTx.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/x_CO2_pTx.mo new file mode 100644 index 0000000000000000000000000000000000000000..26247ed6b9d07fe0ef329c3885c881faa5e800a9 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/x_CO2_pTx.mo @@ -0,0 +1,76 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals; +function x_CO2_pTx + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Equilibrium uptake of component 1 (i.e., CO2) as function of partial pessures and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_CO2 + "Equilibrium pressures of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptake of component 2 (i.e., H2O)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake x_adsorpt_CO2 + "Equilibrium uptake of component 1 (i.e., CO2)" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + // + // Calculate equilibrium uptake + // + x_adsorpt_CO2 := (1 - Modelica.Math.exp(-c[4,1] / x_adsorpt_H2O)) * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_CO2, p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1,1], + c[2,1], + c[3,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + Modelica.Math.exp(-c[4,1] / x_adsorpt_H2O) * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_CO2, p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[5,1], + c[6,1], + c[7,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of CO2"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium uptake of component 1 (i.e., CO2) +<i>x_adsorpt_CO2</i> as function of the partial equilibrium pressure of CO2 <i>p_CO2</i>, +the equilibrium uptake of component 2 (i.e., H2O) <i>x_adsorpt_H2O</i>, and the +equilibrium temperature <i>T_adsorpt</i>. For full details of the isotherm model, +check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + August 2, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_CO2_pTx; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/x_H20_pT.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/x_H20_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..bbeb2abcfb75f5646860847aee5d10319d137ca0 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/Internals/x_H20_pT.mo @@ -0,0 +1,86 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals; +function x_H20_pT + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Equilibrium uptake of component 2 (i.e., H2O) as function of partial pessures and temperature" + extends SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialMulti; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_H2O + "Equilibrium pressure of H2O of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptake of component 2 (i.e., H2O)" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O_max= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.x_pT( + p_adsorpt=max(c[1,2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Maximal equilibrium uptake of H2O achieved at relative humidity of 1 (i.e., + p_adsorpt_H2O = p_sat_H2O"; + +algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the equilibrium uptake of component 1 (i.e., CO2) + // + // + x_adsorpt_H2O := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.x_pT( + p_adsorpt=max(p_H2O, p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium uptake of H2O"; + + x_adsorpt_H2O := min(x_adsorpt_H2O, x_adsorpt_H2O_max) + "Limit equilibrium uptake of H2O to its maximal equilibrium uptake"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the equilibrium uptake of component 2 (i.e., H2O) +<i>x_adsorpt_H2O</i> as function of the partial equilibrium pressure of H2O <i>p_H2O</i> +and the equilibrium temperature <i>T_adsorpt</i>. For full details of the isotherm +model, check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.x_pyT\">SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.x_pyT</a>. +</p> +</p> +</html>", revisions="<html> +<ul> + <li> + August 2, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end x_H20_pT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..04b824749835545d8f830b4b5a9f0ccf1b97536c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/package.mo @@ -0,0 +1,831 @@ +within SorpLib.Media.Functions.SorptionEquilibria.MultiComponents; +package WeightedAverageDualSiteTothGAB "Package containing all functions regarding the weighted-average dual site Toth-GAB isotherm developed by Young et al. (2021) for adsorption of CO2 & H2O" + extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialMultiComponents; + + // + // Internal package + // + redeclare final function extends x_pyT + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Uptakes as function of pressure, mole fractions of independent gas phase components, and temperature" + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the equilibrium uptake of component 1 (i.e., CO2) + // + x_adsorpt[2] := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.x_H20_pT( + p_H2O=p_i[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate the equilibrium uptake of component 1 (i.e., CO2) + // + x_adsorpt[1] := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.x_CO2_pTx( + p_CO2=p_i[1], + x_adsorpt_H2O=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of CO2"; + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end x_pyT; + + redeclare final function extends p_xyT + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Pressure as function of uptakes, mole fractions of independent gas phase components, and temperature" + algorithm + // + // First, calculte the equilibrium pressure of component 2 (i.e., H2O) + // + p_i[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.p_xT( + x_adsorpt=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium pressure of H2O"; + + p_i[2] := max(p_i[2], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Second, calculte the equilibrium pressure of component 1 (i.e., CO2) + // + p_i[1] := y_i[1] * (p_i[2] / (1-y_i[1])) + "Calculate equilibrium pressure of CO2"; + + p_i[1] := max(p_i[1], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Third, calculate the equilibrium pressure + // + p_adsorpt := sum(p_i) + "Equilibrium pressure"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + y_i = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.y_pxT(p_adsorpt=p_adsorpt, x_adsorpt=x_adsorpt, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end p_xyT; + + redeclare final function extends y_pxT + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Mole fractions of independent gas phase components as function of uptakes, pressure, and temperature" + algorithm + // + // First, calculte the equilibrium pressure of component 2 (i.e., H2O) + // + p_i[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.p_xT( + x_adsorpt=x_adsorpt[2], + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Calculate equilibrium pressure of H2O"; + + p_i[2] := max(p_i[2], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Second, calculte the equilibrium pressure of component 1 (i.e., CO2) + // + p_i[1] := (1 - p_i[2] / max(p_adsorpt, p_threshold_min)) * max(p_adsorpt, p_threshold_min) + "Calculate equilibrium pressure of CO2"; + + p_i[1] := max(p_i[1], p_threshold_min) + "Limit equilibrium pressure if necessary"; + + // + // Third, calculate the independent mole fractions (i.e., mole fraction of + // component 1) + // + y_i[1] := p_i[1] / max(p_adsorpt, p_threshold_min) + "Mole fractions of independent component in the gas or vapor phase"; + + // + // Assertions + // + assert(size(c,2)==2, + "This function is only valid for the two components CO2 and H2O with this order!", + level=AssertionLevel.error); + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.x_pyT(p_adsorpt=p_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance), + p_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.p_xyT(x_adsorpt=x_adsorpt, y_i=y_i, T_adsorpt=T_adsorpt, c=c, p_threshold_min=p_threshold_min, p_adsorpt_lb_start=p_adsorpt_lb_start, p_adsorpt_ub_start=p_adsorpt_ub_start, tolerance=tolerance))); + end y_pxT; + + redeclare final function extends py_xT + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Pressure and mole fractions of independent gas phase components as function of uptakes and temperature (numerical solution)" + algorithm + p_i := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.p_i_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min, + p_adsorpt_lb_start=p_adsorpt_lb_start, + p_adsorpt_ub_start=p_adsorpt_ub_start, + tolerance=tolerance) + "Partial pressures"; + + p_adsorpt := max(sum(p_i), p_threshold_min) + "Equilibrium pressure"; + + for ind in 1:size(c,2)-1 loop + y_i[ind] := p_i[ind] / p_adsorpt + "Mole fractions of independent components in the gas or vapor phase"; + end for; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true); + end py_xT; + + redeclare final function extends dx_dp + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Partial derivative of uptakes w.r.t. pressure at constant mole fractions and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptakes of component 2 (i.e., H2O)"; + + Real C_CO2_wet(unit="1") + "Contribution of saturation uptake of CO2 under wet conditions"; + Real C_CO2_dry(unit="1") + "Contribution of saturation uptake of CO2 under dry conditions"; + + SorpLib.Units.Uptake x_adsorpt_CO2_wet + "Equilibrium uptakes of component 1 (i.e., CO2) under wet conditions"; + SorpLib.Units.Uptake x_adsorpt_CO2_dry + "Equilibrium uptakes of component 1 (i.e., CO2) under dry conditions"; + + Real dC_CO2_wet_dx_adsorpt_H2O(unit="kg/kg") + "Partial derivative of contribution of saturation uptake of CO2 under wet + conditions w.r.t. equilibrium uptake of H2O"; + Real dC_CO2_dry_dx_adsorpt_H2O(unit="kg/kg") + "Partial derivative of contribution of saturation uptake of CO2 under dry + conditions w.r.t. equilibrium uptake of H2O"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_CO2_wet_dp_adsorpt + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + wet conditions w.r.t. equilibrium pressure"; + SorpLib.Units.DerUptakeByPressure dx_adsorpt_CO2_dry_dp_adsorpt + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + dry conditions w.r.t. equilibrium pressure"; + + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the partial derivative of the equilibrium uptake + // w.r.t. the equilibrium pressure of component 1 (i.e., CO2) + // + x_adsorpt_H2O := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.x_H20_pT( + p_H2O=p_i[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate partial derivatives: + // + // The partial derivative of component 2 (i.e., H2O) must be calculated first + // because it is required to calculate the partial derivative of component 1 + // (i.e., CO2). + // + // The existing derivative function of the GAB isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // equilibrium pressure (i.e., y_i_[2]). + // + dx_adsorpt_dp_adsorpt[2] := y_i_[2] * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dp( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + + // + // The existing derivative function of the Toth isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // equilibrium pressure (i.e., y_i_[1]). + // + C_CO2_wet := Modelica.Math.exp(-c[4,1] / x_adsorpt_H2O) + "Contribution of saturation uptake of CO2 under wet conditions"; + C_CO2_dry := (1 - C_CO2_wet) + "Contribution of saturation uptake of CO2 under dry conditions"; + + x_adsorpt_CO2_wet := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[5,1], + c[6,1], + c[7,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Equilibrium uptakes of component 1 (i.e., CO2) under wet conditions"; + x_adsorpt_CO2_dry := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1,1], + c[2,1], + c[3,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Equilibrium uptakes of component 1 (i.e., CO2) under dry conditions"; + + dC_CO2_wet_dx_adsorpt_H2O := + c[4,1] * C_CO2_wet / x_adsorpt_H2O^2 + "Partial derivative of contribution of saturation uptake of CO2 under wet + conditions w.r.t. equilibrium uptake of H2O"; + dC_CO2_dry_dx_adsorpt_H2O := + -dC_CO2_wet_dx_adsorpt_H2O + "Partial derivative of contribution of saturation uptake of CO2 under dry + conditions w.r.t. equilibrium uptake of H2O"; + + dx_adsorpt_CO2_wet_dp_adsorpt := y_i_[1] * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dp( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[5,1], + c[6,1], + c[7,1]}) + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + wet conditions w.r.t. equilibrium pressure"; + dx_adsorpt_CO2_dry_dp_adsorpt := y_i_[1] * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dp( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1,1], + c[2,1], + c[3,1]}) + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + dry conditions w.r.t. equilibrium pressure"; + + dx_adsorpt_dp_adsorpt[1] := + dC_CO2_dry_dx_adsorpt_H2O * dx_adsorpt_dp_adsorpt[2] * x_adsorpt_CO2_dry + + C_CO2_dry * dx_adsorpt_CO2_dry_dp_adsorpt + + dC_CO2_wet_dx_adsorpt_H2O * dx_adsorpt_dp_adsorpt[2] * x_adsorpt_CO2_wet + + C_CO2_wet * dx_adsorpt_CO2_wet_dp_adsorpt + "Partial derivative of first component's equilibrium uptake w.r.t. the + equilibrium pressure at constant mole fractions and temperature"; + end dx_dp; + + redeclare final function extends dx_dy + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Partial derivative of uptakes w.r.t. mole fractions of independent gas phase components at constant pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptakes of component 2 (i.e., H2O)"; + + Real C_CO2_wet(unit="1") + "Contribution of saturation uptake of CO2 under wet conditions"; + Real C_CO2_dry(unit="1") + "Contribution of saturation uptake of CO2 under dry conditions"; + + SorpLib.Units.Uptake x_adsorpt_CO2_wet + "Equilibrium uptakes of component 1 (i.e., CO2) under wet conditions"; + SorpLib.Units.Uptake x_adsorpt_CO2_dry + "Equilibrium uptakes of component 1 (i.e., CO2) under dry conditions"; + + Real dC_CO2_wet_dx_adsorpt_H2O(unit="kg/kg") + "Partial derivative of contribution of saturation uptake of CO2 under wet + conditions w.r.t. equilibrium uptake of H2O"; + Real dC_CO2_dry_dx_adsorpt_H2O(unit="kg/kg") + "Partial derivative of contribution of saturation uptake of CO2 under dry + conditions w.r.t. equilibrium uptake of H2O"; + + SorpLib.Units.DerUptakeByMolarFraction dx_adsorpt_CO2_wet_dy_i + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + wet conditions w.r.t. independent mole fractions"; + SorpLib.Units.DerUptakeByMolarFraction dx_adsorpt_CO2_dry_dy_i + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + dry conditions w.r.t. independent mole fractions"; + + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the partial derivative of the equilibrium uptake + // w.r.t. the independent mole fractions of component 1 (i.e., CO2) + // + x_adsorpt_H2O := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.x_H20_pT( + p_H2O=p_i[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate partial derivatives: + // + // The partial derivative of component 2 (i.e., H2O) must be calculated first + // because it is required to calculate the partial derivative of component 1 + // (i.e., CO2). + // + // The existing derivative function of the GAB isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // independent mole fractions (i.e., -p_adsorpt) + // + dx_adsorpt_dy_i[2,1] := -p_adsorpt * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dp( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + independent mole fractions at contant pressure and temperature"; + + // + // The existing derivative function of the Toth isotherm model corresponds to + // the partial derivative w.r.t. the partial pressure. Hence, the result must + // be multiplied by the partial derivative of the partial pressure w.r.t. the + // independent mole fractions (i.e., p_adsorpt) + // + C_CO2_wet := Modelica.Math.exp(-c[4,1] / x_adsorpt_H2O) + "Contribution of saturation uptake of CO2 under wet conditions"; + C_CO2_dry := (1 - C_CO2_wet) + "Contribution of saturation uptake of CO2 under dry conditions"; + + x_adsorpt_CO2_wet := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[5,1], + c[6,1], + c[7,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Equilibrium uptakes of component 1 (i.e., CO2) under wet conditions"; + x_adsorpt_CO2_dry := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1,1], + c[2,1], + c[3,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Equilibrium uptakes of component 1 (i.e., CO2) under dry conditions"; + + dC_CO2_wet_dx_adsorpt_H2O := + c[4,1] * C_CO2_wet / x_adsorpt_H2O^2 + "Partial derivative of contribution of saturation uptake of CO2 under wet + conditions w.r.t. equilibrium uptake of H2O"; + dC_CO2_dry_dx_adsorpt_H2O := + -dC_CO2_wet_dx_adsorpt_H2O + "Partial derivative of contribution of saturation uptake of CO2 under dry + conditions w.r.t. equilibrium uptake of H2O"; + + dx_adsorpt_CO2_wet_dy_i := p_adsorpt * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dp( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[5,1], + c[6,1], + c[7,1]}) + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + wet conditions w.r.t. independent mole fractions"; + dx_adsorpt_CO2_dry_dy_i := p_adsorpt * + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dp( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1,1], + c[2,1], + c[3,1]}) + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + dry conditions w.r.t. independent mole fractions"; + + dx_adsorpt_dy_i[1, 1] := + dC_CO2_dry_dx_adsorpt_H2O * dx_adsorpt_dy_i[2,1] * x_adsorpt_CO2_dry + + C_CO2_dry * dx_adsorpt_CO2_dry_dy_i + + dC_CO2_wet_dx_adsorpt_H2O * dx_adsorpt_dy_i[2,1] * x_adsorpt_CO2_wet + + C_CO2_wet * dx_adsorpt_CO2_wet_dy_i + "Partial derivative of first component's equilibrium uptake w.r.t. the + independent mole fractions at constant pressure and temperature"; + end dx_dy; + + redeclare final function extends dx_dT + "Weighted-average dual site Toth-GAB isotherm model developed by Young et al. (2021): Partial derivative of uptakes w.r.t. temperature at constant pressure and mole fractions" + + // + // Definition of variables + // +protected + SorpLib.Units.Uptake x_adsorpt_H2O + "Equilibrium uptakes of component 2 (i.e., H2O)"; + + Real C_CO2_wet(unit="1") + "Contribution of saturation uptake of CO2 under wet conditions"; + Real C_CO2_dry(unit="1") + "Contribution of saturation uptake of CO2 under dry conditions"; + + SorpLib.Units.Uptake x_adsorpt_CO2_wet + "Equilibrium uptakes of component 1 (i.e., CO2) under wet conditions"; + SorpLib.Units.Uptake x_adsorpt_CO2_dry + "Equilibrium uptakes of component 1 (i.e., CO2) under dry conditions"; + + Real dC_CO2_wet_dc4(unit="kg/kg") + "Partial derivative of contribution of saturation uptake of CO2 under wet + conditions w.r.t. fourth coefficient of the weighted-average dual site Toth + isotherm model"; + Real dC_CO2_dry_dc4(unit="kg/kg") + "Partial derivative of contribution of saturation uptake of CO2 under dry + conditions w.r.t. fourth coefficient of the weighted-average dual site Toth + isotherm model"; + Real dC_CO2_wet_dx_adsorpt_H2O(unit="kg/kg") + "Partial derivative of contribution of saturation uptake of CO2 under wet + conditions w.r.t. equilibrium uptake of H2O"; + Real dC_CO2_dry_dx_adsorpt_H2O(unit="kg/kg") + "Partial derivative of contribution of saturation uptake of CO2 under dry + conditions w.r.t. equilibrium uptake of H2O"; + + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_CO2_wet_dT_adsorpt + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + wet conditions w.r.t. equilibrium temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_CO2_dry_dT_adsorpt + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + dry conditions w.r.t. equilibrium temperature"; + + algorithm + // + // First, calculte the equilibrium uptake of component 2 (i.e., H2O) because it + // is required to calculate the partial derivative of the equilibrium uptake + // w.r.t. the equilibrium temperature of component 1 (i.e., CO2) + // + x_adsorpt_H2O := + SorpLib.Media.Functions.SorptionEquilibria.MultiComponents.WeightedAverageDualSiteTothGAB.Internals.x_H20_pT( + p_H2O=p_i[2], + T_adsorpt=T_adsorpt, + c=c, + p_threshold_min=p_threshold_min) + "Calculate equilibrium uptake of H2O limited to its maximal equilibrium uptake"; + + // + // Second, calculate partial derivatives: + // + // The existing derivative functions of the Toth and GAB isotherm models + // correspond to partial derivatives w.r.t. the equilibrium temperature. Again, + // the partial derivative of component 2 (i.e., H2O) must be calculated first + // because it is required to calculate the partial derivative of component 1 + // (i.e., CO2). + // + dx_adsorpt_dT_adsorpt[2] := SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.dx_dT( + p_adsorpt=max(p_i[2], p_threshold_min), + T_adsorpt=T_adsorpt, + c={max(c[1,2], p_threshold_min), + c[2,2], + c[3,2], + c[4,2]}, + dc_dT_adsorpt={dc_dT_adsorpt[1,2], + dc_dT_adsorpt[2,2], + dc_dT_adsorpt[3,2], + dc_dT_adsorpt[4,2]}) + "Partial derivative of second component's equilibrium uptake w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + + // + // Note that for component 1, the coefficients of the isotherm model are + // enhanced by the uptake of component 2. Hence, the parameter dc_dT cannot + // directly be passed to the existing derivative function of the Toth isotherm + // model. Instead, the the correct derivative must be calculated first. + // + C_CO2_wet := Modelica.Math.exp(-c[4,1] / x_adsorpt_H2O) + "Contribution of saturation uptake of CO2 under wet conditions"; + C_CO2_dry := (1 - C_CO2_wet) + "Contribution of saturation uptake of CO2 under dry conditions"; + + x_adsorpt_CO2_wet := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[5,1], + c[6,1], + c[7,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Equilibrium uptakes of component 1 (i.e., CO2) under wet conditions"; + x_adsorpt_CO2_dry := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1,1], + c[2,1], + c[3,1]}, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Equilibrium uptakes of component 1 (i.e., CO2) under dry conditions"; + + dC_CO2_wet_dc4 := -C_CO2_wet / x_adsorpt_H2O + "Partial derivative of contribution of saturation uptake of CO2 under wet + conditions w.r.t. fourth coefficient of the weighted-average dual site Toth + isotherm model"; + dC_CO2_dry_dc4 := -dC_CO2_wet_dc4 + "Partial derivative of contribution of saturation uptake of CO2 under dry + conditions w.r.t. fourth coefficient of the weighted-average dual site Toth + isotherm model"; + dC_CO2_wet_dx_adsorpt_H2O := + c[4,1] * C_CO2_wet / x_adsorpt_H2O^2 + "Partial derivative of contribution of saturation uptake of CO2 under wet + conditions w.r.t. equilibrium uptake of H2O"; + dC_CO2_dry_dx_adsorpt_H2O := + -dC_CO2_wet_dx_adsorpt_H2O + "Partial derivative of contribution of saturation uptake of CO2 under dry + conditions w.r.t. equilibrium uptake of H2O"; + + dx_adsorpt_CO2_wet_dT_adsorpt := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[5,1], + c[6,1], + c[7,1]}, + dc_dT_adsorpt={dc_dT_adsorpt[5,1], + dc_dT_adsorpt[6,1], + dc_dT_adsorpt[7,1]}) + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + wet conditions w.r.t. equilibrium temperature"; + dx_adsorpt_CO2_dry_dT_adsorpt := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.dx_dT( + p_adsorpt=max(p_i[1], p_threshold_min), + T_adsorpt=T_adsorpt, + c={c[1,1], + c[2,1], + c[3,1]}, + dc_dT_adsorpt={dc_dT_adsorpt[1,1], + dc_dT_adsorpt[2,1], + dc_dT_adsorpt[3,1]}) + "Partial derivative of equilibrium uptakes of component 1 (i.e., CO2) under + dry conditions w.r.t. equilibrium temperature"; + + dx_adsorpt_dT_adsorpt[1] := + (dC_CO2_dry_dc4 * dc_dT_adsorpt[4,1] + dC_CO2_dry_dx_adsorpt_H2O * + dx_adsorpt_dT_adsorpt[2]) * x_adsorpt_CO2_dry + + C_CO2_dry * dx_adsorpt_CO2_dry_dT_adsorpt + + (dC_CO2_wet_dc4 * dc_dT_adsorpt[4,1] + dC_CO2_wet_dx_adsorpt_H2O * + dx_adsorpt_dT_adsorpt[2]) * x_adsorpt_CO2_wet + + C_CO2_wet * dx_adsorpt_CO2_wet_dT_adsorpt + "Partial derivative of first component's equilibrium uptake w.r.t. the + equilibrium pressure at constant pressure and mole fractions"; + end dx_dT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + August 2, 2024, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +The weighted-average dual site Toth-GAB isotherm model calculates equilibrium +uptakes <i>x_adsorpt</i> of CO<sub>2</sub> and H<sub>2</sub>O on amine-functionalized +sorbents as a function of the equilibrium pressure <i>p_adsorpt</i>, mole fractions +of independent components in the gas or vapor phase <i>y_i</i>, and the equilibrium +temperature <i>T_adsorpt</i>. The model was developed by Young et al. (2021) for +modeling of direct air capture systems. A weighted-average dual site Toth isotherm +model describes the uptake of CO<sub>2</sub>, while a GAB isotherm model describes +the uptake of H<sub>2</sub>O. +</p> + +<h4>Main equations</h4> +<p> +The weighted-average dual site Toth isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt,CO<sub>2</sub></sub> = (1 - <strong>exp</strong>(-C<sub>CO<sub>2</sub></sub> / x<sub>adsorpt,H<sub>2</sub>O</sub>)) * x<sub>adsorpt,CO<sub>2</sub>,dry</sub> + <strong>exp</strong>(-C<sub>CO<sub>2</sub></sub> / x<sub>adsorpt,H<sub>2</sub>O</sub>) * x<sub>adsorpt,CO<sub>2</sub>,wet</sub>; +</pre> +<p> +with: +</p> +<pre> + x<sub>adsorpt,CO<sub>2</sub>,dry</sub> = x<sub>sat,CO<sub>2</sub>,dry</sub>(T<sub>adsorpt</sub>) * b<sub>CO<sub>2</sub>,dry</sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,CO<sub>2</sub></sub> / ((1 + (b<sub>CO<sub>2</sub>,dry</sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,CO<sub>2</sub></sub>) ^ t<sub>CO<sub>2</sub>,dry</sub>(T<sub>adsorpt</sub>)) ^ (1/t<sub>CO<sub>2</sub>,dry</sub>(T<sub>adsorpt</sub>))); +</pre> +<pre> + x<sub>adsorpt,CO<sub>2</sub>,wet</sub> = x<sub>sat,CO<sub>2</sub>,wet</sub>(T<sub>adsorpt</sub>) * b<sub>CO<sub>2</sub>,wet</sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,CO<sub>2</sub></sub> / ((1 + (b<sub>CO<sub>2</sub>,wet</sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt,CO<sub>2</sub></sub>) ^ t<sub>CO<sub>2</sub>,wet</sub>(T<sub>adsorpt</sub>)) ^ (1/t<sub>CO<sub>2</sub>,wet</sub>(T<sub>adsorpt</sub>))); +</pre> +<p> +Herein, <i>x<sub>sat,CO<sub>2</sub>,i</sub>(T<sub>adsorpt</sub>)</i> is the +saturation uptake, <i>b<sub>CO<sub>2</sub>,i</sub>(T<sub>adsorpt</sub></i> is +the Toth coefficient, and <i>t<sub>CO<sub>2</sub>,i</sub>(T<sub>adsorpt</sub>)</i> +is the Toth exponent under dry (i.e., <i>i = dry</i>) or wet (i.e., <i>i = wet</i>). +conditions. The coefficient <i>C<sub>CO<sub>2</sub></sub></i> describes the +critical water loading to accout for the presence of H<sub>2</sub>O (i.e., +H<sub>2</sub>O uptake). Typical temperature dependencies may have the following +forms: +</p> +<pre> + x<sub>sat,i</sub>(T<sub>adsorpt</sub>) = x<sub>ref,i</sub> * <strong>exp</strong>(Χ<sub>i</sub> * (1 - T<sub>adsorpt</sub>/T<sub>ref,i</sub>)); +</pre> +<pre> + b<sub>i</sub>(T<sub>adsorpt</sub>) = b<sub>ref,i</sub> * <strong>exp</strong>(Q<sub>i</sub>/(R * T<sub>ref,i</sub>) * (T<sub>ref,i</sub>/T<sub>adsorpt</sub> - 1)); +</pre> +<pre> + t<sub>i</sub>(T<sub>adsorpt</sub>) = t<sub>ref,i</sub> + α<sub>i</sub> * (1 - T<sub>ref,i</sub>/T<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>ref,i</sub></i> is the saturation uptake at reference temperature +<i>T<sub>ref,i</sub></i> under dry (i.e., <i>i = dry</i>) or wet (i.e., <i>i = +wet</i>). conditions, <i>b<sub>ref,i</sub></i> is the Toth coefficient at reference +temperature, and <i>t<sub>ref,i</sub></i> is the Toth exponent at reference +temperature. The parameter <i>Q<sub>i</sub></i> is a measure for the isosteric +adsorption enthalpy, the parameter <i>Χ<sub>i</sub></i> describes the change +of the saturation uptake with temperature, and the parameter <i>α<sub>i</sub></i> +describes the change of the Toth exponent with temperature. All parameters can be +used as fitting parameters. +<br/> +<p> +The GAB isotherm model has the following form: +</p> +</p> +<pre> + x<sub>adsorpt,H<sub>2</sub>O</sub> = x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) / ((1 - k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)) * (1 + (c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) - 1) * k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) * φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>))); +</pre> +<p> +with +</p> +<pre> + φ<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = p<sub>adsorpt</sub>/p<sub>sat,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> is the monolayer +uptake and <i>c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> and +<i>k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i> are affinity coefficients of +the GAB isotherm model. These three parameters can be modeled independent of temperature. +When assuming these three parameters to be dependent on temperature, typical temperature +dependencies may have the following forms: +</p> +<pre> + x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = x<sub>mon,ref,H<sub>2</sub>O</sub> * <strong>exp</strong>(Χ<sub>H<sub>2</sub>O</sub> * (1 - T<sub>adsorpt</sub>/T<sub>ref,H<sub>2</sub>O</sub>)); +</pre> +<pre> + c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = <strong>exp</strong>((E<sub>1,H<sub>2</sub>O</sub> - E<sub>10+,H<sub>2</sub>O</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<pre> + k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) = <strong>exp</strong>((E<sub>2-9,H<sub>2</sub>O</sub> - E<sub>10+,H<sub>2</sub>O</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + E<sub>1,H<sub>2</sub>O</sub> = C<sub>H<sub>2</sub>O</sub> - <strong>exp</strong>(D<sub>H<sub>2</sub>O</sub> * T<sub>adsorpt</sub>); +</pre> +<pre> + E<sub>2-9,H<sub>2</sub>O</sub> = F<sub>H<sub>2</sub>O</sub> + G<sub>H<sub>2</sub>O</sub> * T<sub>adsorpt</sub>; +</pre> +<pre> + E<sub>10+,H<sub>2</sub>O</sub> = Δh<sub>vap,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>mon,ref,H<sub>2</sub>O</sub></i> is the monolayer uptake at reference +temperature <i>T<sub>ref,H<sub>2</sub>O</sub></i> and <i>Χ<sub>H<sub>2</sub>O</sub></i> +describes the change of the monolayer uptake with temperature. The coefficient +<i>E<sub>1,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption of the first layer +and <i>E<sub>2-9,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption of layers +2-9: These enthalpies of adsorption can be modeled temperature-dependent as shown +in the example above, with the four fitting parameters <i>C<sub>H<sub>2</sub>O</sub></i>, +<i>D<sub>H<sub>2</sub>O</sub></i>, <i>E<sub>H<sub>2</sub>O</sub></i>, and <i>F<sub>H<sub>2</sub>O</sub></i>. +The coefficient <i>E<sub>10+,H<sub>2</sub>O</sub></i> is the enthalpy of adsorption +for layer 10 or higher layers and is assumed to correspond to the temperature-dependent +enthalpy of vaporization <i>Δh<sub>vap,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>)</i>. +</p> + +<h4>Required parameter order in function input c[:,no_components]:</h4> +<p> +For component 1 (i.e., CO<sub>2</sub>), the required parameter order in the function +input <i>c</i> is as follows: +</p> +<ul> + <li> + c[1,1] = x<sub>sat,CO<sub>2</sub>,dry</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[2,1] = b<sub>CO<sub>2</sub>,dry</sub>(T<sub>adsorpt</sub>) in 1/Pa + </li> + <li> + c[3,1] = t<sub>CO<sub>2</sub>,dry</sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[4,1] = C<sub>CO<sub>2</sub></sub> in kg/kg + </li> + <li> + c[5,1] = x<sub>sat,CO<sub>2</sub>,wet</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[6,1] = b<sub>CO<sub>2</sub>,wet</sub>(T<sub>adsorpt</sub>) in 1/Pa + </li> + <li> + c[7,1] = t<sub>CO<sub>2</sub>,wet</sub>(T<sub>adsorpt</sub>) in - + </li> +</ul> +<p> +For component 2 (i.e., H<sub>2</sub>0), the required parameter order in the function +input <i>c</i> is as follows: +</p> +<ul> + <li> + c[1,2] = p<sub>sat,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2,2] = x<sub>mon,H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[3,2] = c<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[4,2] = k<sub>H<sub>2</sub>O</sub>(T<sub>adsorpt</sub>) in - + </li> + <li> + c[5,2] = 0 (i.e., not required) + </li> + <li> + c[6,2] = 0 (i.e., not required) + </li> + <li> + c[7,2] = 0 (i.e., not required) + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the weighted-average dual site Toth-GAB isotherm model +for one parameter set. In the upper sub-figure, the equilibrium pressure changes +with time. In the centre sub-figure, the independent mole fractions change with +time. In the lower sub-figure, the equilibrium temperature changes with time. The +left side shows the uptake of component 1 (i.e., CO<sub>2</sub>), and the right +side shows the uptake of component 2 (i.e., H<sub>2</sub>0). +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_multi_wads_toth_gab.png\" alt=\"media_functions_equilibria_multi_wads_toth_gab.png\"> + +<h4>References</h4> +<ul> + <li> + <li> + Young, J. and García-Díez, E. and Garcia, S. and van der Spek, M. (2021). The impact of binary water–CO<sub>2</sub> isotherm models on the optimal performance of sorbent-based direct air capture processes, Energy & Environmental Science, 14:5377. DOI: http://doi.org/10.1039/d1ee01272j. + </li> +</ul> +</html>")); +end WeightedAverageDualSiteTothGAB; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6d0f8d93aba1f8e0f67c45861309e4734531ccf1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/WeightedAverageDualSiteTothGAB/package.order @@ -0,0 +1,8 @@ +Internals +x_pyT +p_xyT +y_pxT +py_xT +dx_dp +dx_dy +dx_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..3694bd11227a4b6c1301dd03a16a3512819736ad --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/package.mo @@ -0,0 +1,66 @@ +within SorpLib.Media.Functions.SorptionEquilibria; +package MultiComponents "Functions required to calculate sorption equlibria for multicomponents" +extends Modelica.Icons.VariantsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains isotherm models for multi-component adsorption. Each isotherm +model is stored as a separate package. There are also test models for each isotherm +model, which test all functions of the isotherm models regarding their implementation. +The isotherm models already implemented can be found in the package content. +</p> + +<h4>Implemented functions for each isotherm model</h4> +<p> +The following functions are provided for each isotherm model: +</p> +<ul> + <li> + Equilibrium uptakes as function of equilibrium pressure, mole fractions of independent + gas phase components, and equilibrium temperature. + </li> + <li> + Equilibrium pressure as function of equilibrium uptakes, mole fractions of independent + gas phase components, and eqiulibrium temperature. + </li> + <li> + Mole fractions of independent gas phase components as function of equilibrium pressure, + equilibrium uptakes, and eqiulibrium temperature. + </li> + <li> + Equilibrium pressure and mole fractions of independent gas phase components as function + of equilibrium uptakes and eqiulibrium temperature. + </li> + <li> + Partial derivatives of equilibrium uptakes w.r.t. equilibrium pressure at constant mole + fractions and temperature. + </li> + <li> + Partial derivatives of equilibrium uptakes w.r.t. mole fractions of independent gas phase + components at constant pressure and temperature. + </li> + <li> + Partial derivatives of equilibrium uptakes w.r.t. equilibrium temperature at constant + pressure and mole fractions. + </li> +</ul> + +<h4>How to add new isotherm models</h4> +<p> +To add a new isotherm model, duplicate the package of a similar isotherm model that is +already implemented. Then, customise all functions of the isotherm model. If new +functions are implemented (e.g., equilibrium temperature as function of equilibrium +pressure, independent mole fractions, and uptake), add these for all existing isotherm +models as well. Then, adapt the test models and check the functions of the new isotherm +model regarding their implementation. Finally, write the documentation for each function, +model, and package. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end MultiComponents; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/package.order b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..d63e983abdbcb2f297668b5f8fae493581c98276 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/MultiComponents/package.order @@ -0,0 +1,10 @@ +Langmuir +Sips +Toth +TothGAB_StampiBombelli +TothGAB_Schellevis +MechanisticTothGAB +WeightedAverageDualSiteTothGAB +IAST_N2 +IAST_N3 +Testers diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BET/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BET/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..842549d47b9c08e84a13ab213c933bae4476243f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BET/package.mo @@ -0,0 +1,784 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package BET "Package containing all functions regarding the BET isotherm" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents; + + redeclare final function extends x_pT + "BET isotherm model: Uptake as function of pressure and temperature" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + + Real F = c[2]*c[3] * phi / (1 - phi) + "Pre-factor"; + Real A = 1 + (c[4]*c[5]/2 - c[4]) * phi ^ (c[4]-1) - + (c[4]*c[5] - c[4] + 1) * phi^c[4] + (c[4]*c[5]/2) * phi ^ (c[4]+1) + "Numerator of the fraction"; + Real B = 1 + (c[3] - 1) * phi + (c[3]*c[5]/2 - c[3]) * phi^c[4] - + (c[3]*c[5]/2) * phi ^ (c[4]+1) + "Denominator of the fraction"; + + algorithm + x_adsorpt := F * A/B + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BET.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare function p_xT + "BET isotherm model: Pressure as function of uptake and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT_num( + redeclare final function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BET.x_pT); + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BET.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dp + "BET isotherm model: Partial derivative of uptake w.r.t. pressure at constant temperature" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + + Real F = c[2]*c[3] * phi / (1 - phi) + "Pre-factor"; + Real A = 1 + (c[4]*c[5]/2 - c[4]) * phi ^ (c[4]-1) - + (c[4]*c[5] - c[4] + 1) * phi^c[4] + (c[4]*c[5]/2) * phi ^ (c[4]+1) + "Numerator of the fraction"; + Real B = 1 + (c[3] - 1) * phi + (c[3]*c[5]/2 - c[3]) * phi^c[4] - + (c[3]*c[5]/2) * phi ^ (c[4]+1) + "Denominator of the fraction"; + + Real dphi_dp_adsorpt = 1/c[1] + "Partial derivative of relative pressure w.r.t. to pressure"; + + Real dF_dphi = (c[2] * c[3]) / (phi - 1)^2 + "Partial derivative of pre-factor w.r.t. to relative pressure"; + Real dA_dphi = (c[4] * phi ^ (c[4]-2) * ((c[4] + 1) * c[5] * phi^2 + + (-2*c[4]*c[5] + 2*c[4] - 2) * phi + (c[4]-1) * c[5] - 2*c[4] + 2)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to relative pressure"; + Real dB_dphi = -(c[3] * (c[4]+1) * c[5] * phi^c[4]) / 2 + + c[4] * ((c[3]*c[5])/2 - c[3]) * phi ^ (c[4]-1) + c[3] - 1 + "Partial derivative of denominator of the fraction w.r.t. to relative pressure"; + + Real dF_dp_adsorpt = dF_dphi * dphi_dp_adsorpt + "Partial derivative of pre-factor w.r.t. pressure"; + Real dA_dp_adsorpt = dA_dphi * dphi_dp_adsorpt + "Partial derivative of numerator w.r.t. pressure"; + Real dB_dp_adsorpt = dB_dphi * dphi_dp_adsorpt + "Partial derivative of denominator w.r.t. pressure"; + + algorithm + dx_adsorpt_dp_adsorpt := (A/B) * dF_dp_adsorpt + + (F/B) * dA_dp_adsorpt + + (-F * A/B^2) * dB_dp_adsorpt + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure at constant temperature"; + end dx_dp; + + redeclare final function extends dx_dT + "BET isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + + Real F = c[2]*c[3] * phi / (1 - phi) + "Pre-factor"; + Real A = 1 + (c[4]*c[5]/2 - c[4]) * phi ^ (c[4]-1) - + (c[4]*c[5] - c[4] + 1) * phi^c[4] + (c[4]*c[5]/2) * phi ^ (c[4]+1) + "Numerator of the fraction"; + Real B = 1 + (c[3] - 1) * phi + (c[3]*c[5]/2 - c[3]) * phi^c[4] - + (c[3]*c[5]/2) * phi ^ (c[4]+1) + "Denominator of the fraction"; + + Real dphi_dT_adsorpt = -p_adsorpt/c[1]^2 * dc_dT_adsorpt[1] + "Partial derivative of relative pressure w.r.t. to temperature"; + + Real dF_dc2 = c[3] * phi / (1 - phi) + "Partial derivative of pre-factor w.r.t. to second coefficient of BET isotherm"; + Real dF_dc3 = c[2] * phi / (1 - phi) + "Partial derivative of pre-factor w.r.t. to third coefficient of BET isotherm"; + Real dF_dphi = (c[2] * c[3]) / (phi - 1)^2 + "Partial derivative of pre-factor w.r.t. to relative pressure"; + + Real dA_dc4 = (phi ^ (c[4]-1) * ((c[5] * phi^2 + (2-2*c[5]) * phi + c[5] - 2) * + log(phi) * c[4] - 2*phi * log(phi) + c[5] * phi^2 + (2-2*c[5]) * phi + c[5] - + 2)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to fourth coefficient + of BET isotherm"; + Real dA_dc5 = (c[4] * phi ^ (c[4]-1) * (phi^2 - 2*phi + 1)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to fivth coefficient + of BET isotherm"; + Real dA_dphi = (c[4] * phi ^ (c[4]-2) * ((c[4] + 1) * c[5] * phi^2 + + (-2*c[4]*c[5] + 2*c[4] - 2) * phi + (c[4]-1) * c[5] - 2*c[4] + 2)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to relative pressure"; + + Real dB_dc3 = -(phi^c[4] * (c[5]*phi - c[5] + 2) - 2*phi) / 2 + "Partial derivative of denominator of the fraction w.r.t. to third coefficient + of BET isotherm"; + Real dB_dc4 = -(c[3] * phi^c[4] * (c[5]*phi - c[5] + 2) * log(phi)) / 2 + "Partial derivative of denominator of the fraction w.r.t. to fourth coefficient + of BET isotherm"; + Real dB_dc5 = -(c[3] * (phi-1) * phi^c[4]) / 2 + "Partial derivative of denominator of the fraction w.r.t. to fivth coefficient + of BET isotherm"; + Real dB_dphi = -(c[3] * (c[4]+1) * c[5] * phi^c[4]) / 2 + + c[4] * ((c[3]*c[5])/2 - c[3]) * phi ^ (c[4]-1) + c[3] - 1 + "Partial derivative of denominator of the fraction w.r.t. to relative pressure"; + + Real dF_dT_adsorpt = dF_dc2 * dc_dT_adsorpt[2] + + dF_dc3 * dc_dT_adsorpt[3] + + dF_dphi * dphi_dT_adsorpt + "Partial derivative of pre-factor w.r.t. temperature"; + Real dA_dT_adsorpt = dA_dc4 * dc_dT_adsorpt[4] + + dA_dc5 * dc_dT_adsorpt[5] + + dA_dphi * dphi_dT_adsorpt + "Partial derivative of numerator w.r.t. temperature"; + Real dB_dT_adsorpt = dB_dc3 * dc_dT_adsorpt[3] + + dB_dc4 * dc_dT_adsorpt[4] + + dB_dc5 * dc_dT_adsorpt[5] + + dB_dphi * dphi_dT_adsorpt + "Partial derivative of denominator w.r.t. temperature"; + + algorithm + dx_adsorpt_dT_adsorpt := (A/B) * dF_dT_adsorpt + + (F/B) * dA_dT_adsorpt + + (-F * A/B^2) * dB_dT_adsorpt + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dp_dp + "BET isotherm model: Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + + Real F = c[2]*c[3] * phi / (1 - phi) + "Pre-factor"; + Real A = 1 + (c[4]*c[5]/2 - c[4]) * phi ^ (c[4]-1) - + (c[4]*c[5] - c[4] + 1) * phi^c[4] + (c[4]*c[5]/2) * phi ^ (c[4]+1) + "Numerator of the fraction"; + Real B = 1 + (c[3] - 1) * phi + (c[3]*c[5]/2 - c[3]) * phi^c[4] - + (c[3]*c[5]/2) * phi ^ (c[4]+1) + "Denominator of the fraction"; + + Real dphi_dp_adsorpt = 1/c[1] + "Partial derivative of relative pressure w.r.t. to pressure"; + + Real dF_dphi = (c[2] * c[3]) / (phi - 1)^2 + "Partial derivative of pre-factor w.r.t. to relative pressure"; + Real dA_dphi = (c[4] * phi ^ (c[4]-2) * ((c[4] + 1) * c[5] * phi^2 + + (-2*c[4]*c[5] + 2*c[4] - 2) * phi + (c[4]-1) * c[5] - 2*c[4] + 2)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to relative pressure"; + Real dB_dphi = -(c[3] * (c[4]+1) * c[5] * phi^c[4]) / 2 + + c[4] * ((c[3]*c[5])/2 - c[3]) * phi ^ (c[4]-1) + c[3] - 1 + "Partial derivative of denominator of the fraction w.r.t. to relative pressure"; + + Real dF_dp_adsorpt = dF_dphi * dphi_dp_adsorpt + "Partial derivative of pre-factor w.r.t. pressure"; + Real dA_dp_adsorpt = dA_dphi * dphi_dp_adsorpt + "Partial derivative of numerator w.r.t. pressure"; + Real dB_dp_adsorpt = dB_dphi * dphi_dp_adsorpt + "Partial derivative of denominator w.r.t. pressure"; + + Real ddF_dphi_dp_adsorpt= + (-(2 * c[2] * c[3]) / (phi - 1)^3) * dphi_dp_adsorpt + "Second-order artial derivative of pre-factor w.r.t. to relative pressure + and pressure"; + Real ddA_dphi_dp_adsorpt= + ((c[4] * phi^(c[4] - 3) * (phi * (c[4] * (c[5] * ((c[4] + 1) * phi - + 2 * c[4] + 2) + 2 * c[4] - 4) + 2) + (c[4] - 2) * (c[4] - 1) * c[5] - + 2 * (c[4] - 2) * (c[4] - 1))) / 2) * dphi_dp_adsorpt + "Second-order artial derivative of numerator of the fraction w.r.t. to + relative pressure and pressure"; + Real ddB_dphi_dp_adsorpt= + (-(c[3] * c[4] * phi^(c[4] - 2) * (c[5] * ((c[4] + 1) * phi - + c[4] + 1) + 2 * c[4] - 2)) / 2) * dphi_dp_adsorpt + "Second-order artial derivative of denominator of the fraction w.r.t. to + relative pressure and pressure"; + + Real ddF_dp_adsorpt_dp_adsorpt= (dphi_dp_adsorpt) * ddF_dphi_dp_adsorpt + "Second-order partial derivative of pre-factor w.r.t. pressure"; + Real ddA_dp_adsorpt_dp_adsorpt= (dphi_dp_adsorpt) * ddA_dphi_dp_adsorpt + "Second-order partial derivative of numerator w.r.t. pressure"; + Real ddB_dp_adsorpt_dp_adsorpt= (dphi_dp_adsorpt) * ddB_dphi_dp_adsorpt + "Second-order partial derivative of denominator w.r.t. pressure"; + + algorithm + ddx_adsorpt_dp_adsorpt_dp_adsorpt := + ((1/B * dF_dp_adsorpt) * dA_dp_adsorpt + + (-A/B^2 * dF_dp_adsorpt) * dB_dp_adsorpt + + (A/B) * ddF_dp_adsorpt_dp_adsorpt) + + ((1/B * dA_dp_adsorpt) * dF_dp_adsorpt + + (-F/B^2 * dA_dp_adsorpt) * dB_dp_adsorpt + + (F/B) * ddA_dp_adsorpt_dp_adsorpt) + + ((-A/B^2 * dB_dp_adsorpt) * dF_dp_adsorpt + + (-F/B^2 * dB_dp_adsorpt) * dA_dp_adsorpt + + (2 * F * A/B^3 * dB_dp_adsorpt) * dB_dp_adsorpt + + (-F * A/B^2) * ddB_dp_adsorpt_dp_adsorpt) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure at constant temperature"; + end ddx_dp_dp; + + redeclare final function extends ddx_dT_dT + "BET isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + + Real F = c[2]*c[3] * phi / (1 - phi) + "Pre-factor"; + Real A = 1 + (c[4]*c[5]/2 - c[4]) * phi ^ (c[4]-1) - + (c[4]*c[5] - c[4] + 1) * phi^c[4] + (c[4]*c[5]/2) * phi ^ (c[4]+1) + "Numerator of the fraction"; + Real B = 1 + (c[3] - 1) * phi + (c[3]*c[5]/2 - c[3]) * phi^c[4] - + (c[3]*c[5]/2) * phi ^ (c[4]+1) + "Denominator of the fraction"; + + Real dphi_dT_adsorpt = -p_adsorpt/c[1]^2 * dc_dT_adsorpt[1] + "Partial derivative of relative pressure w.r.t. to temperature"; + + Real dF_dc2 = c[3] * phi / (1 - phi) + "Partial derivative of pre-factor w.r.t. to second coefficient of BET isotherm"; + Real dF_dc3 = c[2] * phi / (1 - phi) + "Partial derivative of pre-factor w.r.t. to third coefficient of BET isotherm"; + Real dF_dphi = (c[2] * c[3]) / (phi - 1)^2 + "Partial derivative of pre-factor w.r.t. to relative pressure"; + + Real dA_dc4 = (phi ^ (c[4]-1) * ((c[5] * phi^2 + (2-2*c[5]) * phi + c[5] - 2) * + log(phi) * c[4] - 2*phi * log(phi) + c[5] * phi^2 + (2-2*c[5]) * phi + c[5] - + 2)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to fourth coefficient + of BET isotherm"; + Real dA_dc5 = (c[4] * phi ^ (c[4]-1) * (phi^2 - 2*phi + 1)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to fivth coefficient + of BET isotherm"; + Real dA_dphi = (c[4] * phi ^ (c[4]-2) * ((c[4] + 1) * c[5] * phi^2 + + (-2*c[4]*c[5] + 2*c[4] - 2) * phi + (c[4]-1) * c[5] - 2*c[4] + 2)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to relative pressure"; + + Real dB_dc3 = -(phi^c[4] * (c[5]*phi - c[5] + 2) - 2*phi) / 2 + "Partial derivative of denominator of the fraction w.r.t. to third coefficient + of BET isotherm"; + Real dB_dc4 = -(c[3] * phi^c[4] * (c[5]*phi - c[5] + 2) * log(phi)) / 2 + "Partial derivative of denominator of the fraction w.r.t. to fourth coefficient + of BET isotherm"; + Real dB_dc5 = -(c[3] * (phi-1) * phi^c[4]) / 2 + "Partial derivative of denominator of the fraction w.r.t. to fivth coefficient + of BET isotherm"; + Real dB_dphi = -(c[3] * (c[4]+1) * c[5] * phi^c[4]) / 2 + + c[4] * ((c[3]*c[5])/2 - c[3]) * phi ^ (c[4]-1) + c[3] - 1 + "Partial derivative of denominator of the fraction w.r.t. to relative pressure"; + + Real dF_dT_adsorpt = dF_dc2 * dc_dT_adsorpt[2] + + dF_dc3 * dc_dT_adsorpt[3] + + dF_dphi * dphi_dT_adsorpt + "Partial derivative of pre-factor w.r.t. temperature"; + Real dA_dT_adsorpt = dA_dc4 * dc_dT_adsorpt[4] + + dA_dc5 * dc_dT_adsorpt[5] + + dA_dphi * dphi_dT_adsorpt + "Partial derivative of numerator w.r.t. temperature"; + Real dB_dT_adsorpt = dB_dc3 * dc_dT_adsorpt[3] + + dB_dc4 * dc_dT_adsorpt[4] + + dB_dc5 * dc_dT_adsorpt[5] + + dB_dphi * dphi_dT_adsorpt + "Partial derivative of denominator w.r.t. temperature"; + + Real ddphi_dT_adsorpt_dT_adsorpt = (2*p_adsorpt/c[1]^3 * dc_dT_adsorpt[1]^2) + + (-p_adsorpt/c[1]^2) * ddc_dT_adsorpt_dT_adsorpt[1] + "Second-order partial derivative of relative pressure w.r.t. to temperature"; + + Real ddF_dc2_dc3 = phi / (1 - phi) + "Second-order partial derivative of pre-factor w.r.t. to second and third + coefficient of BET isotherm"; + Real ddF_dc2_dphi = c[3] / (phi -1)^2 + "Second-order partial derivative of pre-factor w.r.t. to second coefficient + of BET isotherm and relative pressure"; + Real ddF_dc3_dphi = c[2] / (phi -1)^2 + "Second-order partial derivative of pre-factor w.r.t. to third coefficient + of BET isotherm and relative pressure"; + Real ddF_dphi_dphi = -2 * (c[2] * c[3]) / (phi - 1)^3 + "Second-order partial derivative of pre-factor w.r.t. to relative pressure"; + + Real ddA_dc4_dc4 = (phi^(c[4] - 1) * log(phi) * ((c[5] * (phi - 1) + 2) * + (phi - 1) * log(phi) * c[4] - 2 * phi * log(phi) + 2 * c[5] * phi^2 - 4 * + (c[5] - 1) * phi + 2 * c[5] - 4)) / 2 + "Second-order partial derivative of numerator w.r.t. to fourth coefficient + of BET isoterm"; + Real ddA_dc4_dc5 = ((phi - 1)^2 * phi^(c[4] - 1) * (c[4] * log(phi) + 1)) / 2 + "Second-order partial derivative of numerator w.r.t. to fourth and fivth + coefficient of BET isoterm"; + Real ddA_dc4_dphi = ((phi - 1) * phi^(c[4] - 2) * (c[4] * (c[5] * ((c[4] + 1) * + phi - c[4] + 1) + 2 * c[4] - 2) * log(phi) + (2 * c[4] + 1) * c[5] * phi - + (2 * c[4] - 1) * c[5] + 4 * c[4] - 2)) / 2 + "Second-order partial derivative of numerator w.r.t. to fourth coefficient + of BET isoterm and relative pressure"; + Real ddA_dc5_dphi = (c[4] * (phi - 1) * phi^(c[4] - 2) * (c[4] * phi + phi - + c[4] + 1)) / 2 + "Second-order partial derivative of numerator w.r.t. to fivth coefficient + of BET isoterm and relative pressure"; + Real ddA_dphi_dphi = (c[4] * phi^(c[4] - 3) * (phi * (c[4] * (c[5] * ((c[4] + + 1) * phi - 2 * c[4] + 2) + 2 * c[4] - 4) + 2) + (c[4] - 2) * (c[4] - 1) * + c[5] - 2 * (c[4] - 2) * (c[4] - 1))) / 2 + "Second-order partial derivative of numerator w.r.t. to relative pressure"; + + Real ddB_dc3_dc4 = -((c[5] * (phi - 1) + 2) * phi^c[4] * log(phi)) / 2 + "Second-order partial derivative of denominator w.r.t. to third and fourht + coefficient of BET isoterm"; + Real ddB_dc3_dc5 = -((phi - 1) * phi^c[4]) / 2 + "Second-order partial derivative of denominator w.r.t. to third and fivth + coefficient of BET isoterm"; + Real ddB_dc3_dphi = (-c[5] * phi^c[4] - c[4] * phi^(c[4] - 1) * (c[5] * phi - + c[5] + 2)) / 2 + 1 + "Second-order partial derivative of denominator w.r.t. to third coefficient + of BET isoterm and relative pressure"; + Real ddB_dc4_dc4 = -(c[3] * (c[5] * (phi - 1) + 2) * phi^c[4] * log(phi)^2) / 2 + "Second-order partial derivative of denominator w.r.t. to fourth coefficient + of BET isoterm"; + Real ddB_dc4_dc5 = -(c[3] * (phi - 1) * phi^c[4] * log(phi)) / 2 + "Second-order partial derivative of denominator w.r.t. to fourth and fivth + coefficient of BET isoterm"; + Real ddB_dc4_dphi = -(c[3] * phi^(c[4] - 1) * (((c[4] + 1) * c[5] * phi - + c[4] * c[5] + 2 * c[4]) * log(phi) + c[5] * phi - c[5] + 2)) / 2 + "Second-order partial derivative of denominator w.r.t. to fourth coefficient + of BET isoterm and relative pressure"; + Real ddB_dc5_dphi = -(c[3] * phi^(c[4] - 1) * (c[4] * phi + phi - c[4])) / 2 + "Second-order partial derivative of denominator w.r.t. to fivth coefficient + of BET isoterm and relative pressure"; + Real ddB_dphi_dphi = -(c[3] * c[4] * phi^(c[4] - 2) * (c[5] * ((c[4] + 1) * + phi - c[4] + 1) + 2 * c[4] - 2)) / 2 + "Second-order partial derivative of denominator w.r.t. to relative pressure"; + + Real ddF_dc2_dT_adsorpt = ddF_dc2_dc3 * dc_dT_adsorpt[3] + + ddF_dc2_dphi * dphi_dT_adsorpt + "Second-order partial derivative of pre-factor w.r.t. to second coefficient + of BET isoterm and temperature"; + Real ddF_dc3_dT_adsorpt = ddF_dc2_dc3 * dc_dT_adsorpt[2] + + ddF_dc3_dphi * dphi_dT_adsorpt + "Second-order partial derivative of pre-factor w.r.t. to third coefficient + of BET isoterm and temperature"; + Real ddF_dphi_dT_adsorpt = ddF_dc2_dphi * dc_dT_adsorpt[2] + + ddF_dc3_dphi * dc_dT_adsorpt[3] + + ddF_dphi_dphi * dphi_dT_adsorpt + "Second-order partial derivative of pre-factor w.r.t. to relative pressure + and temperature"; + + Real ddA_dc4_dT_adsorpt = ddA_dc4_dc4 * dc_dT_adsorpt[4] + + ddA_dc4_dc5 * dc_dT_adsorpt[5] + + ddA_dc4_dphi * dphi_dT_adsorpt + "Second-order partial derivative of numerator w.r.t. to fourth coefficient + of BET isoterm and temperature"; + Real ddA_dc5_dT_adsorpt = ddA_dc4_dc5 * dc_dT_adsorpt[4] + + ddA_dc5_dphi * dphi_dT_adsorpt + "Second-order partial derivative of numerator w.r.t. to fivth coefficient + of BET isoterm and temperature"; + Real ddA_dphi_dT_adsorpt = ddA_dc4_dphi * dc_dT_adsorpt[4] + + ddA_dc5_dphi * dc_dT_adsorpt[5] + + ddA_dphi_dphi * dphi_dT_adsorpt + "Second-order partial derivative of numerator w.r.t. to relative pressure + and temperature"; + + Real ddB_dc3_dT_adsorpt = ddB_dc3_dc4 * dc_dT_adsorpt[4] + + ddB_dc3_dc5 * dc_dT_adsorpt[5] + + ddB_dc3_dphi * dphi_dT_adsorpt + "Second-order partial derivative of denominator w.r.t. to fourth coefficient + of BET isoterm and temperature"; + Real ddB_dc4_dT_adsorpt = ddB_dc3_dc4 * dc_dT_adsorpt[3] + + ddB_dc4_dc4 * dc_dT_adsorpt[4] + + ddB_dc4_dc5 * dc_dT_adsorpt[5] + + ddB_dc4_dphi * dphi_dT_adsorpt + "Second-order partial derivative of denominator w.r.t. to fourth coefficient + of BET isoterm and temperature"; + Real ddB_dc5_dT_adsorpt = ddB_dc3_dc5 * dc_dT_adsorpt[3] + + ddB_dc4_dc5 * dc_dT_adsorpt[4] + + ddB_dc5_dphi * dphi_dT_adsorpt + "Second-order partial derivative of denominator w.r.t. to fivth coefficient + of BET isoterm and temperature"; + Real ddB_dphi_dT_adsorpt = ddB_dc3_dphi * dc_dT_adsorpt[3] + + ddB_dc4_dphi * dc_dT_adsorpt[4] + + ddB_dc5_dphi * dc_dT_adsorpt[5] + + ddB_dphi_dphi * dphi_dT_adsorpt + "Second-order partial derivative of denominator w.r.t. to relative pressure + and temperature"; + + Real ddF_dT_adsorpt_dT_adsorpt = ddF_dc2_dT_adsorpt * dc_dT_adsorpt[2] + + dF_dc2 * ddc_dT_adsorpt_dT_adsorpt[2] + + ddF_dc3_dT_adsorpt * dc_dT_adsorpt[3] + + dF_dc3 * ddc_dT_adsorpt_dT_adsorpt[3] + + ddF_dphi_dT_adsorpt * dphi_dT_adsorpt + + dF_dphi * ddphi_dT_adsorpt_dT_adsorpt + "Second-order partial derivative of pre-factor w.r.t. temperature"; + Real ddA_dT_adsorpt_dT_adsorpt = ddA_dc4_dT_adsorpt * dc_dT_adsorpt[4] + + dA_dc4 * ddc_dT_adsorpt_dT_adsorpt[4] + + ddA_dc5_dT_adsorpt * dc_dT_adsorpt[5] + + dA_dc5 * ddc_dT_adsorpt_dT_adsorpt[5] + + ddA_dphi_dT_adsorpt * dphi_dT_adsorpt + + dA_dphi * ddphi_dT_adsorpt_dT_adsorpt + "Second-order partial derivative of numerator w.r.t. temperature"; + Real ddB_dT_adsorpt_dT_adsorpt = ddB_dc3_dT_adsorpt * dc_dT_adsorpt[3] + + dB_dc3 * ddc_dT_adsorpt_dT_adsorpt[3] + + ddB_dc4_dT_adsorpt * dc_dT_adsorpt[4] + + dB_dc4 * ddc_dT_adsorpt_dT_adsorpt[4] + + ddB_dc5_dT_adsorpt * dc_dT_adsorpt[5] + + dB_dc5 * ddc_dT_adsorpt_dT_adsorpt[5] + + ddB_dphi_dT_adsorpt * dphi_dT_adsorpt + + dB_dphi * ddphi_dT_adsorpt_dT_adsorpt + "Second-order partial derivative of denominator w.r.t. temperature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + ((dF_dT_adsorpt/B) * dA_dT_adsorpt + + (-A/B^2 * dF_dT_adsorpt) * dB_dT_adsorpt + + (A/B) * ddF_dT_adsorpt_dT_adsorpt) + + ((dA_dT_adsorpt/B) * dF_dT_adsorpt + + (-F/B^2 * dA_dT_adsorpt) * dB_dT_adsorpt + + (F/B) * ddA_dT_adsorpt_dT_adsorpt) + + ((-A/B^2 * dB_dT_adsorpt) * dF_dT_adsorpt + + (-F/B^2 * dB_dT_adsorpt) * dA_dT_adsorpt + + (2*F * A/B^3 * dB_dT_adsorpt) * dB_dT_adsorpt + + (-F * A/B^2) * ddB_dT_adsorpt_dT_adsorpt) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "BET isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + + Real F = c[2]*c[3] * phi / (1 - phi) + "Pre-factor"; + Real A = 1 + (c[4]*c[5]/2 - c[4]) * phi ^ (c[4]-1) - + (c[4]*c[5] - c[4] + 1) * phi^c[4] + (c[4]*c[5]/2) * phi ^ (c[4]+1) + "Numerator of the fraction"; + Real B = 1 + (c[3] - 1) * phi + (c[3]*c[5]/2 - c[3]) * phi^c[4] - + (c[3]*c[5]/2) * phi ^ (c[4]+1) + "Denominator of the fraction"; + + Real dphi_dp_adsorpt = 1/c[1] + "Partial derivative of relative pressure w.r.t. to pressure"; + Real dphi_dT_adsorpt = -p_adsorpt/c[1]^2 * dc_dT_adsorpt[1] + "Partial derivative of relative pressure w.r.t. to temperature"; + + Real dF_dc2 = c[3] * phi / (1 - phi) + "Partial derivative of pre-factor w.r.t. to second coefficient of BET isotherm"; + Real dF_dc3 = c[2] * phi / (1 - phi) + "Partial derivative of pre-factor w.r.t. to third coefficient of BET isotherm"; + Real dF_dphi = (c[2] * c[3]) / (phi - 1)^2 + "Partial derivative of pre-factor w.r.t. to relative pressure"; + + Real dA_dc4 = (phi ^ (c[4]-1) * ((c[5] * phi^2 + (2-2*c[5]) * phi + c[5] - 2) * + log(phi) * c[4] - 2*phi * log(phi) + c[5] * phi^2 + (2-2*c[5]) * phi + c[5] - + 2)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to fourth coefficient + of BET isotherm"; + Real dA_dc5 = (c[4] * phi ^ (c[4]-1) * (phi^2 - 2*phi + 1)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to fivth coefficient + of BET isotherm"; + Real dA_dphi = (c[4] * phi ^ (c[4]-2) * ((c[4] + 1) * c[5] * phi^2 + + (-2*c[4]*c[5] + 2*c[4] - 2) * phi + (c[4]-1) * c[5] - 2*c[4] + 2)) / 2 + "Partial derivative of numerator of the fraction w.r.t. to relative pressure"; + + Real dB_dc3 = -(phi^c[4] * (c[5]*phi - c[5] + 2) - 2*phi) / 2 + "Partial derivative of denominator of the fraction w.r.t. to third coefficient + of BET isotherm"; + Real dB_dc4 = -(c[3] * phi^c[4] * (c[5]*phi - c[5] + 2) * log(phi)) / 2 + "Partial derivative of denominator of the fraction w.r.t. to fourth coefficient + of BET isotherm"; + Real dB_dc5 = -(c[3] * (phi-1) * phi^c[4]) / 2 + "Partial derivative of denominator of the fraction w.r.t. to fivth coefficient + of BET isotherm"; + Real dB_dphi = -(c[3] * (c[4]+1) * c[5] * phi^c[4]) / 2 + + c[4] * ((c[3]*c[5])/2 - c[3]) * phi ^ (c[4]-1) + c[3] - 1 + "Partial derivative of denominator of the fraction w.r.t. to relative pressure"; + + Real ddphi_dp_adsorpt_dT_adsorpt = -1/c[1]^2 * dc_dT_adsorpt[1] + "Second-order partial derivative of relative pressure w.r.t. pressure and + temperature"; + + Real ddF_dphi_dc2 = c[3] / (phi - 1)^2 + "Second-order partial derivative of pre-factor w.r.t. to relative pressure + and second coefficient of BET isotherm"; + Real ddF_dphi_dc3 = c[2] / (phi - 1)^2 + "Second-order partial derivative of pre-factor w.r.t. to relative pressure + and third coefficient of BET isotherm"; + Real ddF_dphi_dphi = -2 * (c[2] * c[3]) / (phi - 1)^3 + "Second-order partial derivative of pre-factor w.r.t. to relative pressure"; + + Real ddA_dphi_dc4 = ((phi - 1) * phi^(c[4] - 2) * (c[4] * (log(phi) * ((c[5] * + (phi - 1) + 2) * c[4] + c[5] * (phi + 1) - 2) + 2 * c[5] * (phi - 1) + 4) + + c[5] * (phi + 1) - 2)) / 2 + "Second-order partial derivative of numerator w.r.t. to relative pressure + and fourth coefficient of BET isotherm"; + Real ddA_dphi_dc5 = (c[4] * (phi - 1) * phi^(c[4] - 2) * ((c[4] + 1) * phi - + c[4] + 1)) / 2 + "Second-order partial derivative of numerator w.r.t. to relative pressure + and fivth coefficient of BET isotherm"; + Real ddA_dphi_dphi = (c[4] * phi^(c[4] - 3) * (phi * (c[4] * (c[5] * ((c[4] + + 1) * phi - 2 * c[4] + 2) + 2 * c[4] - 4) + 2) + (c[4] - 2) * (c[4] - 1) * + c[5] - 2 * (c[4] - 2) * (c[4] - 1))) / 2 + "Second-order partial derivative of numerator w.r.t. to relative pressure"; + + Real ddB_dphi_dc3 = (-(c[4] + 1) * c[5] * phi^c[4] + c[4] * (c[5] - 2) * + phi^(c[4] - 1) + 2) / 2 + "Second-order partial derivative of denominator w.r.t. to relative pressure + and fourth coefficient of BET isotherm"; + Real ddB_dphi_dc4 = -(c[3] * phi^(c[4] - 1) * ((c[5] * (phi - 1) + 2) * + log(phi) * c[4] + c[5] * phi * log(phi) + c[5] * phi - c[5] + 2)) / 2 + "Second-order partial derivative of denominator w.r.t. to relative pressure + and fourth coefficient of BET isotherm"; + Real ddB_dphi_dc5 = -(c[3] * phi^(c[4] - 1) * (c[4] * phi + phi - c[4])) / 2 + "Second-order partial derivative of denominator w.r.t. to relative pressure + and fivth coefficient of BET isotherm"; + Real ddB_dphi_dphi = -(c[3] * c[4] * phi^(c[4] - 2) * (c[5] * ((c[4] + 1) * + phi - c[4] + 1) + 2 * c[4] - 2)) / 2 + "Second-order partial derivative of denominator w.r.t. to relative pressure"; + + Real dF_dp_adsorpt = dF_dphi * dphi_dp_adsorpt + "Partial derivative of pre-factor w.r.t. pressure"; + Real dA_dp_adsorpt = dA_dphi * dphi_dp_adsorpt + "Partial derivative of numerator w.r.t. pressure"; + Real dB_dp_adsorpt = dB_dphi * dphi_dp_adsorpt + "Partial derivative of denominator w.r.t. pressure"; + + Real dF_dT_adsorpt = dF_dc2 * dc_dT_adsorpt[2] + + dF_dc3 * dc_dT_adsorpt[3] + + dF_dphi * dphi_dT_adsorpt + "Partial derivative of pre-factor w.r.t. temperature"; + Real dA_dT_adsorpt = dA_dc4 * dc_dT_adsorpt[4] + + dA_dc5 * dc_dT_adsorpt[5] + + dA_dphi * dphi_dT_adsorpt + "Partial derivative of numerator w.r.t. temperature"; + Real dB_dT_adsorpt = dB_dc3 * dc_dT_adsorpt[3] + + dB_dc4 * dc_dT_adsorpt[4] + + dB_dc5 * dc_dT_adsorpt[5] + + dB_dphi * dphi_dT_adsorpt + "Partial derivative of denominator w.r.t. temperature"; + + Real ddF_dphi_dT_adsorpt = ddF_dphi_dc2 * dc_dT_adsorpt[2] + + ddF_dphi_dc3 * dc_dT_adsorpt[3] + + ddF_dphi_dphi * dphi_dT_adsorpt + "Second-order partial derivative of pre-factor w.r.t. relative pressure and + temperature"; + Real ddA_dphi_dT_adsorpt = ddA_dphi_dc4 * dc_dT_adsorpt[4] + + ddA_dphi_dc5 * dc_dT_adsorpt[5] + + ddA_dphi_dphi * dphi_dT_adsorpt + "Second-order partial derivative of numerator w.r.t. relative pressure and + temperature"; + Real ddB_dphi_dT_adsorpt = ddB_dphi_dc3 * dc_dT_adsorpt[3] + + ddB_dphi_dc4 * dc_dT_adsorpt[4] + + ddB_dphi_dc5 * dc_dT_adsorpt[5] + + ddB_dphi_dphi * dphi_dT_adsorpt + "Second-order partial derivative of denominator w.r.t. relative pressure and + temperature"; + + Real ddF_dp_adsorpt_dT_adsorpt = ddF_dphi_dT_adsorpt * dphi_dp_adsorpt + + dF_dphi * ddphi_dp_adsorpt_dT_adsorpt + "Second-order partial derivative of pre-factor w.r.t. pressure and temperature"; + Real ddA_dp_adsorpt_dT_adsorpt = ddA_dphi_dT_adsorpt * dphi_dp_adsorpt + + dA_dphi * ddphi_dp_adsorpt_dT_adsorpt + "Second-order partial derivative of numerator w.r.t. pressure and temperature"; + Real ddB_dp_adsorpt_dT_adsorpt = ddB_dphi_dT_adsorpt * dphi_dp_adsorpt + + dB_dphi * ddphi_dp_adsorpt_dT_adsorpt + "Second-order partial derivative of denominator w.r.t. pressure and temperature"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + ((dF_dp_adsorpt/B) * dA_dT_adsorpt + + (-A/B^2 * dF_dp_adsorpt) * dB_dT_adsorpt + + (A/B) * ddF_dp_adsorpt_dT_adsorpt) + + ((dA_dp_adsorpt/B) * dF_dT_adsorpt + + (-F/B^2 * dA_dp_adsorpt) * dB_dT_adsorpt + + (F/B) * ddA_dp_adsorpt_dT_adsorpt) + + ((-A/B^2 * dB_dp_adsorpt) * dF_dT_adsorpt + + (-F/B^2 * dB_dp_adsorpt) * dA_dT_adsorpt + + (2*F * A/B^3 * dB_dp_adsorpt) * dB_dT_adsorpt + + (-F * A/B^2) * ddB_dp_adsorpt_dT_adsorpt) + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare function pi_pT + "BET isotherm model: Reduced spreading pressure as function of pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT_num( + redeclare final function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BET.x_pT); + end pi_pT; + + redeclare function p_piT + "BET isotherm model: Pressure as function of reduced spreading pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT_num( + redeclare final function func_pi_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BET.pi_pT); + end p_piT; + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The BET isotherm model is a five-parameter model for calculating the equilibrium +uptake <i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>. +The BET isotherm model is suitable for type I-IV isotherms according to the IUPAC +definition. +</p> + +<h4>Main equations</h4> +<p> +The BET isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = x<sub>mon</sub>(T<sub>adsorpt</sub>) * C(T<sub>adsorpt</sub>) * φ(T<sub>adsorpt</sub>) / (1 - φ(T<sub>adsorpt</sub>)) * A(T<sub>adsorpt</sub>) / B(T<sub>adsorpt</sub>); +</pre> +<p> +with +</p> +<pre> + φ(T<sub>adsorpt</sub>) = p<sub>adsorpt</sub>/p<sub>sat</sub>(T<sub>adsorpt</sub>); +</pre> +<pre> + A(T<sub>adsorpt</sub>) = 1 + (n * g(T<sub>adsorpt</sub>)/2 - n) * φ(T<sub>adsorpt</sub>) ^ (n-1) - (n * g(T<sub>adsorpt</sub>) - n + 1) * φ(T<sub>adsorpt</sub>) ^ n + (n *g(T<sub>adsorpt</sub>)/2) * φ(T<sub>adsorpt</sub>) ^ (n+1); +</pre> +<pre> + B(T<sub>adsorpt</sub>) = 1 + (C(T<sub>adsorpt</sub>) - 1) * φ(T<sub>adsorpt</sub>) + (C(T<sub>adsorpt</sub>) * g(T<sub>adsorpt</sub>)/2 - C(T<sub>adsorpt</sub>)) * φ(T<sub>adsorpt</sub>) ^ n - (C(T<sub>adsorpt</sub>) * g(T<sub>adsorpt</sub>)/2) * φ(T<sub>adsorpt</sub>) ^ (n + 1); +</pre> +<p> +and +</p> +<pre> + g(T<sub>adsorpt</sub>) = <strong>exp</strong>(Q<sub>cap</sub> / (R * T<sub>adsorpt</sub>)); +</pre> +<p> +Herein, <i>x<sub>mon</sub>(T<sub>adsorpt</sub>)</i> is the monolayer uptake, +<i>C(T<sub>adsorpt</sub>)</i> is the BET coefficient, <i>n</i> is the number of +layers that can be occupied, and <i>Q<sub>cap</sub> </i> is a measure for the +extra enthalpy added to the enthalpy of vaporization at high layers due to capillary +forces. In the original BET equation, all parameters are independent of the temperature. +However, sometimes the two parameters <i>x<sub>mon</sub>(T<sub>adsorpt</sub>)</i> +and <i>C(T<sub>adsorpt</sub>)</i> are modeled as a function of the temperature, +with typical temperature dependencies may have the following forms: +</p> +<pre> + x<sub>mon</sub>(T<sub>adsorpt</sub>) = x<sub>mon,ref</sub> * <strong>exp</strong>(Χ * (1 - T<sub>adsorpt</sub>/T<sub>ref</sub>)); +</pre> +<pre> + C(T<sub>adsorpt</sub>) = C<sub>ref</sub> * <strong>exp</strong>(Q/(R * T<sub>ref</sub>) * (T<sub>ref</sub>/T<sub>adsorpt</sub> - 1)); +</pre> +<p> +where <i>x<sub>mon,ref</sub></i> is the monolayer uptake at reference temperature +<i>T<sub>ref</sub></i> and <i>C<sub>ref</sub></i> is the BET coefficient at reference +temperature. The parameter <i>Χ</i> describes the change of the monolayer uptake +with temperature and the parameter <i>Q</i> is a measure for some energy. These five +parameters and the two parameters <i>n</i> and <i>Q<sub>cap</sub></i> can be used +as fitting parameters. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = p<sub>sat</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2] = x<sub>mon</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[3] = C(T<sub>adsorpt</sub>) in - + </li> + <li> + c[4] = n in - + </li> + <li> + c[5] = g(T<sub>adsorpt</sub>) in - + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + All adsorption sites are energetically equivalent. + </li> + <li> + All adsorption sites can be occupied. + </li> + <li> + No interactions occur between the adsorbent molecules. + </li> + <li> + No limit exists for the number of layers. + </li> + <li> + Heat of adsorption of all layers except the first layer equals the heat of vaporization. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The isotherm model is used for type I-V isotherms according to the IUPAC definition. +Besides, the BET isotherm can used to calculate the surface area of the adsorbent. +</p> + +<h4>Example</h4> +<p> +The following figure shows the BET isotherm model for different parameter sets. +In the upper sub-figure, the equilibrium pressure changes with time, while the +equilibrium temperature remains constant; in the lower sub-figure, the equilibrium +temperature changes with time, while the equilibrium pressure remains constant. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_bet.png\" alt=\"media_functions_equilibria_pure_bet.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>")); +end BET; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BET/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BET/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5b33869cf15d79cfe321d3ef372972c01c4559b4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BET/package.order @@ -0,0 +1,9 @@ +x_pT +p_xT +dx_dp +dx_dT +ddx_dp_dp +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BiLangmuir/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BiLangmuir/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..15ee2ed092aaef579f1ebdebd624788338f22f29 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BiLangmuir/package.mo @@ -0,0 +1,257 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package BiLangmuir "Package containing all functions regarding the Bi-Langmuir isotherm" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents; + + redeclare final function extends x_pT + "Bi-Langmuir isotherm model: Uptake as function of pressure and temperature" + algorithm + x_adsorpt := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.x_pT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[1:2], + p_adsorpt_lb_start=p_adsorpt_lb_start, + p_adsorpt_ub_start=p_adsorpt_ub_start, + tolerance=tolerance) + + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.x_pT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[3:4], + p_adsorpt_lb_start=p_adsorpt_lb_start, + p_adsorpt_ub_start=p_adsorpt_ub_start, + tolerance=tolerance) + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare function p_xT + "Bi-Langmuir isotherm model: Pressure as function of uptake and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT_num( + redeclare final function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir.x_pT); + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dp + "Bi-Langmuir isotherm model: Partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + dx_adsorpt_dp_adsorpt := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[1:2]) + + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[3:4]) + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure at constant temperature"; + end dx_dp; + + redeclare final function extends dx_dT + "Bi-Langmuir isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + algorithm + dx_adsorpt_dT_adsorpt := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[1:2], + dc_dT_adsorpt=dc_dT_adsorpt[1:2]) + + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[3:4], + dc_dT_adsorpt=dc_dT_adsorpt[3:4]) + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dp_dp + "Bi-Langmuir isotherm model: Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + ddx_adsorpt_dp_adsorpt_dp_adsorpt := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[1:2]) + + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[3:4]) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure at constant temperature"; + end ddx_dp_dp; + + redeclare final function extends ddx_dT_dT + "Bi-Langmuir isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[1:2], + dc_dT_adsorpt=dc_dT_adsorpt[1:2], + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt[1:2]) + + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[3:4], + dc_dT_adsorpt=dc_dT_adsorpt[3:4], + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt[3:4]) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Bi-Langmuir isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[1:2], + dc_dT_adsorpt=dc_dT_adsorpt[1:2]) + + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[3:4], + dc_dT_adsorpt=dc_dT_adsorpt[3:4]) + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare final function extends pi_pT + "Bi-Langmuir isotherm model: Pressure as function of reduced spreading pressure and temperature" + algorithm + pi := + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.pi_pT( + M_adsorptive=M_adsorptive, + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[1:2], + integral_pi_lb=integral_pi_lb, + tolerance=tolerance) + + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.pi_pT( + M_adsorptive=M_adsorptive, + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c[3:4], + integral_pi_lb=integral_pi_lb, + tolerance=tolerance) + "Calculation of the reduced spreading pressure"; + end pi_pT; + + redeclare function p_piT + "Bi-Langmuir isotherm model: Pressure as function of reduced spreading pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT_num( + redeclare final function func_pi_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir.pi_pT); + end p_piT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Bi-Langmuir isotherm model is a four-parameter model for calculating the equilibrium +uptake <i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>. +</p> + +<h4>Main equations</h4> +<p> +The Bi-Langmuir isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = x<sub>sat,1</sub>(T<sub>adsorpt</sub>) * (b<sub>1</sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub>) / (1 + b<sub>1</sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub>) + x<sub>sat,2</sub>(T<sub>adsorpt</sub>) * (b<sub>2</sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub>) / (1 + b<sub>2</sub>(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>sat,1</sub>(T<sub>adsorpt</sub>)</i> is the saturation uptake of +adsorption site 1, <i>x<sub>sat,2</sub>(T<sub>adsorpt</sub>)</i> is the saturation +uptake of adsorption site 2, <i>b<sub>1</sub>(T<sub>adsorpt</sub>)</i> is the +Langmuir coefficient of adsorption site 1, and <i>b<sub>2</sub>(T<sub>adsorpt</sub>)</i> +is the Langmuir coefficient of adsorption site 2. Typical temperature dependencies +may have the following forms: +</p> +<pre> + x<sub>sat,<i>i</i></sub>(T<sub>adsorpt</sub>) = a<sub>0,<i>i</i></sub> + a<sub>1,<i>i</i></sub>/T<sub>adsorpt</sub>; +</pre> +<pre> + b<sub><i>i</i></sub>(T<sub>adsorpt</sub>) = b<sub>0,<i>i</i></sub> * <strong>exp</strong>(-ΔH<sub>ads,<i>i</i></sub>/(R * T<sub>adsorpt</sub>)); +</pre> +<p> +where <i>a<sub>0,<i>i</i></sub></i>, <i>a<sub>1,<i>i</i></sub></i>, <i>b<sub>0</sub></i>, +and <i>ΔH<sub>ads,<i>i</i></sub></i> are fiting parameters. The parameter +<i>ΔH<sub>ads,<i>i</i></sub></i> is the isosteric adsorption heat, which is +invariant with the surface uptake. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = x<sub>sat,1</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[2] = b<sub>1</sub>(T<sub>adsorpt</sub>) in 1/Pa + </li> + <li> + c[3] = x<sub>sat,2</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[4] = b<sub>2</sub>(T<sub>adsorpt</sub>) in 1/Pa + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + All adsorption sites can be occupied. + </li> + <li> + No interactions occur between the adsorbent molecules. + </li> + <li> + The adsorbent surface is covered monomolecularly. + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the Bi-Langmuir isotherm model for different parameter sets. +In the upper sub-figure, the equilibrium pressure changes with time, while the +equilibrium temperature remains constant; in the lower sub-figure, the equilibrium +temperature changes with time, while the equilibrium pressure remains constant. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_bi_langmuir.png\" alt=\"media_functions_equilibria_pure_bi_langmuir.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>")); +end BiLangmuir; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BiLangmuir/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BiLangmuir/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5b33869cf15d79cfe321d3ef372972c01c4559b4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/BiLangmuir/package.order @@ -0,0 +1,9 @@ +x_pT +p_xT +dx_dp +dx_dT +ddx_dp_dp +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininAstakhov/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininAstakhov/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..82712ad1cf5feae8bfa3c44d6e7f2f2ad8b54001 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininAstakhov/package.mo @@ -0,0 +1,526 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package DubininAstakhov "Package containing all functions regarding the Dubinin-Astakhov isotherm" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponentsDubinin; + + redeclare final function extends x_pT + "Dubinin-Astakhov isotherm model: Uptake as function of pressure and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Dubinin-Astakhov isotherm model: Pressure as function of uptake and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dT + "Dubinin-Astakhov isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + SorpLib.Units.FilledPoreVolume W= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.W_A( + A=A, + c=c) + "Filled pore volume"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.dW_dA( + A=A, c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + + Real dx_adsorpt_dA = c[2] * dW_dA + "Derivative of uptake w.r.t. to adsorption potential"; + Real dx_adsorpt_dc2 = W + "Derivative of uptake w.r.t. to second coefficient of Dubinin-Astakhov isotherm"; + Real dx_adsorpt_dc3 = c[2] * exp(-(A / c[4]) ^ c[5]) + "Derivative of uptake w.r.t. to third coefficient of Dubinin-Astakhov isotherm"; + Real dx_adsorpt_dc4 = c[2] * c[5] / c[4] * (A / c[4]) ^ c[5] * W + "Derivative of uptake w.r.t. to fourth coefficient of Dubinin-Astakhov isotherm"; + Real dx_adsorpt_dc5 = -c[2] * log(A / c[4]) * (A / c[4]) ^ c[5] * W + "Derivative of uptake w.r.t. to fivth coefficient of Dubinin-Astakhov isotherm"; + + algorithm + dx_adsorpt_dT_adsorpt := + dx_adsorpt_dA*dA_dT_adsorpt + + dx_adsorpt_dc2*dc_dT_adsorpt[2] + + dx_adsorpt_dc3*dc_dT_adsorpt[3] + + dx_adsorpt_dc4*dc_dT_adsorpt[4] + + dx_adsorpt_dc5*dc_dT_adsorpt[5] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dT_dT + "Dubinin-Astakhov isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperatureTemperature ddA_dT_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dT_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1], + ddp_sat_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt[1]) + "Second-order partial derivative of adsorption potential w.r.t. equilibrium + temperature at constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of characteristic curve w.r.t. adsorption + potential and temperature at constant pressure"; + + Real dx_adsorpt_dA = c[2] * dW_dA + "Derivative of uptake w.r.t. to adsorption potential"; + Real dx_adsorpt_dc2 = c[3] * exp(-(A / c[4]) ^ c[5]) + "Derivative of uptake w.r.t. to second coefficient of Dubinin-Astakhov + isotherm"; + Real dx_adsorpt_dc3 = c[2] * exp(-(A / c[4]) ^ c[5]) + "Derivative of uptake w.r.t. to third coefficient of Dubinin-Astakhov + isotherm"; + Real dx_adsorpt_dc4 = c[2] * c[5] / c[4] * (A / c[4]) ^ c[5] * + c[3] * exp(-(A / c[4]) ^ c[5]) + "Derivative of uptake w.r.t. to fourth coefficient of Dubinin-Astakhov + isotherm"; + Real dx_adsorpt_dc5 = -c[2] * log(A / c[4]) * (A / c[4]) ^ c[5] * + c[3] * exp(-(A / c[4]) ^ c[5]) + "Derivative of uptake w.r.t. to fivth coefficient of Dubinin-Astakhov + isotherm"; + + Real ddx_adsorpt_dc4_dc4 = (c[2] * c[3] * c[5] * (c[5] * (A / c[4])^c[5] - + c[5] - 1) * (A / c[4])^c[5] * exp(-(A / c[4])^c[5])) / c[4]^2 + "Second-order partial derivative of uptake w.r.t. to fourth coefficient of + Dubinin-Astakhov isotherm"; + Real ddx_adsorpt_dc5_dc5 = c[2] * c[3] * log(A / c[4])^2 * ((A / c[4])^c[5] - + 1) * (A / c[4])^c[5] * exp(-(A / c[4])^c[5]) + "Second-order partial derivative of uptake w.r.t. to fivth coefficient of + Dubinin-Astakhov isotherm"; + + Real ddx_adsorpt_dc2_dA= -(c[3] * c[5] * (A / c[4])^c[5] * + exp(-(A / c[4])^c[5])) / A + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Dubinin-Astakhov isotherm and adsorption potential"; + Real ddx_adsorpt_dc2_dc3 = exp(-(A / c[4])^c[5]) + "Second-order partial derivative of uptake w.r.t. to second and third + coefficient of Dubinin-Astakhov isotherm"; + Real ddx_adsorpt_dc2_dc4 = (c[3] * c[5] * (A / c[4])^c[5] * + exp(-(A / c[4])^c[5])) / c[4] + "Second-order partial derivative of uptake w.r.t. to second and fourht + coefficient of Dubinin-Astakhov isotherm"; + Real ddx_adsorpt_dc2_dc5 = -c[3] * log(A / c[4]) * (A / c[4])^c[5] * + exp(-(A / c[4])^c[5]) + "Second-order partial derivative of uptake w.r.t. to second and fivth + coefficient of Dubinin-Astakhov isotherm"; + + Real ddx_adsorpt_dc3_dA = -(c[2] * c[5] * (A / c[4])^c[5] * + exp(-(A / c[4])^c[5])) / A + "Second-order partial derivative of uptake w.r.t. to third coefficient of + Dubinin-Astakhov isotherm and adsorption potential"; + Real ddx_adsorpt_dc3_dc4 = (c[2] * c[5] * (A / c[4])^c[5] * + exp(-(A / c[4])^c[5])) / c[4] + "Second-order partial derivative of uptake w.r.t. to third and fourht + coefficient of Dubinin-Astakhov isotherm"; + Real ddx_adsorpt_dc3_dc5 = -c[2] * log(A / c[4]) * (A / c[4])^c[5] * + exp(-(A / c[4])^c[5]) + "Second-order partial derivative of uptake w.r.t. to third and fivth + coefficient of Dubinin-Astakhov isotherm"; + + Real ddx_adsorpt_dc4_dA = -(c[2] * c[3] * c[5]^2 * (A / c[4])^c[5] * + ((A / c[4])^c[5] - 1) * exp(-(A / c[4])^c[5])) / (c[4] * A) + "Second-order partial derivative of uptake w.r.t. to fourth coefficient of + Dubinin-Astakhov isotherm and adsorption potential"; + Real ddx_adsorpt_dc4_dc5 = -(c[2] * c[3] * (A / c[4])^c[5] * ((log(A / c[4]) * + (A / c[4])^c[5] - log(A / c[4])) * c[5] - 1) * exp(-(A / c[4])^c[5])) / c[4] + "Second-order partial derivative of uptake w.r.t. to fourth and fivth + coefficient of Dubinin-Astakhov isotherm"; + + Real ddx_adsorpt_dc5_dA = (c[2] * c[3] * (A / c[4])^c[5] * + exp(-(A / c[4])^c[5]) * ((c[5] * (A / c[4])^c[5] - c[5]) * + log(A / c[4]) - 1)) / A + "Second-order partial derivative of uptake w.r.t. to fivth coefficient of + Dubinin-Astakhov isotherm and adsorption potential"; + + Real ddx_adsorpt_dA_dT_dT_adsorpt = dc_dT_adsorpt[2] * dW_dA + + c[2] * ddW_dA_dT_adsorpt + "Second-order partial derivative of uptake w.r.t. to adsorption potential + and temperature"; + Real ddx_adsorpt_dc2_dT_dT_adsorpt = ddx_adsorpt_dc2_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[3] + + ddx_adsorpt_dc2_dc4*dc_dT_adsorpt[4] + + ddx_adsorpt_dc2_dc5*dc_dT_adsorpt[5] + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Dubinin-Astakhov isotherm and temperature"; + Real ddx_adsorpt_dc3_dT_dT_adsorpt = ddx_adsorpt_dc3_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[2] + + ddx_adsorpt_dc3_dc4*dc_dT_adsorpt[4] + + ddx_adsorpt_dc3_dc5*dc_dT_adsorpt[5] + "Second-order partial derivative of uptake w.r.t. to third coefficient of + Dubinin-Astakhov isotherm and temperature"; + Real ddx_adsorpt_dc4_dT_dT_adsorpt = ddx_adsorpt_dc4_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc4*dc_dT_adsorpt[2] + + ddx_adsorpt_dc3_dc4*dc_dT_adsorpt[3] + + ddx_adsorpt_dc4_dc4*dc_dT_adsorpt[4] + + ddx_adsorpt_dc4_dc5*dc_dT_adsorpt[5] + "Second-order partial derivative of uptake w.r.t. to fourth coefficient of + Dubinin-Astakhov isotherm and temperature"; + Real ddx_adsorpt_dc5_dT_dT_adsorpt = ddx_adsorpt_dc5_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc5*dc_dT_adsorpt[2] + + ddx_adsorpt_dc3_dc5*dc_dT_adsorpt[3] + + ddx_adsorpt_dc4_dc5*dc_dT_adsorpt[4] + + ddx_adsorpt_dc5_dc5*dc_dT_adsorpt[5] + "Second-order partial derivative of uptake w.r.t. to fivth coefficient of + Dubinin-Astakhov isotherm and temperature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + (ddx_adsorpt_dA_dT_dT_adsorpt*dA_dT_adsorpt + + dx_adsorpt_dA*ddA_dT_adsorpt_dT_adsorpt) + + (ddx_adsorpt_dc2_dT_dT_adsorpt*dc_dT_adsorpt[2] + + dx_adsorpt_dc2*ddc_dT_adsorpt_dT_adsorpt[2]) + + (ddx_adsorpt_dc3_dT_dT_adsorpt*dc_dT_adsorpt[3] + + dx_adsorpt_dc3*ddc_dT_adsorpt_dT_adsorpt[3]) + + (ddx_adsorpt_dc4_dT_dT_adsorpt*dc_dT_adsorpt[4] + + dx_adsorpt_dc4*ddc_dT_adsorpt_dT_adsorpt[4]) + + (ddx_adsorpt_dc5_dT_dT_adsorpt*dc_dT_adsorpt[5] + + dx_adsorpt_dc5*ddc_dT_adsorpt_dT_adsorpt[5]) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Dubinin-Astakhov isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of adsorption potential w.r.t. to pressure at constant + temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressureTemperature ddA_dp_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dp_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Second-order partial derivative of adsorption potential w.r.t. to pressure + and temperature"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.dW_dA( + A=A, c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of characteristic curve w.r.t. adsorption + potential and temperature at constant pressure"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + dc_dT_adsorpt[2] * dW_dA * dA_dp_adsorpt + + c[2] * ddW_dA_dT_adsorpt * dA_dp_adsorpt + + c[2] * dW_dA * ddA_dp_adsorpt_dT_adsorpt + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare function pi_pT + "Dubinin-Astakhov isotherm model: Reduced spreading pressure as function of pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT_num( + integral_pi_lb = Modelica.Constants.small, + tolerance = 100*Modelica.Constants.eps, + redeclare final function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.x_pT); + end pi_pT; + + redeclare function p_piT + "Dubinin-Astakhov isotherm model: Pressure as function of reduced spreading pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT_num( + p_adsorpt_lb_start = 1, + integral_pi_lb = Modelica.Constants.small, + tolerance_p_adsorpt = 1e-6, + tolerance_pi = 100*Modelica.Constants.eps, + redeclare final function func_pi_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.pi_pT); + end p_piT; + + redeclare final function extends W_A + "Dubinin-Astakhov isotherm model: Filled pore volume as function of adsorption potential" + algorithm + W := c[3] * exp(-(max(A, 0) / c[4]) ^ c[5]) + "Filled pore volume"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(A=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.A_W(W, c, A_lb_start, A_ub_start, tolerance))); + end W_A; + + redeclare final function extends A_W + "Dubinin-Astakhov isotherm model: Adsorption potential as function of the filled pore volume" + algorithm + A := c[4] * (-log(W/c[3])) ^ (1/c[5]) + "Adsorption potential"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(W=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov.W_A(A, c, A_lb_start, A_ub_start, tolerance))); + end A_W; + + redeclare final function extends dW_dA + "Dubinin-Astakhov isotherm model: Partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + algorithm + dW_dA := -c[5] / c[4] * (A / c[4]) ^ (c[5] - 1) * c[3] * exp(-(A / c[4]) ^ c[5]) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + end dW_dA; + + redeclare final function extends ddW_dA_dA + "Dubinin-Astakhov isotherm model: Second-order partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + algorithm + ddW_dA_dA := (c[3] * c[5] * (A / c[4])^c[5] * (c[5] * ((A / c[4])^c[5] - 1) + 1) * + exp(-(A / c[4])^c[5])) / A^2 + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential at constant pressure and temperature"; + end ddW_dA_dA; + + redeclare final function extends ddW_dA_dT + "Dubinin-Astakhov isotherm model: Second-order partial derivative of filled pore volume w.r.t. adsorption potential and temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + Real ddW_dA_dA = (c[3] * c[5] * (A / c[4])^c[5] * (c[5] * (A / c[4])^c[5] - + c[5] + 1) * exp(-(A / c[4])^c[5])) / A^2 + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential"; + Real ddW_dA_dc3 = -((A / c[4])^c[5] * c[5] * exp(-(A / c[4])^c[5])) / A + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and third coefficient of the Dubinin-Astakhov isotherm model"; + Real ddW_dA_dc4 = -(c[3] * c[5]^2 * ((A / c[4])^c[5] - 1) * (A / c[4])^c[5] * + exp(-(A / c[4])^c[5])) / (A * c[4]) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and fourth coefficient of the Dubinin-Astakhov isotherm model"; + Real ddW_dA_dc5 = (c[3] * (A / c[4])^c[5] * ((log(A / c[4]) * (A / c[4])^c[5] - + log(A / c[4])) * c[5] - 1) * exp(-(A / c[4])^c[5])) / A + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and fivth coefficient of the Dubinin-Astakhov isotherm model"; + + algorithm + ddW_dA_dT := ddW_dA_dA * dA_dT_adsorpt + + ddW_dA_dc3 * dc_dT_adsorpt[3] + + ddW_dA_dc4 * dc_dT_adsorpt[4] + + ddW_dA_dc5 * dc_dT_adsorpt[5] + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and temperature at constant pressure"; + end ddW_dA_dT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Dubinin-Astakhov isotherm model is a five-parameter model for calculating the +equilibrium uptake <i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>. +The Dubinin-Astakhov isotherm model is suitable for type I, IV and V isotherms +according to the IUPAC definition. +</p> + +<h4>Main equations</h4> +<p> +The Dubinin-Astakhov isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) * W(A(T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + W(A(T<sub>adsorpt</sub>)) = W<sub>0</sub> * <strong>exp</strong>(-(A(T<sub>adsorpt</sub>) / E) ^ n); +</pre> +<pre> + A(T<sub>adsorpt</sub>) = R * T<sub>adsorpt</sub> * <strong>ln</strong>(p<sub>sat</sub>(T<sub>adsorpt</sub>) / p<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>W(A(T<sub>adsorpt</sub>))</i> is the so-called characteristic curve and +<i>A(T<sub>adsorpt</sub>)</i> is the adsorption potential. Within the characteristic +curve, the parameter <i>W<sub>0</sub></i> describes the maximum filled pore volume, +<i>E</i> is the characteristic energy, and <i>n</i> describes the heterogeneity of the +system. These three parameters can be used as fitting parameters. +<br/><br/> +Note that the exponent <i>n</i> is typically greater than unity. Furthermore, the +density of the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> is assumed +to be the saturated liquid density ρ<sub>sat,liq</sub>(T<sub>adsorpt</sub>) without +any further information about the system under consideration. For super-critical +adsorptives (i.e., <i>T<sub>adsorpt</sub> ≥ T<sub>crit</sub></i>), the density of +the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> can be estimated by +</p> +<pre> + ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) = ρ<sub>sat,liq</sub>(T<sub>boiling,0</sub>) * <strong>exp</strong>(-0.0025 * (T<sub>adsorpt</sub> - T<sub>boiling,0</sub>)); +</pre> +<p> +and a pseudo-vapour pressure <i>p<sub>sat</sub>(T<sub>adsorpt</sub>)</i> can be +calculated by +</p> +<pre> + p<sub>sat</sub>(T<sub>adsorpt</sub>) = p<sub>crit</sub>(T<sub>adsorpt</sub>) * (T<sub>adsorpt</sub> / T<sub>crit</sub>) ^ k; +</pre> +<p> +where <i>T<sub>boiling,0</sub></i> is the normal boiling point at 1 atm and <i>k</i> is +a fitting parameter specific to the system under consideration. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = p<sub>sat</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2] = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) in kg/m<sup>3</sup> + </li> + <li> + c[3] = W<sub>0</sub> in m<sup>3</sup>/kg + </li> + <li> + c[4] = E in J/mol + </li> + <li> + c[5] = n in - + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The characteristic curve <i>W(A)</i> must decrease strictly monotonically with + increasing adsorption potential <i>A</i>. Otherwise, the inverses <i>A(W)</i> + and <i>p(x,T</i>) may not be solveable. + </li> + <li> + The reduced spreading pressure <i>π</i> may not be calculable. Accordingly, the + inverse <i>p(π,T)</i> cannot be calculated either. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The isotherm model is used for type I, IV, and V isotherms according to the IUPAC +definition. +</p> + +<h4>Example</h4> +<p> +The following figure shows the Dubinin-Astakhov isotherm model for different parameter +sets. In the upper sub-figure, the equilibrium pressure changes with time, while the +equilibrium temperature is constant. In the centered sub-figure, the equilibrium +temperature changes with time, while the equilibrium pressure is constant. In the +lower sub-figure, the characteristic curve is shown. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_astakhov.png\" alt=\"media_functions_equilibria_pure_dubinin_astakhov.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>")); +end DubininAstakhov; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininAstakhov/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininAstakhov/package.order new file mode 100644 index 0000000000000000000000000000000000000000..44a21b8e54c5e42bc784fb6013efc1fbbf99d434 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininAstakhov/package.order @@ -0,0 +1,12 @@ +x_pT +p_xT +dx_dT +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT +W_A +A_W +dW_dA +ddW_dA_dA +ddW_dA_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininChebyshevSeriesRaionalOrder33/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininChebyshevSeriesRaionalOrder33/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..adb00bbadd811f6043e915bf986ec372ac819c21 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininChebyshevSeriesRaionalOrder33/package.mo @@ -0,0 +1,607 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package DubininChebyshevSeriesRaionalOrder33 "Package containing all functions regarding the Dubinin isotherm model using a 'Chebyshev series' equation type with rational order 3/3" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponentsDubinin; + + redeclare final function extends x_pT + "Dubinin-Chebyshev-Series-3/3 isotherm model: Uptake as function of pressure and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Dubinin-Chebyshev-Series-3/3 isotherm model: Pressure as function of uptake and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dT + "Dubinin-Chebyshev-Series-3/3 isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + Real n = (A - c[10]) / c[11] + "Auxiliary variable"; + + Real num = c[3] + c[5] * n + c[7] * (2 * n^2 - 1) + c[9] * (4 * n^3 - 3 * n) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * n + c[6] * (2 * n^2 - 1) + c[8] * (4 * n^3 - 3 * n) + "Denominator of characteristic curve"; + + Real dn_dT_adsorpt = (1 / c[11]) * dA_dT_adsorpt + + (-1 / c[11]) * dc_dT_adsorpt[10] + + ((c[10] - A) / c[11]^2) * dc_dT_adsorpt[11] + "Partial derivative of auxiliary variable w.r.t. temprature"; + Real dnum_dT_adsorpt = (1) * dc_dT_adsorpt[3] + + (n) * dc_dT_adsorpt[5] + + (2 * n^2 - 1) * dc_dT_adsorpt[7] + + (4 * n^3 - 3 * n) * dc_dT_adsorpt[9] + + (4 * n * (3 * c[9] * n + c[7]) - 3 * c[9] + c[5]) * dn_dT_adsorpt + "Partial derivative of numerator of characteristic curve w.r.t. temprature"; + Real dden_dT_adsorpt = (n) * dc_dT_adsorpt[4] + + (2 * n^2 - 1) * dc_dT_adsorpt[6] + + (4 * n^3 - 3 * n) * dc_dT_adsorpt[8] + + (4 * n * (3 * c[8] * n + c[6]) - 3 * c[8] + c[4]) * dn_dT_adsorpt + "Partial derivative of denominator of characteristic curve w.r.t. temprature"; + + algorithm + dx_adsorpt_dT_adsorpt := + (1 * num / den) * dc_dT_adsorpt[2] + + (c[2] / den) * dnum_dT_adsorpt + + (-c[2] * num / den^2) * dden_dT_adsorpt + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dT_dT + "Dubinin-Chebyshev-Series-3/3 isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperatureTemperature ddA_dT_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dT_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1], + ddp_sat_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt[1]) + "Second-order partial derivative of adsorption potential w.r.t. equilibrium + temperature at constant pressure"; + + Real n = (A - c[10]) / c[11] + "Auxiliary variable"; + Real num = c[3] + c[5] * n + c[7] * (2 * n^2 - 1) + c[9] * (4 * n^3 - 3 * n) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * n + c[6] * (2 * n^2 - 1) + c[8] * (4 * n^3 - 3 * n) + "Denominator of characteristic curve"; + + Real dn_dT_adsorpt = (1 / c[11]) * dA_dT_adsorpt + + (-1 / c[11]) * dc_dT_adsorpt[10] + + ((c[10] - A) / c[11]^2) * dc_dT_adsorpt[11] + "Partial derivative of auxiliary variable w.r.t. temprature"; + Real dnum_dT_adsorpt = (1) * dc_dT_adsorpt[3] + + (n) * dc_dT_adsorpt[5] + + (2 * n^2 - 1) * dc_dT_adsorpt[7] + + (4 * n^3 - 3 * n) * dc_dT_adsorpt[9] + + (4 * n * (3 * c[9] * n + c[7]) - 3 * c[9] + c[5]) * dn_dT_adsorpt + "Partial derivative of numerator of characteristic curve w.r.t. temprature"; + Real dden_dT_adsorpt = (n) * dc_dT_adsorpt[4] + + (2 * n^2 - 1) * dc_dT_adsorpt[6] + + (4 * n^3 - 3 * n) * dc_dT_adsorpt[8] + + (4 * n * (3 * c[8] * n + c[6]) - 3 * c[8] + c[4]) * dn_dT_adsorpt + "Partial derivative of denominator of characteristic curve w.r.t. temprature"; + + Real ddn_dT_adsorpt_dT_adsorpt= + ((-1 / c[11]^2 * dA_dT_adsorpt) * dc_dT_adsorpt[11] + + (1 / c[11]) * ddA_dT_adsorpt_dT_adsorpt) + + ((-1 / c[11]) * ddc_dT_adsorpt_dT_adsorpt[10] + + (1 / c[11]^2 * dc_dT_adsorpt[10]) * dc_dT_adsorpt[11]) + + ((1 / c[11]^2 * dc_dT_adsorpt[11]) * dc_dT_adsorpt[10] + + (-2 * (c[10] - A) / c[11]^3 * dc_dT_adsorpt[11]) * dc_dT_adsorpt[11] + + (-1 / c[11]^2 * dc_dT_adsorpt[11]) * dA_dT_adsorpt + + ((c[10] - A) / c[11]^2) * ddc_dT_adsorpt_dT_adsorpt[11]) + "Second-order partial derivative of auxiliary variable w.r.t. temprature"; + Real ddnum_dT_adsorpt_dT_adsorpt= + ((1) * ddc_dT_adsorpt_dT_adsorpt[3]) + + ((dc_dT_adsorpt[5]) * dn_dT_adsorpt + + (n) * ddc_dT_adsorpt_dT_adsorpt[5]) + + ((4 * n * dc_dT_adsorpt[7]) * dn_dT_adsorpt + + (2 * n^2 - 1) * ddc_dT_adsorpt_dT_adsorpt[7]) + + (((12 * n^2 - 3) * dc_dT_adsorpt[9]) * dn_dT_adsorpt + + (4 * n^3 - 3 * n) * ddc_dT_adsorpt_dT_adsorpt[9]) + + ((4 * dn_dT_adsorpt * (6 * c[9] * n + c[7])) * dn_dT_adsorpt + + (1 * dn_dT_adsorpt) * dc_dT_adsorpt[5] + + (4 * n * dn_dT_adsorpt) * dc_dT_adsorpt[7] + + ((12 * n^2 - 3) * dn_dT_adsorpt) * dc_dT_adsorpt[9] + + (4 * n * (3 * c[9] * n + c[7]) - 3 * c[9] + c[5]) * ddn_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of numerator of characteristic curve w.r.t. + temprature"; + Real ddden_dT_adsorpt_dT_adsorpt= + ((dc_dT_adsorpt[4]) * dn_dT_adsorpt + + (n) * ddc_dT_adsorpt_dT_adsorpt[4]) + + ((4 * n * dc_dT_adsorpt[6]) * dn_dT_adsorpt + + (2 * n^2 - 1) * ddc_dT_adsorpt_dT_adsorpt[6]) + + (((12 * n^2 - 3) * dc_dT_adsorpt[8]) * dn_dT_adsorpt + + (4 * n^3 - 3 * n) * ddc_dT_adsorpt_dT_adsorpt[8]) + + (((4 * (6 * c[8] * n + c[6])) * dn_dT_adsorpt) * dn_dT_adsorpt + + (1 * dn_dT_adsorpt) * dc_dT_adsorpt[4] + + (4 * n * dn_dT_adsorpt) * dc_dT_adsorpt[6] + + ((12 * n^2 - 3) * dn_dT_adsorpt) * dc_dT_adsorpt[8] + + (4 * n * (3 * c[8] * n + c[6]) - 3 * c[8] + c[4]) * ddn_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of denominator of characteristic curve w.r.t. + temprature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + ((1/den * dc_dT_adsorpt[2]) * dnum_dT_adsorpt + + (-num / den^2 * dc_dT_adsorpt[2]) * dden_dT_adsorpt + + (num / den) * ddc_dT_adsorpt_dT_adsorpt[2]) + + ((1/den * dnum_dT_adsorpt) * dc_dT_adsorpt[2] + + (-c[2] / den^2 * dnum_dT_adsorpt) * dden_dT_adsorpt + + (c[2] / den) * ddnum_dT_adsorpt_dT_adsorpt) + + ((-num / den^2 * dden_dT_adsorpt) * dc_dT_adsorpt[2] + + (-c[2] / den^2 * dden_dT_adsorpt) * dnum_dT_adsorpt + + (2 * c[2] * num / den^3 * dden_dT_adsorpt) * dden_dT_adsorpt + + (-c[2] * num / den^2) * ddden_dT_adsorpt_dT_adsorpt) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Dubinin-Chebyshev-Series-3/3 isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of adsorption potential w.r.t. to pressure at constant + temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressureTemperature ddA_dp_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dp_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Second-order partial derivative of adsorption potential w.r.t. to pressure + and temperature"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33.dW_dA( + A=A, c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of characteristic curve w.r.t. adsorption + potential and temperature at constant pressure"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + dc_dT_adsorpt[2] * dW_dA * dA_dp_adsorpt + + c[2] * ddW_dA_dT_adsorpt * dA_dp_adsorpt + + c[2] * dW_dA * ddA_dp_adsorpt_dT_adsorpt + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare function pi_pT + "Dubinin-Chebyshev-Series-3/3 isotherm model: Reduced spreading pressure as function of pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT_num( + integral_pi_lb = 1e-2, + tolerance = 1e-6, + redeclare final function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33.x_pT); + end pi_pT; + + redeclare function p_piT + "Dubinin-Chebyshev-Series-3/3 isotherm model: Pressure as function of reduced spreading pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT_num( + p_adsorpt_lb_start = 1, + integral_pi_lb = 1e-2, + tolerance_p_adsorpt = 1e-6, + tolerance_pi = 1e-6, + redeclare final function func_pi_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33.pi_pT); + end p_piT; + + redeclare final function extends W_A + "Dubinin-Chebyshev-Series-3/3 isotherm model: Filled pore volume as function of adsorption potential" + + // + // Definition of variables + // +protected + Real n = (A - c[10]) / c[11] + "Auxiliary variable"; + + Real num = c[3] + c[5] * n + c[7] * (2 * n^2 - 1) + c[9] * (4 * n^3 - 3 * n) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * n + c[6] * (2 * n^2 - 1) + c[8] * (4 * n^3 - 3 * n) + "Denominator of characteristic curve"; + + algorithm + W := num / den + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(A=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33.A_W(W, c, A_lb_start, A_ub_start, tolerance))); + end W_A; + + redeclare final function extends A_W + "Dubinin-Chebyshev-Series-3/3 isotherm model: Adsorption potential as function of the filled pore volume (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_A_W_num( + redeclare final function func_W_A = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33.W_A); + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(W=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33.W_A(A, c, A_lb_start, A_ub_start, tolerance))); + end A_W; + + redeclare final function extends dW_dA + "Dubinin-Chebyshev-Series-3/3 isotherm model: Partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + + // + // Definition of variables + // +protected + Real n = (A - c[10]) / c[11] + "Auxiliary variable"; + + Real num = c[3] + c[5] * n + c[7] * (2 * n^2 - 1) + c[9] * (4 * n^3 - 3 * n) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * n + c[6] * (2 * n^2 - 1) + c[8] * (4 * n^3 - 3 * n) + "Denominator of characteristic curve"; + + Real dn_dA = 1 / c[11] + "Partial derivative of the auxiliary variable w.r.t. adsorption potential"; + + Real dnum_dn = c[9] * (12 * n^2 - 3) + 4 * c[7] * n + c[5] + "Partial derivative of the numerator w.r.t. auxiliary variable"; + Real dden_dn = c[8] * (12 * n^2 - 3) + 4 * c[6] * n + c[4] + "Partial derivative of the numerator w.r.t. auxiliary variable"; + + Real dW_dn = (dnum_dn * den - num * dden_dn) / den^2 + "Partial derivative of the equilibrium uptake w.r.t. auxiliary variable"; + + algorithm + dW_dA := dW_dn*dn_dA + "Partial derivative of the filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + end dW_dA; + + redeclare final function extends ddW_dA_dA + "Dubinin-Chebyshev-Series-3/3: Second-order partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + + // + // Definition of variables + // +protected + Real n = (A - c[10]) / c[11] + "Auxiliary variable"; + + Real num = c[3] + c[5] * n + c[7] * (2 * n^2 - 1) + c[9] * (4 * n^3 - 3 * n) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * n + c[6] * (2 * n^2 - 1) + c[8] * (4 * n^3 - 3 * n) + "Denominator of characteristic curve"; + + Real dn_dA = 1 / c[11] + "Partial derivative of the auxiliary variable w.r.t. adsorption potential"; + + Real dnum_dn = c[9] * (12 * n^2 - 3) + 4 * c[7] * n + c[5] + "Partial derivative of the numerator w.r.t. auxiliary variable"; + Real dden_dn = c[8] * (12 * n^2 - 3) + 4 * c[6] * n + c[4] + "Partial derivative of the numerator w.r.t. auxiliary variable"; + + Real dW_dn = (dnum_dn * den - num * dden_dn) / den^2 + "Partial derivative of the equilibrium uptake w.r.t. auxiliary variable"; + + Real ddnum_dn_dn = 24 * c[9] * n + 4 * c[7] + "Second-order partial derivative of the numerator w.r.t. auxiliary variable"; + Real ddden_dn_dn = 24 * c[8] * n + 4 * c[6] + "Second-order partial derivative of the numerator w.r.t. auxiliary variable"; + + Real ddW_dn_dn= + (1 / den) * ddnum_dn_dn + + (-dnum_dn / den^2) * dden_dn + + (-dden_dn / den^2) * dnum_dn + + (-num / den^2) * ddden_dn_dn + + (2 * num * dden_dn / den^3) * dden_dn + "Second-order partial derivative of the equilibrium uptake w.r.t. auxiliary + variable"; + + algorithm + ddW_dA_dA := (dn_dA) * (ddW_dn_dn*dn_dA) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential at constant pressure and temperature"; + end ddW_dA_dA; + + redeclare final function extends ddW_dA_dT + "Dubinin-Chebyshev-Series-3/3: Second-order partial derivative of filled pore volume w.r.t. adsorption potential and temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + Real n = (A - c[10]) / c[11] + "Auxiliary variable"; + + Real num = c[3] + c[5] * n + c[7] * (2 * n^2 - 1) + c[9] * (4 * n^3 - 3 * n) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * n + c[6] * (2 * n^2 - 1) + c[8] * (4 * n^3 - 3 * n) + "Denominator of characteristic curve"; + + Real dn_dA = 1 / c[11] + "Partial derivative of the auxiliary variable w.r.t. adsorption potential"; + + Real dnum_dn = c[9] * (12 * n^2 - 3) + 4 * c[7] * n + c[5] + "Partial derivative of the numerator w.r.t. auxiliary variable"; + Real dden_dn = c[8] * (12 * n^2 - 3) + 4 * c[6] * n + c[4] + "Partial derivative of the numerator w.r.t. auxiliary variable"; + + Real dW_dn = (dnum_dn * den - num * dden_dn) / den^2 + "Partial derivative of the equilibrium uptake w.r.t. auxiliary variable"; + + Real dn_dT_adsorpt = (1 / c[11]) * dA_dT_adsorpt + + (-1 / c[11]) * dc_dT_adsorpt[10] + + ((c[10] - A) / c[11]^2) * dc_dT_adsorpt[11] + "Partial derivative of auxiliary variable w.r.t. temprature"; + Real dnum_dT_adsorpt = (1) * dc_dT_adsorpt[3] + + (n) * dc_dT_adsorpt[5] + + (2 * n^2 - 1) * dc_dT_adsorpt[7] + + (4 * n^3 - 3 * n) * dc_dT_adsorpt[9] + + (4 * n * (3 * c[9] * n + c[7]) - 3 * c[9] + c[5]) * dn_dT_adsorpt + "Partial derivative of numerator of characteristic curve w.r.t. temprature"; + Real dden_dT_adsorpt = (n) * dc_dT_adsorpt[4] + + (2 * n^2 - 1) * dc_dT_adsorpt[6] + + (4 * n^3 - 3 * n) * dc_dT_adsorpt[8] + + (4 * n * (3 * c[8] * n + c[6]) - 3 * c[8] + c[4]) * dn_dT_adsorpt + "Partial derivative of denominator of characteristic curve w.r.t. temprature"; + + Real ddn_dA_dT_adsorpt = (-1 / c[11]^2) * dc_dT_adsorpt[11] + "Second-order partial derivative of the auxiliary variable w.r.t. adsorption + potential and temperature at constant pressure"; + + Real ddnum_dn_dT_adsorpt= + (1) * dc_dT_adsorpt[5] + + (4 * n) * dc_dT_adsorpt[7] + + (12 * n^2 - 3) * dc_dT_adsorpt[9] + + (24 * c[9] * n + 4 * c[7]) * dn_dT_adsorpt + "Second-order partial derivative of numerator w.r.t. auxiliary variable and + temperature"; + Real ddden_dn_dT_adsorpt= + (1) * dc_dT_adsorpt[4] + + (4 * n) * dc_dT_adsorpt[6] + + (12 * n^2 - 3) * dc_dT_adsorpt[8] + + (24 * c[8] * n + 4 * c[6]) * dn_dT_adsorpt + "Second-order partial derivative of numerator w.r.t. auxiliary variable and + temperature"; + + Real ddW_dn_dT_adsorpt= + ((1/den) * ddnum_dn_dT_adsorpt + + (-1/den^2 * dnum_dn) * dden_dT_adsorpt) + + ((-dden_dn/den^2) * dnum_dT_adsorpt + + (-num/den^2) * ddden_dn_dT_adsorpt + + (2 * num * dden_dn / den^3) * dden_dT_adsorpt) + "Second-order partial derivative of the equilibrium uptake w.r.t. auxiliary + variable and temperature"; + + algorithm + ddW_dA_dT := (dn_dA) * ddW_dn_dT_adsorpt + + (dW_dn) * ddn_dA_dT_adsorpt + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and temperature"; + end ddW_dA_dT; + // + // Annotation + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Dubinin-Chebyshev-Series-3/3 isotherm model is a eleven-parameter model for calculating +the equilibrium uptake <i>x_adsorpt</i> as a function of the equilibrium pressure +<i>p_adsorpt</i>. +</p> + +<h4>Main equations</h4> +<p> +The Dubinin-Chebyshev-Series-3/3 isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) * W(A(T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + W(A(T<sub>adsorpt</sub>)) = (a + c * n + e * (2 * n<sup>2</sup> - 1) + g * (4 * n<sup>3</sup> - 3 * n)) / (1 + b * n + d * (2 * n<sup>2</sup> - 1) + f * (4 * n<sup>3</sup> - 3 * n)); +</pre> +<pre> + n(A(T<sub>adsorpt</sub>)) = (A - h) / i; +</pre> +<pre> + A(T<sub>adsorpt</sub>) = R * T<sub>adsorpt</sub> * <strong>ln</strong>(p<sub>sat</sub>(T<sub>adsorpt</sub>) / p<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>W(A(T<sub>adsorpt</sub>))</i> is the so-called characteristic curve and +<i>A(T<sub>adsorpt</sub>)</i> is the adsorption potential. Within the characteristic +curve, the parameters <i>a</i>, <i>b</i>, <i>c</i>, <i>d</i>, <i>e</i>, <i>f</i>, +<i>g</i>, <i>h</i>, and <i>i</i> are fitting parameters. +<br/><br/> +Note that the density of the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> +is assumed to be the saturated liquid density ρ<sub>sat,liq</sub>(T<sub>adsorpt</sub>) +without any further information about the system under consideration. For super-critical +adsorptives (i.e., <i>T<sub>adsorpt</sub> ≥ T<sub>crit</sub></i>), the density of +the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> can be estimated by +</p> +<pre> + ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) = ρ<sub>sat,liq</sub>(T<sub>boiling,0</sub>) * <strong>exp</strong>(-0.0025 * (T<sub>adsorpt</sub> - T<sub>boiling,0</sub>)); +</pre> +<p> +and a pseudo-vapour pressure <i>p<sub>sat</sub>(T<sub>adsorpt</sub>)</i> can be calculated by +</p> +<pre> + p<sub>sat</sub>(T<sub>adsorpt</sub>) = p<sub>crit</sub>(T<sub>adsorpt</sub>) * (T<sub>adsorpt</sub> / T<sub>crit</sub>) ^ k; +</pre> +<p> +where <i>T<sub>boiling,0</sub></i> is the normal boiling point at 1 atm and <i>k</i> is +a fitting parameter specific to the system under consideration. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = p<sub>sat</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2] = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) in kg/m<sup>3</sup> + </li> + <li> + c[3] = a in m<sup>3</sup>/kg + </li> + <li> + c[4] = b in - + </li> + <li> + c[5] = c in m<sup>3</sup>/kg + </li> + <li> + c[6] = d in - + </li> + <li> + c[7] = e in m<sup>3</sup>/kg + </li> + <li> + c[8] = f in - + </li> + <li> + c[9] = g in m<sup>3</sup>/kg + </li> + <li> + c[10] = h in J/mol + </li> + <li> + c[11] = i in J/mol + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The characteristic curve <i>W(A)</i> must decrease strictly monotonically with + increasing adsorption potential <i>A</i>. Otherwise, the inverses <i>A(W)</i> + and <i>p(x,T</i>) may not be solveable. + </li> + <li> + The reduced spreading pressure <i>π</i> may not be calculable. Accordingly, the + inverse <i>p(π,T)</i> cannot be calculated either. + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the Dubinin-Chebyshev-Series-3/3 isotherm model for one +parameter set. In the upper sub-figure, the equilibrium pressure changes with +time, while the equilibrium temperature is constant. In the centered sub-figure, the +equilibrium temperature changes with time, while the equilibrium pressure is constant. +In the lower sub-figure, the characteristic curve is shown. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_chebyshev_series_3_3.png\" alt=\"media_functions_equilibria_pure_dubinin_chebyshev_series_3_3.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> + <li> + Schawe, D. (1999). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD Thesis, Stuttgart. + </li> +</ul> +</html>")); +end DubininChebyshevSeriesRaionalOrder33; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininChebyshevSeriesRaionalOrder33/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininChebyshevSeriesRaionalOrder33/package.order new file mode 100644 index 0000000000000000000000000000000000000000..44a21b8e54c5e42bc784fb6013efc1fbbf99d434 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininChebyshevSeriesRaionalOrder33/package.order @@ -0,0 +1,12 @@ +x_pT +p_xT +dx_dT +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT +W_A +A_W +dW_dA +ddW_dA_dA +ddW_dA_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical1/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical1/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a3dbe3d503d86ec1396a4d3f3e1ef65e1007db91 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical1/package.mo @@ -0,0 +1,496 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package DubininEmpirical1 "Package containing all functions regarding the Dubinin-Empirical-1 isotherm model" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponentsDubinin; + + redeclare final function extends x_pT + "Dubinin-Empirical-1 isotherm model: Uptake as function of pressure and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Dubinin-Empirical-1 isotherm model: Pressure as function of uptake and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dT + "Dubinin-Empirical-1 isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + Real den = (c[3] + c[4] * A^2 * log(c[5] * A) + c[6] * A^3) + "Denominator of characteristic curve"; + + Real dden_dc3 = 1 + "Partial derivative of denominator of characteristic curve w.r.t. third + coefficient of isotherm"; + Real dden_dc4 = A^2 * log(c[5] * A) + "Partial derivative of denominator of characteristic curve w.r.t. fourth + coefficient of isotherm"; + Real dden_dc5 = c[4] * A^2 / c[5] + "Partial derivative of denominator of characteristic curve w.r.t. fivth + coefficient of isotherm"; + Real dden_dc6 = A^3 + "Partial derivative of denominator of characteristic curve w.r.t. sixth + coefficient of isotherm"; + Real dden_dA = A * (2 * c[4] * log(c[5] * A) + 3 * c[6] * A + c[4]) + "Partial derivative of denominator of characteristic curve w.r.t. adsorption + potential"; + + Real dden_dT_adsorpt = dden_dc3 * dc_dT_adsorpt[3] + + dden_dc4 * dc_dT_adsorpt[4] + + dden_dc5 * dc_dT_adsorpt[5] + + dden_dc6 * dc_dT_adsorpt[6] + + dden_dA * dA_dT_adsorpt + "Partial derivative of denominator of characteristic curve w.r.t. temprature"; + + algorithm + dx_adsorpt_dT_adsorpt := (1 / den) * dc_dT_adsorpt[2] + + (-c[2]/den^2) * dden_dT_adsorpt + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dT_dT + "Dubinin-Empirical-1 isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperatureTemperature ddA_dT_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dT_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1], + ddp_sat_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt[1]) + "Second-order partial derivative of adsorption potential w.r.t. equilibrium + temperature at constant pressure"; + + Real den = (c[3] + c[4] * A^2 * log(c[5] * A) + c[6] * A^3) + "Denominator of characteristic curve"; + + Real dden_dc3 = 1 + "Partial derivative of denominator of characteristic curve w.r.t. third + coefficient of isotherm"; + Real dden_dc4 = A^2 * log(c[5] * A) + "Partial derivative of denominator of characteristic curve w.r.t. fourth + coefficient of isotherm"; + Real dden_dc5 = c[4] * A^2 / c[5] + "Partial derivative of denominator of characteristic curve w.r.t. fivth + coefficient of isotherm"; + Real dden_dc6 = A^3 + "Partial derivative of denominator of characteristic curve w.r.t. sixth + coefficient of isotherm"; + Real dden_dA = A * (2 * c[4] * log(c[5] * A) + 3 * c[6] * A + c[4]) + "Partial derivative of denominator of characteristic curve w.r.t. adsorption + potential"; + + Real dden_dT_adsorpt = dden_dc3 * dc_dT_adsorpt[3] + + dden_dc4 * dc_dT_adsorpt[4] + + dden_dc5 * dc_dT_adsorpt[5] + + dden_dc6 * dc_dT_adsorpt[6] + + dden_dA * dA_dT_adsorpt + "Partial derivative of denominator of characteristic curve w.r.t. temprature"; + + Real ddden_dc4_dT_adsorpt = (A^2 / c[5]) * dc_dT_adsorpt[5] + + (2 * A * log(c[5] * A) + A) * dA_dT_adsorpt + "Second-order partial darivative of denominator of characteristic curve w.r.t. + fourth coefficient of isotherm and temperature"; + Real ddden_dc5_dT_adsorpt = (A^2 / c[5]) * dc_dT_adsorpt[4] + + (-c[4] * A^2 / c[5]^2) * dc_dT_adsorpt[5] + + (2 * c[4] * A / c[5]) * dA_dT_adsorpt + "Second-order partial darivative of denominator of characteristic curve w.r.t. + fivth coefficient of isotherm and temperature"; + Real ddden_dc6_dT_adsorpt = 3 * A^2 * dA_dT_adsorpt + "Second-order partial darivative of denominator of characteristic curve w.r.t. + sixth coefficient of isotherm and temperature"; + Real ddden_dA_dT_adsorpt = (A * (2 * log(A * c[5]) + 1)) * dc_dT_adsorpt[4] + + ((2 * A * c[4]) / c[5]) * dc_dT_adsorpt[5] + + (3 * A^2) * dc_dT_adsorpt[6] + + (2 * c[4] * log(c[5] * A) + 6 * c[6] * A + 3 * c[4]) * dA_dT_adsorpt + "Second-order partial darivative of denominator of characteristic curve w.r.t. + adsorption potential and temperature"; + + Real ddden_dT_adsorpt_dT_adsorpt= + ((dden_dc3) * ddc_dT_adsorpt_dT_adsorpt[3]) + + ((dc_dT_adsorpt[4]) * ddden_dc4_dT_adsorpt + + (dden_dc4) * ddc_dT_adsorpt_dT_adsorpt[4]) + + ((dc_dT_adsorpt[5]) * ddden_dc5_dT_adsorpt + + (dden_dc5) * ddc_dT_adsorpt_dT_adsorpt[5]) + + ((dc_dT_adsorpt[6]) * ddden_dc6_dT_adsorpt + + (dden_dc6) * ddc_dT_adsorpt_dT_adsorpt[6]) + + ((dA_dT_adsorpt) * ddden_dA_dT_adsorpt + + (dden_dA) * ddA_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of denominator of characteristic curve w.r.t. + temprature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + ((-1/den^2 * dc_dT_adsorpt[2]) * dden_dT_adsorpt + + (1 / den) * ddc_dT_adsorpt_dT_adsorpt[2]) + + ((-1/den^2 * dden_dT_adsorpt) * dc_dT_adsorpt[2] + + (2 * c[2]/den^3 * dden_dT_adsorpt) * dden_dT_adsorpt + + (-c[2]/den^2) * ddden_dT_adsorpt_dT_adsorpt) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Dubinin-Empirical-1 isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of adsorption potential w.r.t. to pressure at constant + temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressureTemperature ddA_dp_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dp_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Second-order partial derivative of adsorption potential w.r.t. to pressure + and temperature"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1.dW_dA( + A=A, c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of characteristic curve w.r.t. adsorption + potential and temperature at constant pressure"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + dc_dT_adsorpt[2] * dW_dA * dA_dp_adsorpt + + c[2] * ddW_dA_dT_adsorpt * dA_dp_adsorpt + + c[2] * dW_dA * ddA_dp_adsorpt_dT_adsorpt + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare function pi_pT + "Dubinin-Empirical-1 isotherm model: Reduced spreading pressure as function of pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT_num( + integral_pi_lb = 1e-12, + tolerance = 100*Modelica.Constants.eps, + redeclare final function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1.x_pT); + end pi_pT; + + redeclare function p_piT + "Dubinin-Empirical-1 isotherm model: Pressure as function of reduced spreading pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT_num( + p_adsorpt_lb_start = 1, + integral_pi_lb = 1e-12, + tolerance_p_adsorpt = 1e-6, + tolerance_pi = 100*Modelica.Constants.eps, + redeclare final function func_pi_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1.pi_pT); + end p_piT; + + redeclare final function extends W_A + "Dubinin-Empirical-1 isotherm model: Filled pore volume as function of adsorption potential" + + algorithm + W := 1 / max((c[3] + c[4] * A^2 * log(max(c[5] * A, + Modelica.Constants.small)) + c[6] * A^3), Modelica.Constants.small) + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(A=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1.A_W(W, c, A_lb_start, A_ub_start, tolerance))); + end W_A; + + redeclare function A_W + "Dubinin-Empirical-1 isotherm model: Adsorption potential as function of the filled pore volume (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_A_W_num( + A_lb_start = 1, + redeclare final function func_W_A = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1.W_A); + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(W=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1.W_A(A, c, A_lb_start, A_ub_start, tolerance))); + end A_W; + + redeclare final function extends dW_dA + "Dubinin-Empirical-1 isotherm model: Partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + algorithm + dW_dA := -A * (2 * c[4] * log(c[5] * A) + 3 * c[6] * A + c[4]) / + (c[3] + c[4] * A^2 * log(c[5] * A) + c[6] * A^3)^2 + "Partial derivative of the filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + end dW_dA; + + redeclare final function extends ddW_dA_dA + "Dubinin-Empirical-1: Second-order partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + algorithm + ddW_dA_dA := (6 * c[4]^2 * A^2 * log(c[5] * A)^2 + c[4] * (A^2 * (16 * c[6] * + A + 5 * c[4]) - 2 * c[3]) * log(c[5] * A) + 12 * c[6]^2 * A^4 + 9 * c[4] * + c[6] * A^3 + 2 * c[4]^2 * A^2 - 6 * c[3] * c[6] * A - 3 * c[3] * c[4]) / + (A^2 * (c[4] * log(c[5] * A) + c[6] * A) + c[3])^3 + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential at constant pressure and temperature"; + end ddW_dA_dA; + + redeclare final function extends ddW_dA_dT + "Dubinin-Empirical-1: Second-order partial derivative of filled pore volume w.r.t. adsorption potential and temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + Real num = -A * (2 * c[4] * log(c[5] * A) + 3 * c[6] * A + c[4]) + "Numerator of characteristic curve"; + Real den = (c[3] + c[4] * A^2 * log(c[5] * A) + c[6] * A^3)^2 + "Denominator of characteristic curve"; + + Real dnum_dc4 = -A * (2 * log(A * c[5]) + 1) + "Partial derivative of numerator of characteristic curve w.r.t. fourth + coefficient of isotherm"; + Real dnum_dc5 = -(2 * A * c[4]) / c[5] + "Partial derivative of numerator of characteristic curve w.r.t. fivth + coefficient of isotherm"; + Real dnum_dc6 = -3 * A^2 + "Partial derivative of numerator of characteristic curve w.r.t. sixth + coefficient of isotherm"; + Real dnum_dA = -c[4] * (2 * log(c[5] * A) + 3) - 6 * c[6] * A + "Partial derivative of numerator of characteristic curve w.r.t. adsorption + potential"; + + Real dden_dc3 = 2 * (c[3] + A^2 * (A * c[6] + c[4] * log(A * c[5]))) + "Partial derivative of denominator of characteristic curve w.r.t. third + coefficient of isotherm"; + Real dden_dc4 = 2 * A^2 * log(A * c[5]) * (A^2 * (log(A * c[5]) * c[4] + + A * c[6]) + c[3]) + "Partial derivative of denominator of characteristic curve w.r.t. fourth + coefficient of isotherm"; + Real dden_dc5 = (2 * A^2 * c[4] * (A^2 * (c[4] * log(A * c[5]) + A * c[6]) + + c[3])) / c[5] + "Partial derivative of denominator of characteristic curve w.r.t. fivth + coefficient of isotherm"; + Real dden_dc6 = 2 * A^3 * (A^2 * (A * c[6] + c[4] * log(A * c[5])) + c[3]) + "Partial derivative of denominator of characteristic curve w.r.t. sixth + coefficient of isotherm"; + Real dden_dA = 2 * A * (2 * c[4] * log(c[5] * A) + 3 * c[6] * A + c[4]) * + (A^2 * (c[4] * log(c[5] * A) + c[6] * A) + c[3]) + "Partial derivative of denominator of characteristic curve w.r.t. adsorption + potential"; + + Real dnum_dT_adsorpt = dnum_dc4 * dc_dT_adsorpt[4] + + dnum_dc5 * dc_dT_adsorpt[5] + + dnum_dc6 * dc_dT_adsorpt[6] + + dnum_dA * dA_dT_adsorpt + "Partial derivative of numerator of characteristic curve w.r.t. temprature"; + Real dden_dT_adsorpt = dden_dc3 * dc_dT_adsorpt[3] + + dden_dc4 * dc_dT_adsorpt[4] + + dden_dc5 * dc_dT_adsorpt[5] + + dden_dc6 * dc_dT_adsorpt[6] + + dden_dA * dA_dT_adsorpt + "Partial derivative of denominator of characteristic curve w.r.t. temprature"; + + algorithm + ddW_dA_dT := (1/den) * dnum_dT_adsorpt + + (-num/den^2) * dden_dT_adsorpt + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and temperature at constant pressure"; + end ddW_dA_dT; + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 3, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Dubinin-Empirical-1 isotherm model is a four-parameter model for calculating +the equilibrium uptake <i>x_adsorpt</i> as a function of the equilibrium pressure +<i>p_adsorpt</i>. +</p> + +<h4>Main equations</h4> +<p> +The Dubinin-Empirical-1 isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) * W(A(T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + W(A(T<sub>adsorpt</sub>)) = 1 / (a + b * A<sup>2</sup> * <strong>ln</strong>(c * A) + d * A<sup>3</sup>); +</pre> +<pre> + A(T<sub>adsorpt</sub>) = R * T<sub>adsorpt</sub> * <strong>ln</strong>(p<sub>sat</sub>(T<sub>adsorpt</sub>) / p<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>W(A(T<sub>adsorpt</sub>))</i> is the so-called characteristic curve and +<i>A(T<sub>adsorpt</sub>)</i> is the adsorption potential. Within the characteristic +curve, the parameters <i>a</i>, <i>b</i>, and <i>c</i> are fitting parameters. +<br/><br/> +Note that the density of the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> +is assumed to be the saturated liquid density ρ<sub>sat,liq</sub>(T<sub>adsorpt</sub>) +without any further information about the system under consideration. For super-critical +adsorptives (i.e., <i>T<sub>adsorpt</sub> ≥ T<sub>crit</sub></i>), the density of +the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> can be estimated by +</p> +<pre> + ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) = ρ<sub>sat,liq</sub>(T<sub>boiling,0</sub>) * <strong>exp</strong>(-0.0025 * (T<sub>adsorpt</sub> - T<sub>boiling,0</sub>)); +</pre> +<p> +and a pseudo-vapour pressure <i>p<sub>sat</sub>(T<sub>adsorpt</sub>)</i> can be calculated by +</p> +<pre> + p<sub>sat</sub>(T<sub>adsorpt</sub>) = p<sub>crit</sub>(T<sub>adsorpt</sub>) * (T<sub>adsorpt</sub> / T<sub>crit</sub>) ^ k; +</pre> +<p> +where <i>T<sub>boiling,0</sub></i> is the normal boiling point at 1 atm and <i>k</i> is +a fitting parameter specific to the system under consideration. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = p<sub>sat</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2] = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) in kg/m<sup>3</sup> + </li> + <li> + c[3] = a in kg/m<sup>3</sup> + </li> + <li> + c[4] = b in kg.mol<sup>2</sup>/(m<sup>3</sup>.J<sup>2</sup>) + </li> + <li> + c[5] = c in mol/J + </li> + <li> + c[6] = d in kg.mol<sup>3</sup>/(m<sup>3</sup>.J<sup>3</sup>) + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The characteristic curve <i>W(A)</i> must decrease strictly monotonically with + increasing adsorption potential <i>A</i>. Otherwise, the inverses <i>A(W)</i> + and <i>p(x,T</i>) may not be solveable. + </li> + <li> + The reduced spreading pressure <i>π</i> may not be calculable. Accordingly, the + inverse <i>p(π,T)</i> cannot be calculated either. + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the Dubinin-Empirical-1 isotherm model for one +parameter set. In the upper sub-figure, the equilibrium pressure changes with +time, while the equilibrium temperature is constant. In the centered sub-figure, the +equilibrium temperature changes with time, while the equilibrium pressure is constant. +In the lower sub-figure, the characteristic curve is shown. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_empirical_1.png\" alt=\"media_functions_equilibria_pure_dubinin_empirical_1.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> + <li> + Schawe, D. (1999). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD Thesis, Stuttgart. + </li> +</ul> +</html>")); +end DubininEmpirical1; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical1/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical1/package.order new file mode 100644 index 0000000000000000000000000000000000000000..44a21b8e54c5e42bc784fb6013efc1fbbf99d434 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical1/package.order @@ -0,0 +1,12 @@ +x_pT +p_xT +dx_dT +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT +W_A +A_W +dW_dA +ddW_dA_dA +ddW_dA_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical2/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..261393dfa046b729251c592f35a886d4ffd9397f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical2/package.mo @@ -0,0 +1,645 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package DubininEmpirical2 "Package containing all functions regarding the Dubinin-Empirical-2 isotherm model" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponentsDubinin; + + redeclare final function extends x_pT + "Dubinin-Empirical-2 isotherm model: Uptake as function of pressure and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Dubinin-Empirical-2 isotherm model: Pressure as function of uptake and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dT + "Dubinin-Empirical-2 isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + Real num = c[3] + c[5] * sqrt(A) + c[7] * A + c[9] * A * sqrt(A) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * sqrt(A) + c[6] * A + c[8] * A * sqrt(A) + "Denominator of characteristic curve"; + + Real dnum_dc3 = 1 + "Partial derivative of numerator of characteristic curve w.r.t. third + coefficient of isotherm"; + Real dnum_dc5 = sqrt(A) + "Partial derivative of numerator of characteristic curve w.r.t. fivth + coefficient of isotherm"; + Real dnum_dc7 = A + "Partial derivative of numerator of characteristic curve w.r.t. seventh + coefficient of isotherm"; + Real dnum_dc9 = A ^ (3 / 2) + "Partial derivative of numerator of characteristic curve w.r.t. ninth + coefficient of isotherm"; + Real dnum_dA = (3 * c[9] * sqrt(A)) / 2 + c[5] / (2 * sqrt(A)) + c[7] + "Partial derivative of the numerator w.r.t. adsorption potential"; + + Real dden_dc4 = sqrt(A) + "Partial derivative of denominator of characteristic curve w.r.t. fourth + coefficient of isotherm"; + Real dden_dc6 = A + "Partial derivative of denominator of characteristic curve w.r.t. sixth + coefficient of isotherm"; + Real dden_dc8 = A * sqrt(A) + "Partial derivative of denominator of characteristic curve w.r.t. eigth + coefficient of isotherm"; + Real dden_dA = (3 * c[8] * sqrt(A)) / 2 + c[4] / (2 * sqrt(A)) + c[6] + "Partial derivative of the numerator w.r.t. adsorption potential"; + + Real dnum_dT_adsorpt = dnum_dc3 * dc_dT_adsorpt[3] + + dnum_dc5 * dc_dT_adsorpt[5] + + dnum_dc7 * dc_dT_adsorpt[7] + + dnum_dc9 * dc_dT_adsorpt[9] + + dnum_dA * dA_dT_adsorpt + "Partial derivative of numerator of characteristic curve w.r.t. temprature"; + Real dden_dT_adsorpt = dden_dc4 * dc_dT_adsorpt[4] + + dden_dc6 * dc_dT_adsorpt[6] + + dden_dc8 * dc_dT_adsorpt[8] + + dden_dA * dA_dT_adsorpt + "Partial derivative of denominator of characteristic curve w.r.t. temprature"; + + algorithm + dx_adsorpt_dT_adsorpt := (num / den) * dc_dT_adsorpt[2] + + (c[2] / den) * dnum_dT_adsorpt + + (-c[2] * num / den^2) * dden_dT_adsorpt + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dT_dT + "Dubinin-Empirical-1 isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperatureTemperature ddA_dT_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dT_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1], + ddp_sat_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt[1]) + "Second-order partial derivative of adsorption potential w.r.t. equilibrium + temperature at constant pressure"; + + Real num = c[3] + c[5] * sqrt(A) + c[7] * A + c[9] * A * sqrt(A) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * sqrt(A) + c[6] * A + c[8] * A * sqrt(A) + "Denominator of characteristic curve"; + + Real dnum_dc3 = 1 + "Partial derivative of numerator of characteristic curve w.r.t. third + coefficient of isotherm"; + Real dnum_dc5 = sqrt(A) + "Partial derivative of numerator of characteristic curve w.r.t. fivth + coefficient of isotherm"; + Real dnum_dc7 = A + "Partial derivative of numerator of characteristic curve w.r.t. seventh + coefficient of isotherm"; + Real dnum_dc9 = A ^ (3 / 2) + "Partial derivative of numerator of characteristic curve w.r.t. ninth + coefficient of isotherm"; + Real dnum_dA = (3 * c[9] * sqrt(A)) / 2 + c[5] / (2 * sqrt(A)) + c[7] + "Partial derivative of the numerator w.r.t. adsorption potential"; + + Real dden_dc4 = sqrt(A) + "Partial derivative of denominator of characteristic curve w.r.t. fourth + coefficient of isotherm"; + Real dden_dc6 = A + "Partial derivative of denominator of characteristic curve w.r.t. sixth + coefficient of isotherm"; + Real dden_dc8 = A * sqrt(A) + "Partial derivative of denominator of characteristic curve w.r.t. eigth + coefficient of isotherm"; + Real dden_dA = (3 * c[8] * sqrt(A)) / 2 + c[4] / (2 * sqrt(A)) + c[6] + "Partial derivative of the numerator w.r.t. adsorption potential"; + + Real dnum_dT_adsorpt= + dnum_dc3 * dc_dT_adsorpt[3] + + dnum_dc5 * dc_dT_adsorpt[5] + + dnum_dc7 * dc_dT_adsorpt[7] + + dnum_dc9 * dc_dT_adsorpt[9] + + dnum_dA * dA_dT_adsorpt + "Partial derivative of numerator of characteristic curve w.r.t. temprature"; + Real dden_dT_adsorpt= + dden_dc4 * dc_dT_adsorpt[4] + + dden_dc6 * dc_dT_adsorpt[6] + + dden_dc8 * dc_dT_adsorpt[8] + + dden_dA * dA_dT_adsorpt + "Partial derivative of denominator of characteristic curve w.r.t. temprature"; + + Real ddnum_dc5_dT_adsorpt = (1 / (2 * sqrt(A))) * dA_dT_adsorpt + "Second-order partial derivative of numerator of characteristic curve w.r.t. + fivth coefficient of isotherm and temperature"; + Real ddnum_dc7_dT_adsorpt = (1) * dA_dT_adsorpt + "Partial derivative of numerator of characteristic curve w.r.t. seventh + coefficient of isotherm and temperature"; + Real ddnum_dc9_dT_adsorpt = ((3 * sqrt(A)) / 2) * dA_dT_adsorpt + "Second-order partial derivative of numerator of characteristic curve w.r.t. ninth + coefficient of isotherm"; + Real ddnum_dA_dT_adsorpt = (1 / (2 * sqrt(A))) * dc_dT_adsorpt[5] + + (1) * dc_dT_adsorpt[7] + + ((3 * sqrt(A)) / 2) * dc_dT_adsorpt[9] + + ((3 * c[9] * A - c[5]) / (4 * A^(3 / 2))) * dA_dT_adsorpt + "Second-order partial derivative of the numerator w.r.t. adsorption potential + and temperature"; + + Real ddden_dc4_dT_adsorpt = (1 / (2 * sqrt(A))) * dA_dT_adsorpt + "Second-order partial derivative of denominator of characteristic curve w.r.t. + fourth coefficient of isotherm and temperature"; + Real ddden_dc6_dT_adsorpt = (1) * dA_dT_adsorpt + "Second-order partial derivative of denominator of characteristic curve w.r.t. + sixth coefficient of isotherm and temperature"; + Real ddden_dc8_dT_adsorpt = ((3 * sqrt(A)) / 2) * dA_dT_adsorpt + "Second-order partial derivative of denominator of characteristic curve w.r.t. + eigth coefficient of isotherm and temperature"; + Real ddden_dA_dT_adsorpt = (1 / (2 * sqrt(A))) * dc_dT_adsorpt[4] + + (1) * dc_dT_adsorpt[6] + + ((3 * sqrt(A)) / 2) * dc_dT_adsorpt[8] + + ((3 * c[8] * A - c[4]) / (4 * A^(3 / 2))) * dA_dT_adsorpt + "Second-order partial derivative of the numerator w.r.t. adsorption potential + and temperature"; + + Real ddnum_dT_adsorpt_dT_adsorpt= + ((dnum_dc3) * ddc_dT_adsorpt_dT_adsorpt[3]) + + ((dc_dT_adsorpt[5]) * ddnum_dc5_dT_adsorpt + + (dnum_dc5) * ddc_dT_adsorpt_dT_adsorpt[5]) + + ((dc_dT_adsorpt[7]) * ddnum_dc7_dT_adsorpt + + (dnum_dc7) * ddc_dT_adsorpt_dT_adsorpt[7]) + + ((dc_dT_adsorpt[9]) * ddnum_dc9_dT_adsorpt + + (dnum_dc9) * ddc_dT_adsorpt_dT_adsorpt[9]) + + ((dA_dT_adsorpt) * ddnum_dA_dT_adsorpt + + (dnum_dA) * ddA_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of numerator of characteristic curve w.r.t. + temprature"; + Real ddden_dT_adsorpt_dT_adsorpt= + ((dc_dT_adsorpt[4]) * ddden_dc4_dT_adsorpt + + (dden_dc4) * ddc_dT_adsorpt_dT_adsorpt[4]) + + ((dc_dT_adsorpt[6]) * ddden_dc6_dT_adsorpt + + (dden_dc6) * ddc_dT_adsorpt_dT_adsorpt[6]) + + ((dc_dT_adsorpt[8]) * ddden_dc8_dT_adsorpt + + (dden_dc8) * ddc_dT_adsorpt_dT_adsorpt[8]) + + ((dA_dT_adsorpt) * ddden_dA_dT_adsorpt + + (dden_dA) * ddA_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of denominator of characteristic curve w.r.t. + temprature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + ((1/den * dc_dT_adsorpt[2]) * dnum_dT_adsorpt + + (-num / den^2 * dc_dT_adsorpt[2]) * dden_dT_adsorpt + + (num / den) * ddc_dT_adsorpt_dT_adsorpt[2]) + + ((1/den * dnum_dT_adsorpt) * dc_dT_adsorpt[2] + + (-c[2] / den^2 * dnum_dT_adsorpt) * dden_dT_adsorpt + + (c[2] / den) * ddnum_dT_adsorpt_dT_adsorpt) + + ((-num / den^2 * dden_dT_adsorpt) * dc_dT_adsorpt[2] + + (-c[2] / den^2 * dden_dT_adsorpt) * dnum_dT_adsorpt + + (2 * c[2] * num / den^3 * dden_dT_adsorpt) * dden_dT_adsorpt + + (-c[2] * num / den^2) * ddden_dT_adsorpt_dT_adsorpt) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Dubinin-Empirical-2 isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of adsorption potential w.r.t. to pressure at constant + temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressureTemperature ddA_dp_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dp_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Second-order partial derivative of adsorption potential w.r.t. to pressure + and temperature"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2.dW_dA( + A=A, c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of characteristic curve w.r.t. adsorption + potential and temperature at constant pressure"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + dc_dT_adsorpt[2] * dW_dA * dA_dp_adsorpt + + c[2] * ddW_dA_dT_adsorpt * dA_dp_adsorpt + + c[2] * dW_dA * ddA_dp_adsorpt_dT_adsorpt + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare function pi_pT + "Dubinin-Empirical-2 isotherm model: Reduced spreading pressure as function of pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT_num( + integral_pi_lb = 1e-2, + tolerance = 1e-4, + redeclare final function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2.x_pT); + end pi_pT; + + redeclare function p_piT + "Dubinin-Empirical-2 isotherm model: Pressure as function of reduced spreading pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT_num( + p_adsorpt_lb_start = 1, + integral_pi_lb = 1e-2, + tolerance_p_adsorpt = 1e-6, + tolerance_pi = 1e-4, + redeclare final function func_pi_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2.pi_pT); + end p_piT; + + redeclare final function extends W_A + "Dubinin-Empirical-2 isotherm model: Filled pore volume as function of adsorption potential" + algorithm + W := (c[3] + c[5] * sqrt(max(A, Modelica.Constants.small)) + + c[7] * A + c[9] * A * sqrt(max(A, Modelica.Constants.small))) / + (1 + c[4] * sqrt(max(A, Modelica.Constants.small)) + + c[6] * A + c[8] * A * sqrt(max(A, Modelica.Constants.small))) + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(A=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2.A_W(W, c, A_lb_start, A_ub_start, tolerance))); + end W_A; + + redeclare function A_W + "Dubinin-Empirical-2 isotherm model: Adsorption potential as function of the filled pore volume (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_A_W_num( + redeclare final function func_W_A = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2.W_A); + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(W=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2.W_A(A, c, A_lb_start, A_ub_start, tolerance))); + end A_W; + + redeclare final function extends dW_dA + "Dubinin-Empirical-2 isotherm model: Partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + + // + // Definition of variables + // +protected + Real num = c[3] + c[5] * sqrt(A) + c[7] * A + c[9] * A * sqrt(A) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * sqrt(A) + c[6] * A + c[8] * A * sqrt(A) + "Denominator of characteristic curve"; + + Real dnum_dA = (3 * c[9] * sqrt(A)) / 2 + c[5] / (2 * sqrt(A)) + c[7] + "Partial derivative of the numerator w.r.t. adsorption potential"; + Real dden_dA = (3 * c[8] * sqrt(A)) / 2 + c[4] / (2 * sqrt(A)) + c[6] + "Partial derivative of the numerator w.r.t. adsorption potential"; + + algorithm + dW_dA := (dnum_dA * den - num * dden_dA) / den^2 + "Partial derivative of the filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + end dW_dA; + + redeclare final function extends ddW_dA_dA + "Dubinin-Empirical-1: Second-order partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + + // + // Definition of variables + // +protected + Real num = c[3] + c[5] * sqrt(A) + c[7] * A + c[9] * A * sqrt(A) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * sqrt(A) + c[6] * A + c[8] * A * sqrt(A) + "Denominator of characteristic curve"; + + Real dnum_dA = (3 * c[9] * sqrt(A)) / 2 + c[5] / (2 * sqrt(A)) + c[7] + "Partial derivative of the numerator w.r.t. adsorption potential"; + Real dden_dA = (3 * c[8] * sqrt(A)) / 2 + c[4] / (2 * sqrt(A)) + c[6] + "Partial derivative of the numerator w.r.t. adsorption potential"; + + Real ddnum_dA_dA = (3 * c[9] * A - c[5]) / (4 * A^(3 / 2)) + "Second-order partial derivative of the numerator w.r.t. adsorption potential"; + Real ddden_dA_dA = (3 * c[8] * A - c[4]) / (4 * A^(3 / 2)) + "Second-order partial derivative of the numerator w.r.t. adsorption potential"; + + algorithm + ddW_dA_dA := + (1 / den) * ddnum_dA_dA + + (-dnum_dA / den^2) * dden_dA + + (-dden_dA / den^2) * dnum_dA + + (-num / den^2) * ddden_dA_dA + + (2 * num * dden_dA / den^3) * dden_dA + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential at constant pressure and temperature"; + end ddW_dA_dA; + + redeclare final function extends ddW_dA_dT + "Dubinin-Empirical-1: Second-order partial derivative of filled pore volume w.r.t. adsorption potential and temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + Real num = c[3] + c[5] * sqrt(A) + c[7] * A + c[9] * A * sqrt(A) + "Numerator of characteristic curve"; + Real den = 1 + c[4] * sqrt(A) + c[6] * A + c[8] * A * sqrt(A) + "Denominator of characteristic curve"; + + Real dnum_dc3 = 1 + "Partial derivative of numerator of characteristic curve w.r.t. third + coefficient of isotherm"; + Real dnum_dc5 = sqrt(A) + "Partial derivative of numerator of characteristic curve w.r.t. fivth + coefficient of isotherm"; + Real dnum_dc7 = A + "Partial derivative of numerator of characteristic curve w.r.t. seventh + coefficient of isotherm"; + Real dnum_dc9 = A * sqrt(A) + "Partial derivative of numerator of characteristic curve w.r.t. ninth + coefficient of isotherm"; + Real dnum_dA = (3 * c[9] * sqrt(A)) / 2 + c[5] / (2 * sqrt(A)) + c[7] + "Partial derivative of the numerator w.r.t. adsorption potential"; + + Real dden_dc4 = sqrt(A) + "Partial derivative of denominator of characteristic curve w.r.t. fourth + coefficient of isotherm"; + Real dden_dc6 = A + "Partial derivative of denominator of characteristic curve w.r.t. sixth + coefficient of isotherm"; + Real dden_dc8 = A * sqrt(A) + "Partial derivative of denominator of characteristic curve w.r.t. eigth + coefficient of isotherm"; + Real dden_dA = (3 * c[8] * sqrt(A)) / 2 + c[4] / (2 * sqrt(A)) + c[6] + "Partial derivative of the numerator w.r.t. adsorption potential"; + + Real dnum_dT_adsorpt = dnum_dc3 * dc_dT_adsorpt[3] + + dnum_dc5 * dc_dT_adsorpt[5] + + dnum_dc7 * dc_dT_adsorpt[7] + + dnum_dc9 * dc_dT_adsorpt[9] + + dnum_dA * dA_dT_adsorpt + "Partial derivative of numerator of characteristic curve w.r.t. temprature"; + Real dden_dT_adsorpt = dden_dc4 * dc_dT_adsorpt[4] + + dden_dc6 * dc_dT_adsorpt[6] + + dden_dc8 * dc_dT_adsorpt[8] + + dden_dA * dA_dT_adsorpt + "Partial derivative of denominator of characteristic curve w.r.t. temprature"; + + Real ddnum_dA_dc5 = 1 / (2 * sqrt(A)) + "Second-order partial derivative of the numerator w.r.t. adsorption potential + fivth coefficient of isotherm"; + Real ddnum_dA_dc7 = 1 + "Second-order partial derivative of the numerator w.r.t. adsorption potential + seventh coefficient of isotherm"; + Real ddnum_dA_dc9 = (3 * sqrt(A)) / 2 + "Second-order partial derivative of the numerator w.r.t. adsorption potential + ninth coefficient of isotherm"; + Real ddnum_dA_dA = (3 * c[9] * A - c[5]) / (4 * A^(3 / 2)) + "Second-order partial derivative of the numerator w.r.t. adsorption potential"; + + Real ddden_dA_dc4 = 1 / (2 * sqrt(A)) + "Second-order partial derivative of the denominator w.r.t. adsorption potential + fourth coefficient of isotherm"; + Real ddden_dA_dc6 = 1 + "Second-order partial derivative of the denominator w.r.t. adsorption potential + sixth coefficient of isotherm"; + Real ddden_dA_dc8 = (3 * sqrt(A)) / 2 + "Second-order partial derivative of the denominator w.r.t. adsorption potential + eigth coefficient of isotherm"; + Real ddden_dA_dA = (3 * c[8] * A - c[4]) / (4 * A^(3 / 2)) + "Second-order partial derivative of the denominator w.r.t. adsorption potential"; + + Real ddnum_dA_dT_adsorpt = ddnum_dA_dc5 * dc_dT_adsorpt[5] + + ddnum_dA_dc7 * dc_dT_adsorpt[7] + + ddnum_dA_dc9 * dc_dT_adsorpt[9] + + ddnum_dA_dA * dA_dT_adsorpt + "Second-order partial derivative of the numerator w.r.t. adsorption potential + and temperature"; + + Real ddden_dA_dT_adsorpt = ddden_dA_dc4 * dc_dT_adsorpt[4] + + ddden_dA_dc6 * dc_dT_adsorpt[6] + + ddden_dA_dc8 * dc_dT_adsorpt[8] + + ddden_dA_dA * dA_dT_adsorpt + "Second-order partial derivative of the denominator w.r.t. adsorption potential + and temperature"; + + algorithm + ddW_dA_dT := (1 / den) * ddnum_dA_dT_adsorpt + + (-dnum_dA / den^2) * dden_dT_adsorpt + + (-dden_dA / den^2) * dnum_dT_adsorpt + + (-num / den^2) * ddden_dA_dT_adsorpt + + (2 * num * dden_dA / den^3) * dden_dT_adsorpt + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and temperature at constant pressure"; + end ddW_dA_dT; + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Dubinin-Empirical-2 isotherm model is a nine-parameter model for calculating +the equilibrium uptake <i>x_adsorpt</i> as a function of the equilibrium pressure +<i>p_adsorpt</i>. +</p> + +<h4>Main equations</h4> +<p> +The Dubinin-Empirical-2 isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) * W(A(T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + W(A(T<sub>adsorpt</sub>)) = (a + c * <strong>sqrt</strong>(A) + e * A + g * A * <strong>sqrt</strong>(A)) / (1 + b * <strong>sqrt</strong>(A) + d * A + f * A * <strong>sqrt</strong>(A)); +</pre> +<pre> + A(T<sub>adsorpt</sub>) = R * T<sub>adsorpt</sub> * <strong>ln</strong>(p<sub>sat</sub>(T<sub>adsorpt</sub>) / p<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>W(A(T<sub>adsorpt</sub>))</i> is the so-called characteristic curve and +<i>A(T<sub>adsorpt</sub>)</i> is the adsorption potential. Within the characteristic +curve, the parameters <i>a</i>, <i>b</i>, and <i>c</i> are fitting parameters. +<br/><br/> +Note that the density of the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> +is assumed to be the saturated liquid density ρ<sub>sat,liq</sub>(T<sub>adsorpt</sub>) +without any further information about the system under consideration. For super-critical +adsorptives (i.e., <i>T<sub>adsorpt</sub> ≥ T<sub>crit</sub></i>), the density of +the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> can be estimated by +</p> +<pre> + ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) = ρ<sub>sat,liq</sub>(T<sub>boiling,0</sub>) * <strong>exp</strong>(-0.0025 * (T<sub>adsorpt</sub> - T<sub>boiling,0</sub>)); +</pre> +<p> +and a pseudo-vapour pressure <i>p<sub>sat</sub>(T<sub>adsorpt</sub>)</i> can be calculated by +</p> +<pre> + p<sub>sat</sub>(T<sub>adsorpt</sub>) = p<sub>crit</sub>(T<sub>adsorpt</sub>) * (T<sub>adsorpt</sub> / T<sub>crit</sub>) ^ k; +</pre> +<p> +where <i>T<sub>boiling,0</sub></i> is the normal boiling point at 1 atm and <i>k</i> is +a fitting parameter specific to the system under consideration. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = p<sub>sat</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2] = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) in kg/m<sup>3</sup> + </li> + <li> + c[3] = a in m<sup>3</sup>/kg + </li> + <li> + c[4] = b in - + </li> + <li> + c[5] = c in m<sup>3</sup>/kg + </li> + <li> + c[6] = d in mol<sup>3</sup>/J + </li> + <li> + c[7] = e in m<sup>3</sup>.mol/(kg.J) + </li> + <li> + c[8] = f in mol<sup>3</sup>/J + </li> + <li> + c[9] = g in m<sup>3</sup>.mol/(kg.J) + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The characteristic curve <i>W(A)</i> must decrease strictly monotonically with + increasing adsorption potential <i>A</i>. Otherwise, the inverses <i>A(W)</i> + and <i>p(x,T</i>) may not be solveable. + </li> + <li> + The reduced spreading pressure <i>π</i> may not be calculable. Accordingly, the + inverse <i>p(π,T)</i> cannot be calculated either. + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the Dubinin-Empirical-2 isotherm model for one +parameter set. In the upper sub-figure, the equilibrium pressure changes with +time, while the equilibrium temperature is constant. In the centered sub-figure, the +equilibrium temperature changes with time, while the equilibrium pressure is constant. +In the lower sub-figure, the characteristic curve is shown. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_empirical_2.png\" alt=\"media_functions_equilibria_pure_dubinin_empirical_2.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> + <li> + Schawe, D. (1999). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD Thesis, Stuttgart. + </li> +</ul> +</html>")); +end DubininEmpirical2; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical2/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..44a21b8e54c5e42bc784fb6013efc1fbbf99d434 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininEmpirical2/package.order @@ -0,0 +1,12 @@ +x_pT +p_xT +dx_dT +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT +W_A +A_W +dW_dA +ddW_dA_dA +ddW_dA_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininLorentzianCumulative/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininLorentzianCumulative/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..10f579e8c6d7858918f43231cf5b4cfffd44aed7 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininLorentzianCumulative/package.mo @@ -0,0 +1,558 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package DubininLorentzianCumulative "Package containing all functions regarding the Dubinin isotherm model using a 'Lorentzian Cumulative' equation type (i.e., arctan-function)" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponentsDubinin; + + redeclare final function extends x_pT + "Dubinin-Lorentzian-Cumulative isotherm model: Uptake as function of pressure and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Dubinin-Lorentzian-Cumulative isotherm model: Pressure as function of uptake and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dT + "Dubinin-Lorentzian-Cumulative isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature"; + + SorpLib.Units.FilledPoreVolume W= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.W_A( + A=A, c=c) + "Filled pore volume"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A, c=c) + "Partial derivative of characteristic curve w.r.t. adsorption potential"; + + Real dx_adsorpt_dA = c[2] * dW_dA + "Derivative of uptake w.r.t. to adsorption potential"; + Real dx_adsorpt_dc2 = W + "Derivative of uptake w.r.t. to second coefficient of Dubinin-Lorentzian-Cumulative + isotherm"; + Real dx_adsorpt_dc3 = c[2] / Modelica.Constants.pi * + (Modelica.Math.atan((A - c[4]) / c[5]) + Modelica.Constants.pi / 2) + "Derivative of uptake w.r.t. to third coefficient of Dubinin-Lorentzian-Cumulative + isotherm"; + Real dx_adsorpt_dc4 = -c[2] * c[3] / + (Modelica.Constants.pi * c[5] * ((A - c[4])^2 / c[5]^2 + 1)) + "Derivative of uptake w.r.t. to fourth coefficient of Dubinin-Lorentzian-Cumulative + isotherm"; + Real dx_adsorpt_dc5 = -c[2] * c[3] * (A - c[4]) / + (Modelica.Constants.pi * c[5]^2 * ((A - c[4])^2 / c[5]^2 + 1)) + "Derivative of uptake w.r.t. to fivth coefficient of Dubinin-Lorentzian-Cumulative + isotherm"; + Real dx_adsorpt_dc6 = c[2] + "Derivative of uptake w.r.t. to sixth coefficient of Dubinin-Lorentzian-Cumulative + isotherm"; + + algorithm + dx_adsorpt_dT_adsorpt := + dx_adsorpt_dA*dA_dT_adsorpt + + dx_adsorpt_dc2*dc_dT_adsorpt[2] + + dx_adsorpt_dc3*dc_dT_adsorpt[3] + + dx_adsorpt_dc4*dc_dT_adsorpt[4] + + dx_adsorpt_dc5*dc_dT_adsorpt[5] + + dx_adsorpt_dc6*dc_dT_adsorpt[6] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dT_dT + "Dubinin-Lorentzian-Cumulative isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperatureTemperature ddA_dT_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dT_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1], + ddp_sat_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt[1]) + "Second-order partial derivative of adsorption potential w.r.t. equilibrium + temperature at constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and temperature at constant pressure"; + + Real dx_adsorpt_dA = c[2] * dW_dA + "Derivative of uptake w.r.t. to adsorption potential"; + Real dx_adsorpt_dc2 = c[3] / Modelica.Constants.pi * + (Modelica.Math.atan((A - c[4]) / c[5]) + Modelica.Constants.pi / 2) + c[6] + "Derivative of uptake w.r.t. to second coefficient of Dubinin-Lorentzian-Cumulative + isotherm"; + Real dx_adsorpt_dc3 = c[2] / Modelica.Constants.pi * + (Modelica.Math.atan((A - c[4]) / c[5]) + Modelica.Constants.pi / 2) + "Derivative of uptake w.r.t. to third coefficient of Dubinin-Lorentzian-Cumulative + isotherm"; + Real dx_adsorpt_dc4 = -c[2] * c[3] / + (Modelica.Constants.pi * c[5] * ((A - c[4])^2 / c[5]^2 + 1)) + "Derivative of uptake w.r.t. to fourth coefficient of Dubinin-Lorentzian-Cumulative + isotherm"; + Real dx_adsorpt_dc5 = -c[2] * c[3] * (A - c[4]) / + (Modelica.Constants.pi * c[5]^2 * ((A - c[4])^2 / c[5]^2 + 1)) + "Derivative of uptake w.r.t. to fivth coefficient of Dubinin-Lorentzian-Cumulative + isotherm"; + Real dx_adsorpt_dc6 = c[2] + "Derivative of uptake w.r.t. to sixth coefficient of Dubinin-Lorentzian-Cumulative + isotherm"; + + Real ddx_adsorpt_dc4_dc4 = -(2 * c[2] * c[3] * (A - c[4])) / + (Modelica.Constants.pi * c[5]^3 * ((A - c[4])^2 / c[5]^2 + 1)^2) + "Second-order partial derivative of uptake w.r.t. to fourth coefficient of + Dubinin-Lorentzian-Cumulative isotherm"; + Real ddx_adsorpt_dc5_dc5 = -(2 * c[2] * c[3] * (c[4] - A) * c[5]) / + (Modelica.Constants.pi * (c[5]^2 + c[4]^2 - 2 * A * c[4] + A^2)^2) + "Second-order partial derivative of uptake w.r.t. to fivth coefficient of + Dubinin-Lorentzian-Cumulative isotherm"; + + Real ddx_adsorpt_dc2_dA= c[3] / (Modelica.Constants.pi * c[5] * + ((A - c[4])^2 / c[5]^2 + 1)) + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Dubinin-Lorentzian-Cumulative isotherm and adsorption potential"; + Real ddx_adsorpt_dc2_dc3 = (Modelica.Math.atan((A - c[4]) / c[5]) + + Modelica.Constants.pi / 2) / Modelica.Constants.pi + "Second-order partial derivative of uptake w.r.t. to second and third + coefficient of Dubinin-Lorentzian-Cumulative isotherm"; + Real ddx_adsorpt_dc2_dc4 = -c[3] / (Modelica.Constants.pi * c[5] * + ((A - c[4])^2 / c[5]^2 + 1)) + "Second-order partial derivative of uptake w.r.t. to second and fourht + coefficient of Dubinin-Lorentzian-Cumulative isotherm"; + Real ddx_adsorpt_dc2_dc5 = -(c[3] * (A - c[4])) / (Modelica.Constants.pi * + ((A - c[4])^2 / c[5]^2 + 1) * c[5]^2) + "Second-order partial derivative of uptake w.r.t. to second and fivth + coefficient of Dubinin-Lorentzian-Cumulative isotherm"; + Real ddx_adsorpt_dc2_dc6 = 1 + "Second-order partial derivative of uptake w.r.t. to second and sixth + coefficient of Dubinin-Lorentzian-Cumulative isotherm"; + + Real ddx_adsorpt_dc3_dA = c[2] / (Modelica.Constants.pi * c[5] * + ((A - c[4])^2 / c[5]^2 + 1)) + "Second-order partial derivative of uptake w.r.t. to third coefficient of + Dubinin-Lorentzian-Cumulative isotherm and adsorption potential"; + Real ddx_adsorpt_dc3_dc4 = -c[2] / (Modelica.Constants.pi * c[5] * + ((A - c[4])^2 / c[5]^2 + 1)) + "Second-order partial derivative of uptake w.r.t. to third and fourht + coefficient of Dubinin-Lorentzian-Cumulative isotherm"; + Real ddx_adsorpt_dc3_dc5 = -(c[2] * (A - c[4])) / (Modelica.Constants.pi * + ((A - c[4])^2 / c[5]^2 + 1) * c[5]^2) + "Second-order partial derivative of uptake w.r.t. to third and fivth + coefficient of Dubinin-Lorentzian-Cumulative isotherm"; + + Real ddx_adsorpt_dc4_dA = (2 * c[2] * c[3] * (A - c[4])) / + (Modelica.Constants.pi * c[5]^3 * ((A - c[4])^2 / c[5]^2 + 1)^2) + "Second-order partial derivative of uptake w.r.t. to fourth coefficient of + Dubinin-Lorentzian-Cumulative isotherm and adsorption potential"; + Real ddx_adsorpt_dc4_dc5 = (c[2] * c[3] * (c[5]^2 - c[4]^2 + 2 * A * c[4] - + A^2)) / (Modelica.Constants.pi * (c[5]^2 + c[4]^2 - 2 * A * c[4] + A^2)^2) + "Second-order partial derivative of uptake w.r.t. to fourth and fivth + coefficient of Dubinin-Lorentzian-Cumulative isotherm"; + + Real ddx_adsorpt_dc5_dA = (2 * c[2] * c[3] * (A - c[4])^2) / + (Modelica.Constants.pi * c[5]^4 * ((A - c[4])^2 / c[5]^2 + 1)^2) - (c[2] * + c[3]) / (Modelica.Constants.pi * c[5]^2 * ((A - c[4])^2 / c[5]^2 + 1)) + "Second-order partial derivative of uptake w.r.t. to fivth coefficient of + Dubinin-Lorentzian-Cumulative isotherm and adsorption potential"; + + Real ddx_adsorpt_dA_dT_dT_adsorpt = dc_dT_adsorpt[2] * dW_dA + + c[2] * ddW_dA_dT_adsorpt + "Second-order partial derivative of uptake w.r.t. to adsorption potential + and temperature"; + Real ddx_adsorpt_dc2_dT_dT_adsorpt = ddx_adsorpt_dc2_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[3] + + ddx_adsorpt_dc2_dc4*dc_dT_adsorpt[4] + + ddx_adsorpt_dc2_dc5*dc_dT_adsorpt[5] + + ddx_adsorpt_dc2_dc6*dc_dT_adsorpt[6] + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Dubinin-Lorentzian-Cumulative isotherm and temperature"; + Real ddx_adsorpt_dc3_dT_dT_adsorpt = ddx_adsorpt_dc3_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[2] + + ddx_adsorpt_dc3_dc4*dc_dT_adsorpt[4] + + ddx_adsorpt_dc3_dc5*dc_dT_adsorpt[5] + "Second-order partial derivative of uptake w.r.t. to third coefficient of + Dubinin-Lorentzian-Cumulative isotherm and temperature"; + Real ddx_adsorpt_dc4_dT_dT_adsorpt = ddx_adsorpt_dc4_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc4*dc_dT_adsorpt[2] + + ddx_adsorpt_dc3_dc4*dc_dT_adsorpt[3] + + ddx_adsorpt_dc4_dc4*dc_dT_adsorpt[4] + + ddx_adsorpt_dc4_dc5*dc_dT_adsorpt[5] + "Second-order partial derivative of uptake w.r.t. to fourth coefficient of + Dubinin-Lorentzian-Cumulative isotherm and temperature"; + Real ddx_adsorpt_dc5_dT_dT_adsorpt = ddx_adsorpt_dc5_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc5*dc_dT_adsorpt[2] + + ddx_adsorpt_dc3_dc5*dc_dT_adsorpt[3] + + ddx_adsorpt_dc4_dc5*dc_dT_adsorpt[4] + + ddx_adsorpt_dc5_dc5*dc_dT_adsorpt[5] + "Second-order partial derivative of uptake w.r.t. to fivth coefficient of + Dubinin-Lorentzian-Cumulative isotherm and temperature"; + Real ddx_adsorpt_dc6_dT_dT_adsorpt = ddx_adsorpt_dc2_dc6*dc_dT_adsorpt[2] + "Second-order partial derivative of uptake w.r.t. to sixth coefficient of + Dubinin-Lorentzian-Cumulative isotherm and temperature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + (ddx_adsorpt_dA_dT_dT_adsorpt*dA_dT_adsorpt + + dx_adsorpt_dA*ddA_dT_adsorpt_dT_adsorpt) + + (ddx_adsorpt_dc2_dT_dT_adsorpt*dc_dT_adsorpt[2] + + dx_adsorpt_dc2*ddc_dT_adsorpt_dT_adsorpt[2]) + + (ddx_adsorpt_dc3_dT_dT_adsorpt*dc_dT_adsorpt[3] + + dx_adsorpt_dc3*ddc_dT_adsorpt_dT_adsorpt[3]) + + (ddx_adsorpt_dc4_dT_dT_adsorpt*dc_dT_adsorpt[4] + + dx_adsorpt_dc4*ddc_dT_adsorpt_dT_adsorpt[4]) + + (ddx_adsorpt_dc5_dT_dT_adsorpt*dc_dT_adsorpt[5] + + dx_adsorpt_dc5*ddc_dT_adsorpt_dT_adsorpt[5]) + + (ddx_adsorpt_dc6_dT_dT_adsorpt*dc_dT_adsorpt[6] + + dx_adsorpt_dc6*ddc_dT_adsorpt_dT_adsorpt[6]) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Dubinin-Lorentzian-Cumulative isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of adsorption potential w.r.t. to pressure at constant + temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressureTemperature ddA_dp_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dp_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Second-order partial derivative of adsorption potential w.r.t. to pressure + and temperature"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A, c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and temperature at constant pressure"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + dc_dT_adsorpt[2] * dW_dA * dA_dp_adsorpt + + c[2] * ddW_dA_dT_adsorpt * dA_dp_adsorpt + + c[2] * dW_dA * ddA_dp_adsorpt_dT_adsorpt + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare function pi_pT + "Dubinin-Lorentzian-Cumulative isotherm model: Reduced spreading pressure as function of pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT_num( + integral_pi_lb = 1e-12, + tolerance = 100*Modelica.Constants.eps, + redeclare final function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT); + end pi_pT; + + redeclare function p_piT + "Dubinin-Lorentzian-Cumulative isotherm model: Pressure as function of reduced spreading pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT_num( + p_adsorpt_lb_start = 1, + integral_pi_lb = 1e-12, + tolerance_p_adsorpt = 1e-6, + tolerance_pi = 100*Modelica.Constants.eps, + redeclare final function func_pi_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.pi_pT); + end p_piT; + + redeclare final function extends W_A + "Dubinin-Lorentzian-Cumulative isotherm model: Filled pore volume as function of adsorption potential" + algorithm + W := c[3] / Modelica.Constants.pi * + (Modelica.Math.atan((A - c[4]) / c[5]) + Modelica.Constants.pi / 2) + c[6] + "Filled pore volume"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(A=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.A_W(W, c, A_lb_start, A_ub_start, tolerance))); + end W_A; + + redeclare final function extends A_W + "Dubinin-Lorentzian-Cumulative isotherm model: Adsorption potential as function of the filled pore volume" + algorithm + A := c[5] * Modelica.Math.tan((W - c[6]) / c[3] * Modelica.Constants.pi - + Modelica.Constants.pi / 2) + c[4] + "Adsorption potential"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(W=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.W_A(A, c, A_lb_start, A_ub_start, tolerance))); + end A_W; + + redeclare final function extends dW_dA + "Dubinin-Lorentzian-Cumulative isotherm model: Partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + algorithm + dW_dA := c[3] / (Modelica.Constants.pi * c[5] * ((A - c[4])^2 / c[5]^2 + 1)) + "Partial derivative of the filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + end dW_dA; + + redeclare final function extends ddW_dA_dA + "Dubinin-Lorentzian-Cumulative: Second-order partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + algorithm + ddW_dA_dA := -(2 * c[3] * c[5] * (A - c[4])) / (Modelica.Constants.pi * + ((A - c[4])^2 + c[5]^2)^2) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential at constant pressure and temperature"; + end ddW_dA_dA; + + redeclare final function extends ddW_dA_dT + "Dubinin-Lorentzian-Cumulative: Second-order partial derivative of filled pore volume w.r.t. adsorption potential and temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + Real ddW_dA_dA = -(2 * c[3] * (A - c[4])) / (Modelica.Constants.pi * + c[5]^3 * ((A - c[4])^2 / c[5]^2 + 1)^2) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential"; + Real ddW_dA_dc3 = 1 / (Modelica.Constants.pi * ((A - c[4])^2 / c[5]^2 + 1) * + c[5]) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and third coefficient of the Dubinin-Lorentzian-Cumulative + isotherm model"; + Real ddW_dA_dc4 = (2 * c[3] * (A - c[4])) / (Modelica.Constants.pi * c[5]^3 * + ((A - c[4])^2 / c[5]^2 + 1)^2) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and fourth coefficient of the Dubinin-Lorentzian-Cumulative + isotherm model"; + Real ddW_dA_dc5 = -(c[3] * (c[5]^2 - c[4]^2 + 2 * A * c[4] - A^2)) / + (Modelica.Constants.pi * (c[5]^2 + c[4]^2 - 2 * A * c[4] + A^2)^2) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and fivth coefficient of the Dubinin-Lorentzian-Cumulative + isotherm model"; + + algorithm + ddW_dA_dT := ddW_dA_dA * dA_dT_adsorpt + + ddW_dA_dc3 * dc_dT_adsorpt[3] + + ddW_dA_dc4 * dc_dT_adsorpt[4] + + ddW_dA_dc5 * dc_dT_adsorpt[5] + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and temperature at constant pressure"; + end ddW_dA_dT; + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Dubinin-Lorentzian-Cumulative isotherm model is a six-parameter model for +calculating the equilibrium uptake <i>x_adsorpt</i> as a function of the +equilibrium pressure <i>p_adsorpt</i>. The Dubinin-Lorentzian-Cumulative +isotherm model is suitable for type IV and V isotherms according to the IUPAC +definition. +</p> + +<h4>Main equations</h4> +<p> +The Dubinin-Lorentzian-Cumulative isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) * W(A(T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + W(A(T<sub>adsorpt</sub>)) = a/π *(<strong>arctan</strong>((A - b) / c) + π/2) + d; +</pre> +<pre> + A(T<sub>adsorpt</sub>) = R * T<sub>adsorpt</sub> * <strong>ln</strong>(p<sub>sat</sub>(T<sub>adsorpt</sub>) / p<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>W(A(T<sub>adsorpt</sub>))</i> is the so-called characteristic curve and +<i>A(T<sub>adsorpt</sub>)</i> is the adsorption potential. Within the characteristic +curve, the parameters <i>a</i>, <i>b</i>, <i>c</i>, and <i>d</i> are fitting parameters. +<br/><br/> +Note that the density of the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> +is assumed to be the saturated liquid density ρ<sub>sat,liq</sub>(T<sub>adsorpt</sub>) +without any further information about the system under consideration. For super-critical +adsorptives (i.e., <i>T<sub>adsorpt</sub> ≥ T<sub>crit</sub></i>), the density of +the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> can be estimated by +</p> +<pre> + ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) = ρ<sub>sat,liq</sub>(T<sub>boiling,0</sub>) * <strong>exp</strong>(-0.0025 * (T<sub>adsorpt</sub> - T<sub>boiling,0</sub>)); +</pre> +<p> +and a pseudo-vapour pressure <i>p<sub>sat</sub>(T<sub>adsorpt</sub>)</i> can be calculated by +</p> +<pre> + p<sub>sat</sub>(T<sub>adsorpt</sub>) = p<sub>crit</sub>(T<sub>adsorpt</sub>) * (T<sub>adsorpt</sub> / T<sub>crit</sub>) ^ k; +</pre> +<p> +where <i>T<sub>boiling,0</sub></i> is the normal boiling point at 1 atm and <i>k</i> is +a fitting parameter specific to the system under consideration. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = p<sub>sat</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2] = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) in kg/m<sup>3</sup> + </li> + <li> + c[3] = a in m<sup>3</sup>/kg + </li> + <li> + c[4] = b in J/mol + </li> + <li> + c[5] = c in J/mol + </li> + <li> + c[6] = d in m<sup>3</sup>/kg + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The characteristic curve <i>W(A)</i> must decrease strictly monotonically with + increasing adsorption potential <i>A</i>. Otherwise, the inverses <i>A(W)</i> + and <i>p(x,T</i>) may not be solveable. + </li> + <li> + The reduced spreading pressure <i>π</i> may not be calculable. Accordingly, the + inverse <i>p(π,T)</i> cannot be calculated either. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The isotherm model is used for type IV and V isotherms according to the IUPAC +definition. +</p> + +<h4>Example</h4> +<p> +The following figure shows the Dubinin-Lorentzian-Cumulativ isotherm model for different +parameter sets. In the upper sub-figure, the equilibrium pressure changes with +time, while the equilibrium temperature is constant. In the centered sub-figure, the +equilibrium temperature changes with time, while the equilibrium pressure is constant. +In the lower sub-figure, the characteristic curve is shown. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_lorentzian_cumulativ.png\" alt=\"media_functions_equilibria_pure_dubinin_lorentzian_cumulativ.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> + <li> + Schawe, D. (1999). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD Thesis, Stuttgart. + </li> +</ul> +</html>")); +end DubininLorentzianCumulative; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininLorentzianCumulative/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininLorentzianCumulative/package.order new file mode 100644 index 0000000000000000000000000000000000000000..44a21b8e54c5e42bc784fb6013efc1fbbf99d434 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininLorentzianCumulative/package.order @@ -0,0 +1,12 @@ +x_pT +p_xT +dx_dT +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT +W_A +A_W +dW_dA +ddW_dA_dA +ddW_dA_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininPearsonIV/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininPearsonIV/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d37d8bf9372d17ab4710b9dfddfe98e4879d97f1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininPearsonIV/package.mo @@ -0,0 +1,1170 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package DubininPearsonIV "Package containing all functions regarding the Dubinin isotherm model using a 'Pearson IV' equation type" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponentsDubinin; + + redeclare final function extends x_pT + "Dubinin-Pearson-IV isotherm model: Uptake as function of pressure and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Dubinin-Pearson-IV isotherm model: Pressure as function of uptake and temperature" + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dT + "Dubinin-Pearson-IV isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + SorpLib.Units.FilledPoreVolume W= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.W_A( + A=A, c=c) + "Filled pore volume"; + + Real n = (A - c[6]/2 * c[8]/c[7] - c[5]) / c[6] + "Auxiliary variable"; + Real dn_dA = 1 / c[6] + "Partial derivative of the auxiliary variable w.r.t. adsorption potential"; + Real dn_dc5 = -1 / c[6] + "Derivative of auxiliary variable w.r.t. fifth coefficient of + Dubinin-Pearson-IV isotherm"; + Real dn_dc6 = (c[5] - A) / c[6]^2 + "Derivative of auxiliary variable w.r.t. sixth coefficient of + Dubinin-Pearson-IV isotherm"; + Real dn_dc7 = c[8] / (2*c[7]^2) + "Derivative of auxiliary variable w.r.t. seventh coefficient of + Dubinin-Pearson-IV isotherm"; + Real dn_dc8 = -1 / (2*c[7]) + "Derivative of auxiliary variable w.r.t. eigth coefficient of + Dubinin-Pearson-IV isotherm"; + + Real dW_dn = -c[4] * (1 + c[8]^2 / 4 / c[7]^2) ^ c[7] * + (2*c[7] * n + c[8]) * (n^2 + 1) ^ (-c[7] - 1) * + exp(-c[8] * (Modelica.Math.atan(n) + Modelica.Math.atan(c[8] / (2 * c[7])))) + "Partial derivative of the equilibrium uptake w.r.t. auxiliary variable"; + + Real dx_adsorpt_dA = c[2] * dW_dn * dn_dA + "Derivative of uptake w.r.t. to adsorption potential"; + Real dx_adsorpt_dc2 = W + "Derivative of uptake w.r.t. to second coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc3 = c[2] + "Derivative of uptake w.r.t. to third coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc4 = c[2] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + exp(-c[8] * (Modelica.Math.atan(n) + Modelica.Math.atan(c[8] / (2 * c[7])))) / + (n^2 + 1)^c[7] + "Derivative of uptake w.r.t. to fourth coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc5 = c[2] * dW_dn*dn_dc5 + "Derivative of uptake w.r.t. to fivth coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc6 = c[2] * dW_dn*dn_dc6 + "Derivative of uptake w.r.t. to sixth coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc7 = c[2] * ((c[4] * (log(c[8]^2 / (4 * c[7]^2) + 1) - + log(n^2 + 1)) * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + exp(-c[8] * (Modelica.Math.atan(c[8] / (2 * c[7])) + + Modelica.Math.atan(n)))) / (n^2 + 1)^c[7] + + dW_dn*dn_dc7) + "Derivative of uptake w.r.t. to seventh coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc8 = c[2] * (-(c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + exp(-c[8] * (Modelica.Math.atan(c[8] / (2 * c[7])) + Modelica.Math.atan(n))) * + (Modelica.Math.atan(c[8] / (2 * c[7])) + Modelica.Math.atan(n))) / + (n^2 + 1)^c[7] + + dW_dn*dn_dc8) + "Derivative of uptake w.r.t. to eigth coefficient of Dubinin-Pearson-IV + isotherm"; + + algorithm + dx_adsorpt_dT_adsorpt := + dx_adsorpt_dA*dA_dT_adsorpt + + dx_adsorpt_dc2*dc_dT_adsorpt[2] + + dx_adsorpt_dc3*dc_dT_adsorpt[3] + + dx_adsorpt_dc4*dc_dT_adsorpt[4] + + dx_adsorpt_dc5*dc_dT_adsorpt[5] + + dx_adsorpt_dc6*dc_dT_adsorpt[6] + + dx_adsorpt_dc7*dc_dT_adsorpt[7] + + dx_adsorpt_dc8*dc_dT_adsorpt[8] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dT_dT + "Dubinin-Pearson-IV isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperatureTemperature ddA_dT_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dT_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1], + ddp_sat_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt[1]) + "Second-order partial derivative of adsorption potential w.r.t. equilibrium + temperature at constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of characteristic curve w.r.t. adsorption + potential and temperature at constant pressure"; + + Real dx_adsorpt_dA = c[2] * dW_dA + "Derivative of uptake w.r.t. to adsorption potential"; + Real dx_adsorpt_dc2 = (c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7]))))) / ((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1)^c[7] + c[3] + "Derivative of uptake w.r.t. to second coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc3 = c[2] + "Derivative of uptake w.r.t. to third coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc4 = (c[2] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7]))))) / ((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1)^c[7] + "Derivative of uptake w.r.t. to fourth coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc5 = -(8 * c[2] * c[4] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * (c[5] - A) * exp(-c[8] * (Modelica.Math.atan((-c[5] - (c[6] * + c[8]) / (2 * c[7]) + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + (((-c[5] - (c[6] * c[8]) / (2 * c[7]) + A)^2 / c[6]^2 + 1)^c[7] * (4 * + c[7]^2 * c[5]^2 + (4 * c[6] * c[7] * c[8] - 8 * A * c[7]^2) * c[5] + + c[6]^2 * c[8]^2 - 4 * A * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * A^2) * + c[7]^2)) + "Derivative of uptake w.r.t. to fivth coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc6 = (8 * c[2] * c[4] * (c[5] - A)^2 * c[7]^3 * (c[8]^2 / + (4 * c[7]^2) + 1)^c[7] * exp(-c[8] * (Modelica.Math.atan((-(c[8] * c[6]) / + (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + (c[6] * ((c[8]^2 + 4 * c[7]^2) * c[6]^2 + (4 * c[5] - 4 * A) * c[7] * + c[8] * c[6] + (4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * ((-(c[8] * + c[6]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) + "Derivative of uptake w.r.t. to sixth coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc7 = (c[2] * c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + (((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * log(c[8]^2 / (4 * + c[7]^2) + 1) + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * c[5] - 4 * A^2) * + log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * c[7]^2 + + ((4 * c[5] - 4 * A) * c[6] * c[8] * log(c[8]^2 / (4 * c[7]^2) + 1) + (4 * + A - 4 * c[5]) * c[6] * c[8] * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A)^2 / c[6]^2 + 1) + (4 * c[5] - 4 * A) * c[6] * c[8]) * c[7] + c[6]^2 * + c[8]^2 * log(c[8]^2 / (4 * c[7]^2) + 1) - c[6]^2 * c[8]^2 * log((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7]))))) / (((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1)^c[7] * ((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + + 4 * A^2) * c[7]^2 + (4 * c[5] - 4 * A) * c[6] * c[8] * c[7] + c[6]^2 * + c[8]^2)) + "Derivative of uptake w.r.t. to seventh coefficient of Dubinin-Pearson-IV + isotherm"; + Real dx_adsorpt_dc8 = -(c[2] * c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + exp(-c[8] * (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / + c[6]) + Modelica.Math.atan(c[8] / (2 * c[7])))) * ((c[6]^2 * c[8]^2 + (4 * + c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * + c[5] + 4 * A^2) * c[7]^2) * Modelica.Math.atan((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A) / c[6]) + (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * + c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * + Modelica.Math.atan(c[8] / (2 * c[7])) + (4 * c[5] - 4 * A) * c[6] * + c[7]^2)) / ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * ((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) + "Derivative of uptake w.r.t. to eigth coefficient of Dubinin-Pearson-IV + isotherm"; + + Real ddx_adsorpt_dc5_dc5 = (8 * c[2] * c[4] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * ((8 * c[7]^3 + 4 * c[7]^2) * c[5]^2 + (-16 * A * c[7]^3 - 8 * A * + c[7]^2) * c[5] - c[6]^2 * c[8]^2 + 8 * A^2 * c[7]^3 + (4 * A^2 - 4 * c[6]^2) * + c[7]^2) * exp(-c[8] * (Modelica.Math.atan((-c[5] - (c[6] * c[8]) / (2 * c[7]) + + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / (((-c[5] - (c[6] * + c[8]) / (2 * c[7]) + A)^2 / c[6]^2 + 1)^c[7] * (4 * c[7]^2 * c[5]^2 + (4 * + c[6] * c[7] * c[8] - 8 * A * c[7]^2) * c[5] + c[6]^2 * c[8]^2 - 4 * A * c[6] * + c[7] * c[8] + (4 * c[6]^2 + 4 * A^2) * c[7]^2)^2) + "Second-order partial derivative of uptake w.r.t. to fivth coefficient of + Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc6_dc6 = -(8 * c[2] * c[4] * (c[5] - A)^2 * c[7]^3 * + (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * ((3 * c[8]^2 + 12 * c[7]^2) * c[6]^2 + + (8 * c[5] - 8 * A) * c[7] * c[8] * c[6] + (-8 * c[5]^2 + 16 * A * c[5] - 8 * + A^2) * c[7]^3 + (4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * exp(-c[8] * + (Modelica.Math.atan((-(c[8] * c[6]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7]))))) / (c[6]^2 * ((c[8]^2 + 4 * c[7]^2) * + c[6]^2 + (4 * c[5] - 4 * A) * c[7] * c[8] * c[6] + (4 * c[5]^2 - 8 * A * + c[5] + 4 * A^2) * c[7]^2)^2 * ((-(c[8] * c[6]) / (2 * c[7]) - c[5] + A)^2 / + c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to sixth coefficient of + Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc7_dc7 = ((c[2] * c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + ((((-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * c[5] - 4 * A^2) * c[8] * (-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)) / (c[6] * ((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1) * c[7]^2) - ((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * + c[5] + 4 * A^2) * c[8]^2) / (2 * (c[8]^2 / (4 * c[7]^2) + 1) * c[7]^3)) * + c[7]^2 + (((4 * A - 4 * c[5]) * c[8]^2 * (-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)) / (((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) * + c[7]^2) - ((4 * c[5] - 4 * A) * c[6] * c[8]^3) / (2 * (c[8]^2 / (4 * c[7]^2) + + 1) * c[7]^3)) * c[7] + 2 * ((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * + A^2) * log(c[8]^2 / (4 * c[7]^2) + 1) + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * + c[5] - 4 * A^2) * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + + 1)) * c[7] - (c[6] * c[8]^3 * (-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)) / + (((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) * c[7]^2) - + (c[6]^2 * c[8]^4) / (2 * (c[8]^2 / (4 * c[7]^2) + 1) * c[7]^3) + (4 * c[5] - + 4 * A) * c[6] * c[8] * log(c[8]^2 / (4 * c[7]^2) + 1) + (4 * A - 4 * c[5]) * + c[6] * c[8] * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) + + (4 * c[5] - 4 * A) * c[6] * c[8]) * exp(-c[8] * (Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * + c[7])))) + c[2] * c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * (log(c[8]^2 / + (4 * c[7]^2) + 1) - c[8]^2 / (2 * (c[8]^2 / (4 * c[7]^2) + 1) * c[7]^2)) * + (((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * log(c[8]^2 / (4 * + c[7]^2) + 1) + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * c[5] - 4 * A^2) * + log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * c[7]^2 + + ((4 * c[5] - 4 * A) * c[6] * c[8] * log(c[8]^2 / (4 * c[7]^2) + 1) + (4 * + A - 4 * c[5]) * c[6] * c[8] * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A)^2 / c[6]^2 + 1) + (4 * c[5] - 4 * A) * c[6] * c[8]) * c[7] + c[6]^2 * + c[8]^2 * log(c[8]^2 / (4 * c[7]^2) + 1) - c[6]^2 * c[8]^2 * log((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7])))) - c[2] * c[4] * c[8] * (c[8]^2 / + (4 * c[7]^2) + 1)^c[7] * (c[8] / (2 * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A)^2 / c[6]^2 + 1) * c[7]^2) - c[8] / (2 * (c[8]^2 / (4 * c[7]^2) + 1) * + c[7]^2)) * (((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * log(c[8]^2 / + (4 * c[7]^2) + 1) + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * c[5] - 4 * A^2) * + log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * c[7]^2 + + ((4 * c[5] - 4 * A) * c[6] * c[8] * log(c[8]^2 / (4 * c[7]^2) + 1) + (4 * + A - 4 * c[5]) * c[6] * c[8] * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / + c[6]^2 + 1) + (4 * c[5] - 4 * A) * c[6] * c[8]) * c[7] + c[6]^2 * c[8]^2 * + log(c[8]^2 / (4 * c[7]^2) + 1) - c[6]^2 * c[8]^2 * log((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * exp(-c[8] * (Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * + c[7]))))) * (((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7] * + ((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2 + (4 * c[5] - 4 * + A) * c[6] * c[8] * c[7] + c[6]^2 * c[8]^2)) - (c[2] * c[4] * (c[8]^2 / (4 * + c[7]^2) + 1)^c[7] * (((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * + log(c[8]^2 / (4 * c[7]^2) + 1) + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * c[5] - + 4 * A^2) * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * + c[7]^2 + ((4 * c[5] - 4 * A) * c[6] * c[8] * log(c[8]^2 / (4 * c[7]^2) + 1) + + (4 * A - 4 * c[5]) * c[6] * c[8] * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A)^2 / c[6]^2 + 1) + (4 * c[5] - 4 * A) * c[6] * c[8]) * c[7] + c[6]^2 * + c[8]^2 * log(c[8]^2 / (4 * c[7]^2) + 1) - c[6]^2 * c[8]^2 * log((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7]))))) * (((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1)^c[7] * ((c[8] * (-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)) / (c[6] * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + + 1) * c[7]) + log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * + ((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2 + (4 * c[5] - + 4 * A) * c[6] * c[8] * c[7] + c[6]^2 * c[8]^2) + ((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7] * (2 * (4 * c[6]^2 + 4 * c[5]^2 - 8 * + A * c[5] + 4 * A^2) * c[7] + (4 * c[5] - 4 * A) * c[6] * c[8]))) / (((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7] * ((4 * c[6]^2 + 4 * c[5]^2 - + 8 * A * c[5] + 4 * A^2) * c[7]^2 + (4 * c[5] - 4 * A) * c[6] * c[8] * c[7] + + c[6]^2 * c[8]^2))^2 + "Second-order partial derivative of uptake w.r.t. to seventh coefficient of + Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc8_dc8 = -(c[2] * c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + exp(-c[8] * (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / + c[6]) + Modelica.Math.atan(c[8] / (2 * c[7])))) * (-Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) - Modelica.Math.atan(c[8] / (2 * c[7])) - + c[8] * (1 / (2 * c[7] * (c[8]^2 / (4 * c[7]^2) + 1)) - 1 / (2 * c[7] * ((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)))) * ((c[6]^2 * c[8]^2 + (4 * + c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * + c[5] + 4 * A^2) * c[7]^2) * Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A) / c[6]) + (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * + c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * + Modelica.Math.atan(c[8] / (2 * c[7])) + (4 * c[5] - 4 * A) * c[6] * c[7]^2)) / + ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * ((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1)^c[7]) + (c[2] * c[4] * (2 * c[6]^2 * c[8] + (4 * + c[5] - 4 * A) * c[6] * c[7]) * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7])))) * ((c[6]^2 * c[8]^2 + (4 * c[5] - + 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * + A^2) * c[7]^2) * Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A) / c[6]) + (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * + Modelica.Math.atan(c[8] / (2 * c[7])) + (4 * c[5] - 4 * A) * c[6] * c[7]^2)) / + ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2)^2 * ((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) - (c[2] * c[4] * c[8] * (c[8]^2 / + (4 * c[7]^2) + 1)^(c[7] - 1) * exp(-c[8] * (Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * + c[7])))) * ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * + Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * Modelica.Math.atan(c[8] / + (2 * c[7])) + (4 * c[5] - 4 * A) * c[6] * c[7]^2)) / (2 * c[7] * (c[6]^2 * + c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - + 8 * A * c[5] + 4 * A^2) * c[7]^2) * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A)^2 / c[6]^2 + 1)^c[7]) - (c[2] * c[4] * (-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A) * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A)^2 / c[6]^2 + 1)^(-c[7] - 1) * exp(-c[8] * (Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * + c[7])))) * ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * + c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * + Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + (c[6]^2 * + c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - + 8 * A * c[5] + 4 * A^2) * c[7]^2) * Modelica.Math.atan(c[8] / (2 * c[7])) + + (4 * c[5] - 4 * A) * c[6] * c[7]^2)) / (c[6] * (c[6]^2 * c[8]^2 + (4 * c[5] - + 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * + A^2) * c[7]^2)) - (c[2] * c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7])))) * ((2 * c[6]^2 * c[8] + (4 * c[5] - + 4 * A) * c[6] * c[7]) * Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A) / c[6]) + (2 * c[6]^2 * c[8] + (4 * c[5] - 4 * A) * c[6] * c[7]) * + Modelica.Math.atan(c[8] / (2 * c[7])) - (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * + A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * + c[7]^2) / (2 * c[7] * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + + 1)) + (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * + c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) / (2 * c[7] * + (c[8]^2 / (4 * c[7]^2) + 1)))) / ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * + c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * + c[7]^2) * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to eigth coefficient of + Dubinin-Pearson-IV isotherm"; + + Real ddx_adsorpt_dc2_dA= -(8 * c[4] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * (A - c[5]) * exp(-c[8] * (Modelica.Math.atan((A - (c[6] * c[8]) / + (2 * c[7]) - c[5]) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / ((4 * + c[7]^2 * A^2 + (-4 * c[6] * c[7] * c[8] - 8 * c[5] * c[7]^2) * A + c[6]^2 * + c[8]^2 + 4 * c[5] * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2) * c[7]^2) * + ((A - (c[6] * c[8]) / (2 * c[7]) - c[5])^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Dubinin-Pearson-IV isotherm and adsorption potential"; + Real ddx_adsorpt_dc2_dc3 = 1 + "Second-order partial derivative of uptake w.r.t. to second and third + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc2_dc4 = ((c[8]^2 / (4 * c[7]^2) + 1)^c[7] * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7]))))) / ((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1)^c[7] + "Second-order partial derivative of uptake w.r.t. to second and fourht + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc2_dc5 = -(8 * c[4] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * (c[5] - A) * exp(-c[8] * (Modelica.Math.atan((-c[5] - (c[6] * + c[8]) / (2 * c[7]) + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + (((-c[5] - (c[6] * c[8]) / (2 * c[7]) + A)^2 / c[6]^2 + 1)^c[7] * (4 * c[7]^2 * + c[5]^2 + (4 * c[6] * c[7] * c[8] - 8 * A * c[7]^2) * c[5] + c[6]^2 * c[8]^2 - + 4 * A * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * A^2) * c[7]^2)) + "Second-order partial derivative of uptake w.r.t. to second and fivth + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc2_dc6 = (8 * c[4] * (c[5] - A)^2 * c[7]^3 * (c[8]^2 / (4 * + c[7]^2) + 1)^c[7] * exp(-c[8] * (Modelica.Math.atan((-(c[8] * c[6]) / (2 * + c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + (c[6] * ((c[8]^2 + 4 * c[7]^2) * c[6]^2 + (4 * c[5] - 4 * A) * c[7] * c[8] * + c[6] + (4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * ((-(c[8] * c[6]) / + (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to second and sixth + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc2_dc7 = (c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * (((4 * + c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * log(c[8]^2 / (4 * c[7]^2) + + 1) + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * c[5] - 4 * A^2) * log((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * c[7]^2 + ((4 * c[5] - 4 * + A) * c[6] * c[8] * log(c[8]^2 / (4 * c[7]^2) + 1) + (4 * A - 4 * c[5]) * + c[6] * c[8] * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) + + (4 * c[5] - 4 * A) * c[6] * c[8]) * c[7] + c[6]^2 * c[8]^2 * log(c[8]^2 / + (4 * c[7]^2) + 1) - c[6]^2 * c[8]^2 * log((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1)) * exp(-c[8] * (Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * + c[7]))))) / (((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7] * + ((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2 + (4 * c[5] - + 4 * A) * c[6] * c[8] * c[7] + c[6]^2 * c[8]^2)) + "Second-order partial derivative of uptake w.r.t. to second and seventh + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc2_dc8 = -(c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + exp(-c[8] * (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / + c[6]) + Modelica.Math.atan(c[8] / (2 * c[7])))) * ((c[6]^2 * c[8]^2 + (4 * + c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * + c[5] + 4 * A^2) * c[7]^2) * Modelica.Math.atan((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A) / c[6]) + (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * + c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * + Modelica.Math.atan(c[8] / (2 * c[7])) + (4 * c[5] - 4 * A) * c[6] * c[7]^2)) / + ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * ((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to second and eigth + coefficient of Dubinin-Pearson-IV isotherm"; + + Real ddx_adsorpt_dc4_dA = -(8 * c[2] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * (A - c[5]) * exp(-c[8] * (Modelica.Math.atan((A - (c[6] * c[8]) / + (2 * c[7]) - c[5]) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + ((4 * c[7]^2 * A^2 + (-4 * c[6] * c[7] * c[8] - 8 * c[5] * c[7]^2) * A + + c[6]^2 * c[8]^2 + 4 * c[5] * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * + c[5]^2) * c[7]^2) * ((A - (c[6] * c[8]) / (2 * c[7]) - c[5])^2 / c[6]^2 + + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to fourth coefficient of + Dubinin-Pearson-IV isotherm and adsorption potential"; + Real ddx_adsorpt_dc4_dc5 = -(8 * c[2] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * (c[5] - A) * exp(-c[8] * (Modelica.Math.atan((-c[5] - (c[6] * + c[8]) / (2 * c[7]) + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + (((-c[5] - (c[6] * c[8]) / (2 * c[7]) + A)^2 / c[6]^2 + 1)^c[7] * (4 * + c[7]^2 * c[5]^2 + (4 * c[6] * c[7] * c[8] - 8 * A * c[7]^2) * c[5] + + c[6]^2 * c[8]^2 - 4 * A * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * A^2) * + c[7]^2)) + "Second-order partial derivative of uptake w.r.t. to fourth and fivth + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc4_dc6 = (8 * c[2] * (c[5] - A)^2 * c[7]^3 * (c[8]^2 / (4 * + c[7]^2) + 1)^c[7] * exp(-c[8] * (Modelica.Math.atan((-(c[8] * c[6]) / (2 * + c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + (c[6] * ((c[8]^2 + 4 * c[7]^2) * c[6]^2 + (4 * c[5] - 4 * A) * c[7] * c[8] * + c[6] + (4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * ((-(c[8] * c[6]) / + (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to fourth and sixth + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc4_dc7 = (c[2] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * (((4 * + c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * log(c[8]^2 / (4 * c[7]^2) + + 1) + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * c[5] - 4 * A^2) * log((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)) * c[7]^2 + ((4 * c[5] - 4 * + A) * c[6] * c[8] * log(c[8]^2 / (4 * c[7]^2) + 1) + (4 * A - 4 * c[5]) * + c[6] * c[8] * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) + + (4 * c[5] - 4 * A) * c[6] * c[8]) * c[7] + c[6]^2 * c[8]^2 * log(c[8]^2 / + (4 * c[7]^2) + 1) - c[6]^2 * c[8]^2 * log((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1)) * exp(-c[8] * (Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * + c[7]))))) / (((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7] * + ((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2 + (4 * c[5] - + 4 * A) * c[6] * c[8] * c[7] + c[6]^2 * c[8]^2)) + "Second-order partial derivative of uptake w.r.t. to fourth and seventh + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc4_dc8 = -(c[2] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7])))) * ((c[6]^2 * c[8]^2 + (4 * c[5] - + 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * + A^2) * c[7]^2) * Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A) / c[6]) + (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * + Modelica.Math.atan(c[8] / (2 * c[7])) + (4 * c[5] - 4 * A) * c[6] * + c[7]^2)) / ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * ((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to fourth and eigth + coefficient of Dubinin-Pearson-IV isotherm"; + + Real ddx_adsorpt_dc5_dA = -(8 * c[2] * c[4] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * ((8 * c[7]^3 + 4 * c[7]^2) * A^2 + (-16 * c[5] * c[7]^3 - 8 * + c[5] * c[7]^2) * A - c[6]^2 * c[8]^2 + 8 * c[5]^2 * c[7]^3 + (4 * c[5]^2 - + 4 * c[6]^2) * c[7]^2) * exp(-c[8] * (Modelica.Math.atan((A - (c[6] * c[8]) / + (2 * c[7]) - c[5]) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + ((4 * c[7]^2 * A^2 + (-4 * c[6] * c[7] * c[8] - 8 * c[5] * c[7]^2) * A + + c[6]^2 * c[8]^2 + 4 * c[5] * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2) * + c[7]^2)^2 * ((A - (c[6] * c[8]) / (2 * c[7]) - c[5])^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to fivth coefficient of + Dubinin-Pearson-IV isotherm and adsorption potential"; + Real ddx_adsorpt_dc5_dc6 = (16 * c[2] * c[4] * (c[5] - A) * c[7]^3 * (c[8]^2 / + (4 * c[7]^2) + 1)^c[7] * ((c[8]^2 + 4 * c[7]^2) * c[6]^2 + (2 * c[5] - 2 * + A) * c[7] * c[8] * c[6] + (-4 * c[5]^2 + 8 * A * c[5] - 4 * A^2) * c[7]^3) * + exp(-c[8] * (Modelica.Math.atan((-(c[8] * c[6]) / (2 * c[7]) - c[5] + A) / + c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / (c[6] * ((c[8]^2 + 4 * + c[7]^2) * c[6]^2 + (4 * c[5] - 4 * A) * c[7] * c[8] * c[6] + (4 * c[5]^2 - + 8 * A * c[5] + 4 * A^2) * c[7]^2)^2 * ((-(c[8] * c[6]) / (2 * c[7]) - c[5] + + A)^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to fivth and sixth + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc5_dc7 = -(8 * c[2] * c[4] * (c[5] - A) * (c[8]^2 / (4 * + c[7]^2) + 1)^c[7] * c[7]^2 * (((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * + A^2) * log(c[8]^2 / (4 * c[7]^2) + 1) + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * + c[5] - 4 * A^2) * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + + 1)) * c[7]^3 + ((4 * c[5] - 4 * A) * c[6] * c[8] * log(c[8]^2 / (4 * c[7]^2) + + 1) + (4 * A - 4 * c[5]) * c[6] * c[8] * log((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1) + (4 * c[5] - 4 * A) * c[6] * c[8] + 4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2 + (c[6]^2 * c[8]^2 * log(c[8]^2 / + (4 * c[7]^2) + 1) - c[6]^2 * c[8]^2 * log((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1) + (8 * c[5] - 8 * A) * c[6] * c[8]) * c[7] + 3 * + c[6]^2 * c[8]^2) * exp(-c[8] * (Modelica.Math.atan((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + (((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7] * ((4 * + c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2 + (4 * c[5] - 4 * A) * + c[6] * c[8] * c[7] + c[6]^2 * c[8]^2)^2) + "Second-order partial derivative of uptake w.r.t. to fivth and seventh + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc5_dc8 = (8 * c[2] * c[4] * (c[5] - A) * c[7]^3 * (c[8]^2 / + (4 * c[7]^2) + 1)^c[7] * exp(-c[8] * (Modelica.Math.atan((-(c[6] * c[8]) / + (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7])))) * + ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * + A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * + c[7]^2) * Modelica.Math.atan(c[8] / (2 * c[7])) + 2 * c[6]^2 * c[8] + (4 * + c[5] - 4 * A) * c[6] * c[7]^2 + (4 * c[5] - 4 * A) * c[6] * c[7])) / + ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2)^2 * ((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to fivth and eigth + coefficient of Dubinin-Pearson-IV isotherm"; + + Real ddx_adsorpt_dc6_dA = -(16 * c[2] * c[4] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * (A - c[5]) * (4 * c[7]^3 * A^2 + (2 * c[6] * c[7] * c[8] - 8 * + c[5] * c[7]^3) * A - c[6]^2 * c[8]^2 - 2 * c[5] * c[6] * c[7] * c[8] + 4 * + c[5]^2 * c[7]^3 - 4 * c[6]^2 * c[7]^2) * exp(-c[8] * (Modelica.Math.atan((A - + (c[6] * c[8]) / (2 * c[7]) - c[5]) / c[6]) + Modelica.Math.atan(c[8] / (2 * + c[7]))))) / (c[6] * (4 * c[7]^2 * A^2 + (-4 * c[6] * c[7] * c[8] - 8 * c[5] * + c[7]^2) * A + c[6]^2 * c[8]^2 + 4 * c[5] * c[6] * c[7] * c[8] + (4 * c[6]^2 + + 4 * c[5]^2) * c[7]^2)^2 * ((A - (c[6] * c[8]) / (2 * c[7]) - c[5])^2 / + c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to sixth coefficient of + Dubinin-Pearson-IV isotherm and adsorption potential"; + Real ddx_adsorpt_dc6_dc7 = (8 * c[2] * c[4] * (c[5] - A)^2 * (c[8]^2 / (4 * + c[7]^2) + 1)^c[7] * c[7]^2 * (((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * + A^2) * log(c[8]^2 / (4 * c[7]^2) + 1) + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * + c[5] - 4 * A^2) * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + + 1)) * c[7]^3 + ((4 * c[5] - 4 * A) * c[6] * c[8] * log(c[8]^2 / (4 * c[7]^2) + + 1) + (4 * A - 4 * c[5]) * c[6] * c[8] * log((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1) + (4 * c[5] - 4 * A) * c[6] * c[8] + 4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2 + (c[6]^2 * c[8]^2 * log(c[8]^2 / + (4 * c[7]^2) + 1) - c[6]^2 * c[8]^2 * log((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1) + (8 * c[5] - 8 * A) * c[6] * c[8]) * c[7] + 3 * + c[6]^2 * c[8]^2) * exp(-c[8] * (Modelica.Math.atan((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / (c[6] * + ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7] * ((4 * + c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2 + (4 * c[5] - 4 * A) * + c[6] * c[8] * c[7] + c[6]^2 * c[8]^2)^2) + "Second-order partial derivative of uptake w.r.t. to sixth and seventh + coefficient of Dubinin-Pearson-IV isotherm"; + Real ddx_adsorpt_dc6_dc8 = -(8 * c[2] * c[4] * (c[5] - A)^2 * c[7]^3 * + (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * exp(-c[8] * (Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * + c[7])))) * ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * + Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * Modelica.Math.atan(c[8] / + (2 * c[7])) + 2 * c[6]^2 * c[8] + (4 * c[5] - 4 * A) * c[6] * c[7]^2 + (4 * + c[5] - 4 * A) * c[6] * c[7])) / (c[6] * (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * + A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * + A^2) * c[7]^2)^2 * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to sixth and eigth + coefficient of Dubinin-Pearson-IV isotherm"; + + Real ddx_adsorpt_dc7_dA = (8 * c[2] * c[4] * c[7]^2 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * (A - c[5]) * exp(-c[8] * (Modelica.Math.atan((A - (c[6] * c[8]) / + (2 * c[7]) - c[5]) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7])))) * ((4 * + c[7]^3 * A^2 + (-4 * c[6] * c[7]^2 * c[8] - 8 * c[5] * c[7]^3) * A + c[6]^2 * + c[7] * c[8]^2 + 4 * c[5] * c[6] * c[7]^2 * c[8] + (4 * c[6]^2 + 4 * c[5]^2) * + c[7]^3) * log((A - (c[6] * c[8]) / (2 * c[7]) - c[5])^2 / c[6]^2 + 1) + (-4 * + c[7]^3 * log(c[8]^2 / (4 * c[7]^2) + 1) - 4 * c[7]^2) * A^2 + ((4 * c[6] * + c[7]^2 * c[8] + 8 * c[5] * c[7]^3) * log(c[8]^2 / (4 * c[7]^2) + 1) + (4 * + c[6] * c[7]^2 + 8 * c[6] * c[7]) * c[8] + 8 * c[5] * c[7]^2) * A + (-c[6]^2 * + c[7] * c[8]^2 - 4 * c[5] * c[6] * c[7]^2 * c[8] + (-4 * c[6]^2 - 4 * c[5]^2) * + c[7]^3) * log(c[8]^2 / (4 * c[7]^2) + 1) - 3 * c[6]^2 * c[8]^2 + (-4 * c[5] * + c[6] * c[7]^2 - 8 * c[5] * c[6] * c[7]) * c[8] + (-4 * c[6]^2 - 4 * c[5]^2) * + c[7]^2)) / ((4 * c[7]^2 * A^2 + (-4 * c[6] * c[7] * c[8] - 8 * c[5] * c[7]^2) * + A + c[6]^2 * c[8]^2 + 4 * c[5] * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2) * + c[7]^2)^2 * ((A - (c[6] * c[8]) / (2 * c[7]) - c[5])^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to seventh coefficient of + Dubinin-Pearson-IV isotherm and adsorption potential"; + Real ddx_adsorpt_dc7_dc8 = (-c[2] * c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + exp(-c[8] * (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / + c[6]) + Modelica.Math.atan(c[8] / (2 * c[7])))) * + (-Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) - + Modelica.Math.atan(c[8] / (2 * c[7])) - c[8] * (1 / (2 * c[7] * (c[8]^2 / + (4 * c[7]^2) + 1)) - 1 / (2 * c[7] * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A)^2 / c[6]^2 + 1)))) * ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * + c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * + log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) + (-c[6]^2 * + c[8]^2 + (4 * A - 4 * c[5]) * c[6] * c[7] * c[8] + (-4 * c[6]^2 - 4 * + c[5]^2 + 8 * A * c[5] - 4 * A^2) * c[7]^2) * log(c[8]^2 / (4 * c[7]^2) + + 1) + (4 * A - 4 * c[5]) * c[6] * c[7] * c[8]) - c[2] * c[4] * (c[8]^2 / + (4 * c[7]^2) + 1)^c[7] * exp(-c[8] * (Modelica.Math.atan((-(c[6] * c[8]) / + (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7])))) * + ((2 * c[6]^2 * c[8] + (4 * c[5] - 4 * A) * c[6] * c[7]) * log((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) + ((4 * A - 4 * c[5]) * + c[6] * c[7] - 2 * c[6]^2 * c[8]) * log(c[8]^2 / (4 * c[7]^2) + 1) - + ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) * (c[6]^2 * c[8]^2 + (4 * c[5] - + 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + + 4 * A^2) * c[7]^2)) / (c[6] * c[7] * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A)^2 / c[6]^2 + 1)) + (c[8] * (-c[6]^2 * c[8]^2 + (4 * A - 4 * c[5]) * + c[6] * c[7] * c[8] + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * c[5] - 4 * A^2) * + c[7]^2)) / (2 * c[7]^2 * (c[8]^2 / (4 * c[7]^2) + 1)) + (4 * A - 4 * c[5]) * + c[6] * c[7])) / ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * ((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) + (c[2] * c[4] * (2 * + c[6]^2 * c[8] + (4 * c[5] - 4 * A) * c[6] * c[7]) * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * exp(-c[8] * (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7])))) * ((c[6]^2 * + c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - + 8 * A * c[5] + 4 * A^2) * c[7]^2) * log((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1) + (-c[6]^2 * c[8]^2 + (4 * A - 4 * c[5]) * c[6] * + c[7] * c[8] + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * c[5] - 4 * A^2) * c[7]^2) * + log(c[8]^2 / (4 * c[7]^2) + 1) + (4 * A - 4 * c[5]) * c[6] * c[7] * c[8])) / + ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2)^2 * ((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) - (c[2] * c[4] * c[8] * (c[8]^2 / + (4 * c[7]^2) + 1)^(c[7] - 1) * exp(-c[8] * (Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * + c[7])))) * ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * log((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) + (-c[6]^2 * c[8]^2 + (4 * + A - 4 * c[5]) * c[6] * c[7] * c[8] + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * + c[5] - 4 * A^2) * c[7]^2) * log(c[8]^2 / (4 * c[7]^2) + 1) + (4 * A - 4 * + c[5]) * c[6] * c[7] * c[8])) / (2 * c[7] * (c[6]^2 * c[8]^2 + (4 * c[5] - + 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * + A^2) * c[7]^2) * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + + 1)^c[7]) - (c[2] * c[4] * (-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) * + (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * ((-(c[6] * c[8]) / (2 * c[7]) - c[5] + + A)^2 / c[6]^2 + 1)^(-c[7] - 1) * exp(-c[8] * (Modelica.Math.atan((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * + c[7])))) * ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2) * log((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) + (-c[6]^2 * c[8]^2 + (4 * + A - 4 * c[5]) * c[6] * c[7] * c[8] + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * + c[5] - 4 * A^2) * c[7]^2) * log(c[8]^2 / (4 * c[7]^2) + 1) + (4 * A - 4 * + c[5]) * c[6] * c[7] * c[8])) / (c[6] * (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * + A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * + A^2) * c[7]^2)) + "Second-order partial derivative of uptake w.r.t. to seventh and eigth + coefficient of Dubinin-Pearson-IV isotherm"; + + Real ddx_adsorpt_dc8_dA = (8 * c[2] * c[4] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * (A - c[5]) * exp(-c[8] * (Modelica.Math.atan((A - (c[6] * c[8]) / + (2 * c[7]) - c[5]) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7])))) * ((4 * + c[7]^2 * A^2 + (-4 * c[6] * c[7] * c[8] - 8 * c[5] * c[7]^2) * A + c[6]^2 * + c[8]^2 + 4 * c[5] * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2) * c[7]^2) * + Modelica.Math.atan((A - (c[6] * c[8]) / (2 * c[7]) - c[5]) / c[6]) + 4 * + c[7]^2 * Modelica.Math.atan(c[8] / (2 * c[7])) * A^2 + ((-4 * c[6] * c[7] * + c[8] - 8 * c[5] * c[7]^2) * Modelica.Math.atan(c[8] / (2 * c[7])) - 4 * + c[6] * c[7]^2 - 4 * c[6] * c[7]) * A + (c[6]^2 * c[8]^2 + 4 * c[5] * c[6] * + c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2) * c[7]^2) * Modelica.Math.atan(c[8] / + (2 * c[7])) + 2 * c[6]^2 * c[8] + 4 * c[5] * c[6] * c[7]^2 + 4 * c[5] * + c[6] * c[7])) / ((4 * c[7]^2 * A^2 + (-4 * c[6] * c[7] * c[8] - 8 * c[5] * + c[7]^2) * A + c[6]^2 * c[8]^2 + 4 * c[5] * c[6] * c[7] * c[8] + (4 * + c[6]^2 + 4 * c[5]^2) * c[7]^2)^2 * ((A - (c[6] * c[8]) / (2 * c[7]) - + c[5])^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of uptake w.r.t. to eigth coefficient of + Dubinin-Pearson-IV isotherm and adsorption potential"; + + Real ddx_adsorpt_dA_dT_dT_adsorpt = dc_dT_adsorpt[2] * dW_dA + + c[2] * ddW_dA_dT_adsorpt + "Second-order partial derivative of uptake w.r.t. to adsorption potential + and temperature"; + Real ddx_adsorpt_dc2_dT_dT_adsorpt = ddx_adsorpt_dc2_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[3] + + ddx_adsorpt_dc2_dc4*dc_dT_adsorpt[4] + + ddx_adsorpt_dc2_dc5*dc_dT_adsorpt[5] + + ddx_adsorpt_dc2_dc6*dc_dT_adsorpt[6] + + ddx_adsorpt_dc2_dc7*dc_dT_adsorpt[7] + + ddx_adsorpt_dc2_dc8*dc_dT_adsorpt[8] + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Dubinin-Pearson-IV isotherm and temperature"; + Real ddx_adsorpt_dc3_dT_dT_adsorpt = ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[2] + "Second-order partial derivative of uptake w.r.t. to third coefficient of + Dubinin-Pearson-IV isotherm and temperature"; + Real ddx_adsorpt_dc4_dT_dT_adsorpt = ddx_adsorpt_dc4_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc4*dc_dT_adsorpt[2] + + ddx_adsorpt_dc4_dc5*dc_dT_adsorpt[5] + + ddx_adsorpt_dc4_dc6*dc_dT_adsorpt[6] + + ddx_adsorpt_dc4_dc7*dc_dT_adsorpt[7] + + ddx_adsorpt_dc4_dc8*dc_dT_adsorpt[8] + "Second-order partial derivative of uptake w.r.t. to fourth coefficient of + Dubinin-Pearson-IV isotherm and temperature"; + Real ddx_adsorpt_dc5_dT_dT_adsorpt = ddx_adsorpt_dc5_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc5*dc_dT_adsorpt[2] + + ddx_adsorpt_dc4_dc5*dc_dT_adsorpt[4] + + ddx_adsorpt_dc5_dc5*dc_dT_adsorpt[5] + + ddx_adsorpt_dc5_dc6*dc_dT_adsorpt[6] + + ddx_adsorpt_dc5_dc7*dc_dT_adsorpt[7] + + ddx_adsorpt_dc5_dc8*dc_dT_adsorpt[8] + "Second-order partial derivative of uptake w.r.t. to fivth coefficient of + Dubinin-Pearson-IV isotherm and temperature"; + Real ddx_adsorpt_dc6_dT_dT_adsorpt = ddx_adsorpt_dc6_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc6*dc_dT_adsorpt[2] + + ddx_adsorpt_dc4_dc6*dc_dT_adsorpt[4] + + ddx_adsorpt_dc5_dc6*dc_dT_adsorpt[5] + + ddx_adsorpt_dc6_dc6*dc_dT_adsorpt[6] + + ddx_adsorpt_dc6_dc7*dc_dT_adsorpt[7] + + ddx_adsorpt_dc6_dc8*dc_dT_adsorpt[8] + "Second-order partial derivative of uptake w.r.t. to sixth coefficient of + Dubinin-Pearson-IV isotherm and temperature"; + Real ddx_adsorpt_dc7_dT_dT_adsorpt = ddx_adsorpt_dc7_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc7*dc_dT_adsorpt[2] + + ddx_adsorpt_dc4_dc7*dc_dT_adsorpt[4] + + ddx_adsorpt_dc5_dc7*dc_dT_adsorpt[5] + + ddx_adsorpt_dc6_dc7*dc_dT_adsorpt[6] + + ddx_adsorpt_dc7_dc7*dc_dT_adsorpt[7] + + ddx_adsorpt_dc7_dc8*dc_dT_adsorpt[8] + "Second-order partial derivative of uptake w.r.t. to seventh coefficient of + Dubinin-Pearson-IV isotherm and temperature"; + Real ddx_adsorpt_dc8_dT_dT_adsorpt = ddx_adsorpt_dc8_dA*dA_dT_adsorpt + + ddx_adsorpt_dc2_dc8*dc_dT_adsorpt[2] + + ddx_adsorpt_dc4_dc8*dc_dT_adsorpt[4] + + ddx_adsorpt_dc5_dc8*dc_dT_adsorpt[5] + + ddx_adsorpt_dc6_dc8*dc_dT_adsorpt[6] + + ddx_adsorpt_dc7_dc8*dc_dT_adsorpt[7] + + ddx_adsorpt_dc8_dc8*dc_dT_adsorpt[8] + "Second-order partial derivative of uptake w.r.t. to eigth coefficient of + Dubinin-Pearson-IV isotherm and temperature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + (ddx_adsorpt_dA_dT_dT_adsorpt*dA_dT_adsorpt + + dx_adsorpt_dA*ddA_dT_adsorpt_dT_adsorpt) + + (ddx_adsorpt_dc2_dT_dT_adsorpt*dc_dT_adsorpt[2] + + dx_adsorpt_dc2*ddc_dT_adsorpt_dT_adsorpt[2]) + + (ddx_adsorpt_dc3_dT_dT_adsorpt*dc_dT_adsorpt[3] + + dx_adsorpt_dc3*ddc_dT_adsorpt_dT_adsorpt[3]) + + (ddx_adsorpt_dc4_dT_dT_adsorpt*dc_dT_adsorpt[4] + + dx_adsorpt_dc4*ddc_dT_adsorpt_dT_adsorpt[4]) + + (ddx_adsorpt_dc5_dT_dT_adsorpt*dc_dT_adsorpt[5] + + dx_adsorpt_dc5*ddc_dT_adsorpt_dT_adsorpt[5]) + + (ddx_adsorpt_dc6_dT_dT_adsorpt*dc_dT_adsorpt[6] + + dx_adsorpt_dc6*ddc_dT_adsorpt_dT_adsorpt[6]) + + (ddx_adsorpt_dc7_dT_dT_adsorpt*dc_dT_adsorpt[7] + + dx_adsorpt_dc7*ddc_dT_adsorpt_dT_adsorpt[7]) + + (ddx_adsorpt_dc8_dT_dT_adsorpt*dc_dT_adsorpt[8] + + dx_adsorpt_dc8*ddc_dT_adsorpt_dT_adsorpt[8]) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Dubinin-Pearson-IV isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of adsorption potential w.r.t. to pressure at constant + temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressureTemperature ddA_dp_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dp_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Second-order partial derivative of adsorption potential w.r.t. to pressure + and temperature"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.dW_dA( + A=A, c=c) + "Partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of characteristic curve w.r.t. adsorption + potential and temperature at constant pressure"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + dc_dT_adsorpt[2] * dW_dA * dA_dp_adsorpt + + c[2] * ddW_dA_dT_adsorpt * dA_dp_adsorpt + + c[2] * dW_dA * ddA_dp_adsorpt_dT_adsorpt + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare function pi_pT + "Dubinin-Pearson-IV isotherm model: Reduced spreading pressure as function of pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT_num( + integral_pi_lb = 1e-2, + tolerance = 100*Modelica.Constants.eps, + redeclare final function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.x_pT); + end pi_pT; + + redeclare function p_piT + "Dubinin-Pearson-IV isotherm model: Pressure as function of reduced spreading pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT_num( + p_adsorpt_lb_start = 1, + integral_pi_lb = 1e-2, + tolerance_p_adsorpt = 1e-6, + tolerance_pi = 100*Modelica.Constants.eps, + redeclare final function func_pi_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.pi_pT); + end p_piT; + + redeclare final function extends W_A + "Dubinin-Pearson-IV isotherm model: Filled pore volume as function of adsorption potential" + + // + // Definition of variables + // +protected + Real n = (A - c[6]/2 * c[8]/c[7] - c[5]) / c[6] + "Auxiliary variable"; + + algorithm + W := c[3] + (c[4] * (1 + n^2) ^ (-c[7]) * exp(-c[8] * (Modelica.Math.atan(n) + + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + (1 + c[8]^2 / 4 / c[7]^2) ^ (-c[7]) + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(A=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.A_W(W, c, A_lb_start, A_ub_start, tolerance))); + end W_A; + + redeclare function A_W + "Dubinin-Pearson-IV isotherm model: Adsorption potential as function of the filled pore volume (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_A_W_num( + redeclare final function func_W_A = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.W_A); + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(W=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV.W_A(A, c, A_lb_start, A_ub_start, tolerance))); + end A_W; + + redeclare final function extends dW_dA + "Dubinin-Pearson-IV isotherm model: Partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + + // + // Definition of variables + // +protected + Real n = (A - c[6]/2 * c[8]/c[7] - c[5]) / c[6] + "Auxiliary variable"; + + Real dW_dn = -c[4] * (1 + c[8]^2 / 4 / c[7]^2) ^ c[7] * + (2*c[7] * n + c[8]) * (n^2 + 1) ^ (-c[7] - 1) * + exp(-c[8] * (Modelica.Math.atan(n) + Modelica.Math.atan(c[8] / (2 * c[7])))) + "Partial derivative of the equilibrium uptake w.r.t. auxiliary variable"; + Real dn_dA = 1 / c[6] + "Partial derivative of the auxiliary variable w.r.t. adsorption potential"; + + algorithm + dW_dA := dW_dn*dn_dA + "Partial derivative of the filled pore volume w.r.t. adsorption potential at + constant pressure and temperature"; + end dW_dA; + + redeclare final function extends ddW_dA_dA + "Dubinin-Pearson-IV: Second-order partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure and temperature" + + // + // Definition of variables + // +protected + Real n = (A - c[6]/2 * c[8]/c[7] - c[5]) / c[6] + "Auxiliary variable"; + + Real dW_dn = -c[4] * (1 + c[8]^2 / 4 / c[7]^2) ^ c[7] * + (2*c[7] * n + c[8]) * (n^2 + 1) ^ (-c[7] - 1) * + exp(-c[8] * (Modelica.Math.atan(n) + Modelica.Math.atan(c[8] / (2 * c[7])))) + "Partial derivative of the equilibrium uptake w.r.t. auxiliary variable"; + Real dn_dA = 1 / c[6] + "Partial derivative of the auxiliary variable w.r.t. adsorption potential"; + + Real ddW_dn_dn = c[4] * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * (n^2 + 1)^(-c[7] - 2) * + ((4 * c[7]^2 + 2 * c[7]) * n^2 + (4 * c[7] + 2) * c[8] * n + c[8]^2 - 2 * c[7]) * + exp(-c[8] * (Modelica.Math.atan(n) + Modelica.Math.atan(c[8] / (2 * c[7])))) + "Second-order partial derivative of the equilibrium uptake w.r.t. auxiliary + variable"; + + algorithm + ddW_dA_dA := (dn_dA) * (ddW_dn_dn * dn_dA) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential at constant pressure and temperature"; + end ddW_dA_dA; + + redeclare final function extends ddW_dA_dT + "Dubinin-Pearson-IV: Second-order partial derivative of filled pore volume w.r.t. adsorption potential and temperature at constant pressure" + + // + // Definition of variables + // +protected + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of adsorption potential w.r.t. equilibrium temperature + at constant pressure"; + + Real ddW_dA_dA = (8 * c[4] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + ((8 * c[7]^3 + 4 * c[7]^2) * A^2 + (-16 * c[5] * c[7]^3 - 8 * c[5] * + c[7]^2) * A - c[6]^2 * c[8]^2 + 8 * c[5]^2 * c[7]^3 + (4 * c[5]^2 - 4 * + c[6]^2) * c[7]^2) * exp(-c[8] * (Modelica.Math.atan((A - (c[6] * c[8]) / + (2 * c[7]) - c[5]) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / + ((4 * c[7]^2 * A^2 + (-4 * c[6] * c[7] * c[8] - 8 * c[5] * c[7]^2) * A + + c[6]^2 * c[8]^2 + 4 * c[5] * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * + c[5]^2) * c[7]^2)^2 * ((A - (c[6] * c[8]) / (2 * c[7]) - c[5])^2 / + c[6]^2 + 1)^c[7]) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential"; + Real ddW_dA_dc4 = -(((2 * c[7] * (-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)) / + c[6] + c[8]) * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * ((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A)^2 / c[6]^2 + 1)^(-c[7] - 1) * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7]))))) / c[6] + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and fourth coefficient of the Dubinin-Pearson-IV + isotherm model"; + Real ddW_dA_dc5 = -(8 * c[4] * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + ((8 * c[7]^3 + 4 * c[7]^2) * c[5]^2 + (-16 * A * c[7]^3 - 8 * A * c[7]^2) * + c[5] - c[6]^2 * c[8]^2 + 8 * A^2 * c[7]^3 + (4 * A^2 - 4 * c[6]^2) * + c[7]^2) * exp(-c[8] * (Modelica.Math.atan((-c[5] - (c[6] * c[8]) / (2 * + c[7]) + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / (((-c[5] - + (c[6] * c[8]) / (2 * c[7]) + A)^2 / c[6]^2 + 1)^c[7] * (4 * c[7]^2 * + c[5]^2 + (4 * c[6] * c[7] * c[8] - 8 * A * c[7]^2) * c[5] + c[6]^2 * + c[8]^2 - 4 * A * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * A^2) * c[7]^2)^2) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and fivth coefficient of the Dubinin-Pearson-IV + isotherm model"; + Real ddW_dA_dc6 = -(16 * c[4] * (c[5] - A) * c[7]^3 * (c[8]^2 / (4 * + c[7]^2) + 1)^c[7] * ((c[8]^2 + 4 * c[7]^2) * c[6]^2 + (2 * c[5] - 2 * A) * + c[7] * c[8] * c[6] + (-4 * c[5]^2 + 8 * A * c[5] - 4 * A^2) * c[7]^3) * + exp(-c[8] * (Modelica.Math.atan((-(c[8] * c[6]) / (2 * c[7]) - c[5] + A) / + c[6]) + Modelica.Math.atan(c[8] / (2 * c[7]))))) / (c[6] * ((c[8]^2 + 4 * + c[7]^2) * c[6]^2 + (4 * c[5] - 4 * A) * c[7] * c[8] * c[6] + (4 * c[5]^2 - + 8 * A * c[5] + 4 * A^2) * c[7]^2)^2 * ((-(c[8] * c[6]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and sixth coefficient of the Dubinin-Pearson-IV + isotherm model"; + Real ddW_dA_dc7 = (8 * c[4] * (c[5] - A) * (c[8]^2 / (4 * c[7]^2) + 1)^c[7] * + c[7]^2 * (((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * + log(c[8]^2 / (4 * c[7]^2) + 1) + (-4 * c[6]^2 - 4 * c[5]^2 + 8 * A * + c[5] - 4 * A^2) * log((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + + 1)) * c[7]^3 + ((4 * c[5] - 4 * A) * c[6] * c[8] * log(c[8]^2 / (4 * + c[7]^2) + 1) + (4 * A - 4 * c[5]) * c[6] * c[8] * log((-(c[6] * c[8]) / + (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) + (4 * c[5] - 4 * A) * c[6] * c[8] + + 4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2 + (c[6]^2 * + c[8]^2 * log(c[8]^2 / (4 * c[7]^2) + 1) - c[6]^2 * c[8]^2 * log((-(c[6] * + c[8]) / (2 * c[7]) - c[5] + A)^2 / c[6]^2 + 1) + (8 * c[5] - 8 * A) * + c[6] * c[8]) * c[7] + 3 * c[6]^2 * c[8]^2) * exp(-c[8] * + (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - c[5] + A) / c[6]) + + Modelica.Math.atan(c[8] / (2 * c[7]))))) / (((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A)^2 / c[6]^2 + 1)^c[7] * ((4 * c[6]^2 + 4 * c[5]^2 - 8 * A * + c[5] + 4 * A^2) * c[7]^2 + (4 * c[5] - 4 * A) * c[6] * c[8] * c[7] + + c[6]^2 * c[8]^2)^2) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and seventh coefficient of the Dubinin-Pearson-IV + isotherm model"; + Real ddW_dA_dc8 = -(8 * c[4] * (c[5] - A) * c[7]^3 * (c[8]^2 / (4 * c[7]^2) + + 1)^c[7] * exp(-c[8] * (Modelica.Math.atan((-(c[6] * c[8]) / (2 * c[7]) - + c[5] + A) / c[6]) + Modelica.Math.atan(c[8] / (2 * c[7])))) * ((c[6]^2 * + c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - + 8 * A * c[5] + 4 * A^2) * c[7]^2) * Modelica.Math.atan((-(c[6] * c[8]) / + (2 * c[7]) - c[5] + A) / c[6]) + (c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * + c[6] * c[7] * c[8] + (4 * c[6]^2 + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * + c[7]^2) * Modelica.Math.atan(c[8] / (2 * c[7])) + 2 * c[6]^2 * c[8] + (4 * + c[5] - 4 * A) * c[6] * c[7]^2 + (4 * c[5] - 4 * A) * c[6] * c[7])) / + ((c[6]^2 * c[8]^2 + (4 * c[5] - 4 * A) * c[6] * c[7] * c[8] + (4 * c[6]^2 + + 4 * c[5]^2 - 8 * A * c[5] + 4 * A^2) * c[7]^2)^2 * ((-(c[6] * c[8]) / (2 * + c[7]) - c[5] + A)^2 / c[6]^2 + 1)^c[7]) + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and eigth coefficient of the Dubinin-Pearson-IV + isotherm model"; + + algorithm + ddW_dA_dT := ddW_dA_dA * dA_dT_adsorpt + + ddW_dA_dc4 * dc_dT_adsorpt[4] + + ddW_dA_dc5 * dc_dT_adsorpt[5] + + ddW_dA_dc6 * dc_dT_adsorpt[6] + + ddW_dA_dc7 * dc_dT_adsorpt[7] + + ddW_dA_dc8 * dc_dT_adsorpt[8] + "Second-order partial derivative of filled pore volume w.r.t. adsorption + potential and temperature at constant pressure"; + end ddW_dA_dT; + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Dubinin-Pearson-IV isotherm model is a eight-parameter model for calculating +the equilibrium uptake <i>x_adsorpt</i> as a function of the equilibrium pressure +<i>p_adsorpt</i>. +</p> + +<h4>Main equations</h4> +<p> +The Dubinin-Pearson-IV isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) * W(A(T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + W(A(T<sub>adsorpt</sub>)) = a + (b * (1 + n<sup>2</sup>) ^(-e) * <strong>exp</strong>(-f * (<strong>arctan</strong>(n) + <strong>arctan</strong>(f / (2 * e))))) / (1 + f<sup>2</sup> / (4 * e<sup>2</sup>)) ^(-e); +</pre> +<pre> + n(A(T<sub>adsorpt</sub>)) = (A - d/2 * f/e - c) / d; +</pre> +<pre> + A(T<sub>adsorpt</sub>) = R * T<sub>adsorpt</sub> * <strong>ln</strong>(p<sub>sat</sub>(T<sub>adsorpt</sub>) / p<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>W(A(T<sub>adsorpt</sub>))</i> is the so-called characteristic curve and +<i>A(T<sub>adsorpt</sub>)</i> is the adsorption potential. Within the characteristic +curve, the parameters <i>a</i>, <i>b</i>, <i>c</i>, <i>d</i>, <i>e</i>, and <i>f</i> +are fitting parameters. +<br/><br/> +Note that the density of the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> +is assumed to be the saturated liquid density ρ<sub>sat,liq</sub>(T<sub>adsorpt</sub>) +without any further information about the system under consideration. For super-critical +adsorptives (i.e., <i>T<sub>adsorpt</sub> ≥ T<sub>crit</sub></i>), the density of +the adsorpt <i>ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>)</i> can be estimated by +</p> +<pre> + ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) = ρ<sub>sat,liq</sub>(T<sub>boiling,0</sub>) * <strong>exp</strong>(-0.0025 * (T<sub>adsorpt</sub> - T<sub>boiling,0</sub>)); +</pre> +<p> +and a pseudo-vapour pressure <i>p<sub>sat</sub>(T<sub>adsorpt</sub>)</i> can be calculated by +</p> +<pre> + p<sub>sat</sub>(T<sub>adsorpt</sub>) = p<sub>crit</sub>(T<sub>adsorpt</sub>) * (T<sub>adsorpt</sub> / T<sub>crit</sub>) ^ k; +</pre> +<p> +where <i>T<sub>boiling,0</sub></i> is the normal boiling point at 1 atm and <i>k</i> is +a fitting parameter specific to the system under consideration. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = p<sub>sat</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2] = ρ<sub>adsorpt</sub>(T<sub>adsorpt</sub>) in kg/m<sup>3</sup> + </li> + <li> + c[3] = a in m<sup>3</sup>/kg + </li> + <li> + c[4] = b in m<sup>3</sup>/kg + </li> + <li> + c[5] = c in J/mol + </li> + <li> + c[6] = d in J/mol + </li> + <li> + c[7] = e in - + </li> + <li> + c[8] = f in - + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The characteristic curve <i>W(A)</i> must decrease strictly monotonically with + increasing adsorption potential <i>A</i>. Otherwise, the inverses <i>A(W)</i> + and <i>p(x,T</i>) may not be solveable. + </li> + <li> + The reduced spreading pressure <i>π</i> may not be calculable. Accordingly, the + inverse <i>p(π,T)</i> cannot be calculated either. + </li> +</ul> + +<h4>Example</h4> +<p> +The following figure shows the Dubinin-Pearson-IV isotherm model for one +parameter set. In the upper sub-figure, the equilibrium pressure changes with +time, while the equilibrium temperature is constant. In the centered sub-figure, the +equilibrium temperature changes with time, while the equilibrium pressure is constant. +In the lower sub-figure, the characteristic curve is shown. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_pearson_iv.png\" alt=\"media_functions_equilibria_pure_dubinin_pearson_iv.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> + <li> + Schawe, D. (1999). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD Thesis, Stuttgart. + </li> +</ul> +</html>")); +end DubininPearsonIV; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininPearsonIV/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininPearsonIV/package.order new file mode 100644 index 0000000000000000000000000000000000000000..44a21b8e54c5e42bc784fb6013efc1fbbf99d434 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/DubininPearsonIV/package.order @@ -0,0 +1,12 @@ +x_pT +p_xT +dx_dT +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT +W_A +A_W +dW_dA +ddW_dA_dA +ddW_dA_dT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Freundlich/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Freundlich/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..bb11cd386e5930ea45018116a6097a4e9a6719e1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Freundlich/package.mo @@ -0,0 +1,242 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package Freundlich "Package containing all functions regarding the Freundlich isotherm" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents; + + redeclare final function extends x_pT + "Freundlich isotherm model: Uptake as function of pressure and temperature" + algorithm + x_adsorpt := c[1] * p_adsorpt^(1/c[2]) + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Freundlich.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Freundlich isotherm model: Pressure as function of uptake and temperature" + algorithm + p_adsorpt := (x_adsorpt/c[1])^c[2] + "Calculation of the equilibrium pressure of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Freundlich.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dp + "Freundlich isotherm model: Partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + dx_adsorpt_dp_adsorpt := c[1]/c[2] * p_adsorpt^(1/c[2] - 1) + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure at constant temperature"; + end dx_dp; + + redeclare final function extends dx_dT + "Freundlich isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = p_adsorpt ^ (1/c[2]) + "Derivative of uptake w.r.t. to first coefficient of Freundlich isotherm"; + Real dx_adsorpt_dc2 = -c[1] / c[2]^2 * p_adsorpt ^ (1/c[2]) * log(p_adsorpt) + "Derivative of uptake w.r.t. to second coefficient of Freundlich isotherm"; + + algorithm + dx_adsorpt_dT_adsorpt := + dx_adsorpt_dc1*dc_dT_adsorpt[1] + + dx_adsorpt_dc2*dc_dT_adsorpt[2] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dp_dp + "Freundlich isotherm model: Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + ddx_adsorpt_dp_adsorpt_dp_adsorpt := (c[1] * (1 / c[2] - 1) * + p_adsorpt^(1 / c[2] - 2)) / c[2] + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure at constant temperature"; + end ddx_dp_dp; + + redeclare final function extends ddx_dT_dT + "Freundlich isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = p_adsorpt ^ (1/c[2]) + "Derivative of uptake w.r.t. to first coefficient of Freundlich isotherm"; + Real dx_adsorpt_dc2 = -c[1] / c[2]^2 * p_adsorpt ^ (1/c[2]) * log(p_adsorpt) + "Derivative of uptake w.r.t. to second coefficient of Freundlich isotherm"; + + Real ddx_adsorpt_dc1_dc2 = -1 / c[2]^2 * p_adsorpt ^ (1/c[2]) * log(p_adsorpt) + "Second-order partial derivative of uptake w.r.t. to first and second + coefficient of Freundlich isotherm"; + + Real ddx_adsorpt_dc2_dc2 = c[1] / c[2]^4 * p_adsorpt ^ (1/c[2]) * + log(p_adsorpt) * (2*c[2] + log(p_adsorpt)) + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Freundlich isotherm"; + + Real ddx_adsorpt_dc1_dT_adsorpt = ddx_adsorpt_dc1_dc2*dc_dT_adsorpt[2] + "Second-order partial derivative of uptake w.r.t. to first coefficient of + Freundlich isotherm and temperature"; + Real ddx_adsorpt_dc2_dT_adsorpt = ddx_adsorpt_dc1_dc2*dc_dT_adsorpt[1] + + ddx_adsorpt_dc2_dc2*dc_dT_adsorpt[2] + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Freundlich isotherm and temperature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + (ddx_adsorpt_dc1_dT_adsorpt*dc_dT_adsorpt[1] + + dx_adsorpt_dc1*ddc_dT_adsorpt_dT_adsorpt[1]) + + (ddx_adsorpt_dc2_dT_adsorpt*dc_dT_adsorpt[2] + + dx_adsorpt_dc2*ddc_dT_adsorpt_dT_adsorpt[2]) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Freundlich isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + Real ddx_adsorpt_dp_adsorpt_dc1 = 1 / c[2] * p_adsorpt ^ (1/c[2] - 1) + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + first coefficient of Freundlich isotherm"; + Real ddx_adsorpt_dp_adsorpt_dc2 = -c[1] / c[2]^3 * p_adsorpt ^ (1/c[2] - 1) * + (log(p_adsorpt) + c[2]) + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + second coefficient of Freundlich isotherm"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + ddx_adsorpt_dp_adsorpt_dc1*dc_dT_adsorpt[1] + + ddx_adsorpt_dp_adsorpt_dc2*dc_dT_adsorpt[2] + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare final function extends pi_pT + "Freundlich isotherm model: Reduced spreading pressure as function of pressure and temperature" + algorithm + pi := 1/M_adsorptive * (c[1]*c[2] * p_adsorpt^(1/c[2])) + "Calculation of the reduced spreading pressure"; + end pi_pT; + + redeclare final function extends p_piT + "Freundlich isotherm model: Pressure as function of reduced spreading pressure and temperature" + algorithm + p_adsorpt := (M_adsorptive * pi / (c[1]*c[2])) ^ c[2] + "Calculation of the equilibrium pressure"; + end p_piT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Freundlich isotherm model is a two-parameter model for calculating the equilibrium +uptake <i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>. +The Freundlich isotherm model is suitable for type III isotherms according to the +IUPAC definition. +</p> + +<h4>Main equations</h4> +<p> +The Freundlich isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = K(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub> ^ (1/n(T<sub>adsorpt</sub>)); +</pre> +<p> +where <i>K(T<sub>adsorpt</sub>)</i> is the Freundlich coefficient and +<i>n(T<sub>adsorpt</sub>)</i> is the Freundlich exponent. Typical temperature +dependencies may have the following forms: +</p> +</p> +<pre> + K(T<sub>adsorpt</sub>) = a<sub>0</sub> * <strong>exp</strong>(-a<sub>1</sub> * T<sub>adsorpt</sub>)); +</pre> +<pre> + n(T<sub>adsorpt</sub>) = b<sub>0</sub> + b<sub>1</sub>/T<sub>adsorpt</sub>; +</pre> +<p> +where <i>a<sub>0</sub></i>, <i>a<sub>1</sub></i>, <i>b<sub>0</sub></i>, and +<i>b<sub>1</sub></i> are fiiting parameters. +<br/><br/> +Note that the Freundlich exponent <i>n(T<sub>adsorpt</sub>)</i> is typically +greater than unity. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = K(T<sub>adsorpt</sub>) in 1/Pa^(1/n(T<sub>adsorpt</sub>)) + </li> + <li> + c[2] = n(T<sub>adsorpt</sub>) in - + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + No proper Henry law behavior. + </li> + <li> + No finite limit when pressure is sufficiently high. + </li> +</ul> +<p> +Hence, the Freundlich isotherm is generally valid narrow the range of adsorption +data used for fitting. +</p> + +<h4>Typical use</h4> +<p> +The isotherm model is used for type III isotherms according to the IUPAC definition. +</p> + +<h4>Example</h4> +<p> +The following figure shows the Freundlich isotherm model for different parameter sets. +In the upper sub-figure, the equilibrium pressure changes with time, while the +equilibrium temperature remains constant; in the lower sub-figure, the equilibrium +temperature changes with time, while the equilibrium pressure remains constant. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_freundlich.png\" alt=\"media_functions_equilibria_pure_freundlich.png\"> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>")); +end Freundlich; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Freundlich/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Freundlich/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5b33869cf15d79cfe321d3ef372972c01c4559b4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Freundlich/package.order @@ -0,0 +1,9 @@ +x_pT +p_xT +dx_dp +dx_dT +ddx_dp_dp +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/GAB/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/GAB/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..53016cbf62d14636f960775b1100b1871cf3e2a1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/GAB/package.mo @@ -0,0 +1,416 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package GAB "Package containing all functions regarding the GAB isotherm" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents; + + redeclare final function extends x_pT + "GAB isotherm model: Uptake as function of pressure and temperature" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + + algorithm + x_adsorpt := c[2]*c[3]*c[4] * phi / + ((1 - c[4] * phi) * (1 + (c[3] - 1) * c[4] * phi)) + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "GAB isotherm model: Pressure as function of uptake and temperature" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + + algorithm + p_adsorpt := (c[3]*x_adsorpt - c[3]*c[2] - 2*x_adsorpt + sqrt(c[3] * + (c[3]*x_adsorpt^2 - 2*c[3]*c[2]*x_adsorpt + c[3]*c[2]^2 + 4*c[2]*x_adsorpt))) / + (2*c[4]*x_adsorpt * (c[3] - 1)) * c[1] + "Calculation of the equilibrium pressure of the adsorpt phase: Solve + quadratic equation and discard negative solution"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dp + "GAB isotherm model: Partial derivative of uptake w.r.t. pressure at constant temperature" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + Real dphi_dp_adsorpt = 1/c[1] + "Partial derivative of relative pressure w.r.t. to pressure"; + + algorithm + dx_adsorpt_dp_adsorpt := c[2]*c[3]*c[4] * ((c[3] - 1) * c[4]^2 * phi^2 + 1) / + ((c[4] * phi - 1)^2 * (1 + (c[3] - 1) * c[4] * phi)^2) * dphi_dp_adsorpt + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure at constant temperature"; + end dx_dp; + + redeclare final function extends dx_dT + "GAB isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + Real dphi_dc1 = -p_adsorpt/c[1]^2 + "Partial derivative of relative pressure w.r.t. to saturation pressure"; + + Real dx_adsorpt_dphi = c[2]*c[3]*c[4] * ((c[3] - 1) * c[4]^2 * phi^2 + 1) / + ((c[4] * phi - 1)^2 * (1 + (c[3] - 1) * c[4] * phi)^2) + "Partial derivative of uptake w.r.t. to relative pressure"; + + Real dx_adsorpt_dc1 = dx_adsorpt_dphi*dphi_dc1 + "Derivative of uptake w.r.t. to first coefficient of GAB isotherm"; + Real dx_adsorpt_dc2 = c[3]*c[4] * phi / + ((1 - c[4] * phi) * (1 + (c[3] - 1) * c[4] * phi)) + "Derivative of uptake w.r.t. to second coefficient of GAB isotherm"; + Real dx_adsorpt_dc3 = c[2]*c[4] * phi / (c[3]*c[4] * phi - c[4] * phi + 1)^2 + "Derivative of uptake w.r.t. to third coefficient of GAB isotherm"; + Real dx_adsorpt_dc4 = c[2]*c[3] * phi * ((c[3] - 1) * c[4]^2 * phi^2 + 1) / + ((c[4] * phi - 1)^2 * (1 + (c[3] - 1) * c[4] * phi)^2) + "Derivative of uptake w.r.t. to fourtg coefficient of GAB isotherm"; + + algorithm + dx_adsorpt_dT_adsorpt := + dx_adsorpt_dc1*dc_dT_adsorpt[1] + + dx_adsorpt_dc2*dc_dT_adsorpt[2] + + dx_adsorpt_dc3*dc_dT_adsorpt[3] + + dx_adsorpt_dc4*dc_dT_adsorpt[4] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dp_dp + "GAB isotherm model: Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + Real dphi_dp_adsorpt = 1/c[1] + "Partial derivative of relative pressure w.r.t. to pressure"; + + algorithm + ddx_adsorpt_dp_adsorpt_dp_adsorpt := + (-(2 * c[2] * c[3] * c[4]^2 * ((c[3] - 1) * c[4] * phi * + ((c[3] - 1) * c[4]^2 * phi^2 + 3) - c[3] + 2)) / + ((c[4] * phi - 1)^3 * ((c[3] - 1) * c[4] * phi + 1)^3)) * dphi_dp_adsorpt^2 + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure at constant temperature"; + end ddx_dp_dp; + + redeclare final function extends ddx_dT_dT + "GAB isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = -(c[2] * c[3] * c[4] * p_adsorpt * (c[1]^2 + (c[3] - 1) * + c[4]^2 * p_adsorpt^2)) / ((c[1] - c[4] * p_adsorpt)^2 * (c[1] + (c[3] - 1) * + c[4] * p_adsorpt)^2) + "Derivative of uptake w.r.t. to first coefficient of GAB isotherm"; + Real dx_adsorpt_dc2 = -(c[1] * c[3] * c[4] * p_adsorpt) / ((c[4] * p_adsorpt - + c[1]) * ((c[3] - 1) * c[4] * p_adsorpt + c[1])) + "Derivative of uptake w.r.t. to second coefficient of GAB isotherm"; + Real dx_adsorpt_dc3 = (c[1] * c[2] * c[4] * p_adsorpt) / (c[4] * p_adsorpt * + c[3] - c[4] * p_adsorpt + c[1])^2 + "Derivative of uptake w.r.t. to third coefficient of GAB isotherm"; + Real dx_adsorpt_dc4 = (c[1] * c[2] * c[3] * p_adsorpt * ((c[3] - 1) * p_adsorpt^2 * + c[4]^2 + c[1]^2)) / ((p_adsorpt * c[4] - c[1])^2 * ((c[3] - 1) * p_adsorpt * + c[4] + c[1])^2) + "Derivative of uptake w.r.t. to fourtg coefficient of GAB isotherm"; + + Real ddx_adsorpt_dc1_dc1 = (2 * c[2] * c[3] * c[4] * p_adsorpt * (c[1]^3 + (3 * + c[3] - 3) * c[4]^2 * p_adsorpt^2 * c[1] + (c[3]^2 - 3 * c[3] + 2) * c[4]^3 * + p_adsorpt^3)) / ((c[1] - c[4] * p_adsorpt)^3 * (c[1] + (c[3] - 1) * c[4] * + p_adsorpt)^3) + "Second-order partial derivative of uptake w.r.t. to first coefficient of + GAB isotherm"; + Real ddx_adsorpt_dc3_dc3 = -(2 * c[1] * c[2] * c[4]^2 * p_adsorpt^2) / (c[4] * + p_adsorpt * c[3] - c[4] * p_adsorpt + c[1])^3 + "Second-order partial derivative of uptake w.r.t. to third coefficient of + GAB isotherm"; + Real ddx_adsorpt_dc4_dc4 = -(2 * c[1] * c[2] * c[3] * p_adsorpt^2 * ((c[3]^2 - + 2 * c[3] + 1) * p_adsorpt^3 * c[4]^3 + (3 * c[1]^2 * c[3] - 3 * c[1]^2) * + p_adsorpt * c[4] - c[1]^3 * c[3] + 2 * c[1]^3)) / ((p_adsorpt * c[4] - c[1])^3 * + ((c[3] - 1) * p_adsorpt * c[4] + c[1])^3) + "Second-order partial derivative of uptake w.r.t. to fourth coefficient of + GAB isotherm"; + + Real ddx_adsorpt_dc1_dc2= -(c[3] * c[4] * p_adsorpt * ((c[3] - 1) * c[4]^2 * + p_adsorpt^2 + c[1]^2)) / ((c[1] - c[4] * p_adsorpt)^2 * ((c[3] - 1) * c[4] * + p_adsorpt + c[1])^2) + "Second-order partial derivative of uptake w.r.t. to first and second + coefficient of GAB isotherm"; + Real ddx_adsorpt_dc1_dc3 = (c[2] * c[4] * p_adsorpt * (c[4] * p_adsorpt * c[3] - + c[4] * p_adsorpt - c[1])) / (c[4] * p_adsorpt * c[3] - c[4] * p_adsorpt + + c[1])^3 + "Second-order partial derivative of uptake w.r.t. to first and third + coefficient of GAB isotherm"; + Real ddx_adsorpt_dc1_dc4 = (c[2] * c[3] * p_adsorpt * ((c[3]^2 - 2 * c[3] + 1) * + p_adsorpt^4 * c[4]^4 + (c[1] * c[3]^2 - 3 * c[1] * c[3] + 2 * c[1]) * p_adsorpt^3 * + c[4]^3 + (6 * c[1]^2 * c[3] - 6 * c[1]^2) * p_adsorpt^2 * c[4]^2 + (2 * c[1]^3 - + c[1]^3 * c[3]) * p_adsorpt * c[4] + c[1]^4)) / ((p_adsorpt * c[4] - c[1])^3 * + ((c[3] - 1) * p_adsorpt * c[4] + c[1])^3) + "Second-order partial derivative of uptake w.r.t. to first and fourth + coefficient of GAB isotherm"; + + Real ddx_adsorpt_dc2_dc3 = (c[1] * c[4] * p_adsorpt) / (c[4] * p_adsorpt * c[3] - + c[4] * p_adsorpt + c[1])^2 + "Second-order partial derivative of uptake w.r.t. to second and third + coefficient of GAB isotherm"; + Real ddx_adsorpt_dc2_dc4 = (c[1] * c[3] * p_adsorpt * ((c[3] - 1) * p_adsorpt^2 * + c[4]^2 + c[1]^2)) / ((p_adsorpt * c[4] - c[1])^2 * ((c[3] - 1) * p_adsorpt * + c[4] + c[1])^2) + "Second-order partial derivative of uptake w.r.t. to second and fourht + coefficient of GAB isotherm"; + + Real ddx_adsorpt_dc3_dc4 = -(c[1] * c[2] * p_adsorpt * ((c[3] - 1) * p_adsorpt * + c[4] - c[1])) / ((c[3] - 1) * p_adsorpt * c[4] + c[1])^3 + "Second-order partial derivative of uptake w.r.t. to third and fourht + coefficient of GAB isotherm"; + + Real ddx_adsorpt_dc1_dT_dT_adsorpt = ddx_adsorpt_dc1_dc1*dc_dT_adsorpt[1] + + ddx_adsorpt_dc1_dc2*dc_dT_adsorpt[2] + + ddx_adsorpt_dc1_dc3*dc_dT_adsorpt[3] + + ddx_adsorpt_dc1_dc4*dc_dT_adsorpt[4] + "Second-order partial derivative of uptake w.r.t. to first coefficient of + GAB isotherm and temperature"; + Real ddx_adsorpt_dc2_dT_dT_adsorpt = ddx_adsorpt_dc1_dc2*dc_dT_adsorpt[1] + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[3] + + ddx_adsorpt_dc2_dc4*dc_dT_adsorpt[4] + "Second-order partial derivative of uptake w.r.t. to second coefficient of + GAB isotherm and temperature"; + Real ddx_adsorpt_dc3_dT_dT_adsorpt = ddx_adsorpt_dc1_dc3*dc_dT_adsorpt[1] + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[2] + + ddx_adsorpt_dc3_dc3*dc_dT_adsorpt[3] + + ddx_adsorpt_dc3_dc4*dc_dT_adsorpt[4] + "Second-order partial derivative of uptake w.r.t. to third coefficient of + GAB isotherm and temperature"; + Real ddx_adsorpt_dc4_dT_dT_adsorpt = ddx_adsorpt_dc1_dc4*dc_dT_adsorpt[1] + + ddx_adsorpt_dc2_dc4*dc_dT_adsorpt[2] + + ddx_adsorpt_dc3_dc4*dc_dT_adsorpt[3] + + ddx_adsorpt_dc4_dc4*dc_dT_adsorpt[4] + "Second-order partial derivative of uptake w.r.t. to fourth coefficient of + GAB isotherm and temperature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + (ddx_adsorpt_dc1_dT_dT_adsorpt*dc_dT_adsorpt[1] + + dx_adsorpt_dc1*ddc_dT_adsorpt_dT_adsorpt[1]) + + (ddx_adsorpt_dc2_dT_dT_adsorpt*dc_dT_adsorpt[2] + + dx_adsorpt_dc2*ddc_dT_adsorpt_dT_adsorpt[2]) + + (ddx_adsorpt_dc3_dT_dT_adsorpt*dc_dT_adsorpt[3] + + dx_adsorpt_dc3*ddc_dT_adsorpt_dT_adsorpt[3]) + + (ddx_adsorpt_dc4_dT_dT_adsorpt*dc_dT_adsorpt[4] + + dx_adsorpt_dc4*ddc_dT_adsorpt_dT_adsorpt[4]) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "GAB isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + Real ddx_adsorpt_dp_adsorpt_dc1 = (c[2] * c[3] * c[4] * ((c[3]^2 - 2 * c[3] + 1) * + c[4]^4 * p_adsorpt^4 + (c[1] * c[3]^2 - 3 * c[1] * c[3] + 2 * c[1]) * c[4]^3 * + p_adsorpt^3 + (6 * c[1]^2 * c[3] - 6 * c[1]^2) * c[4]^2 * p_adsorpt^2 + (2 * + c[1]^3 - c[1]^3 * c[3]) * c[4] * p_adsorpt + c[1]^4)) / ((c[4] * p_adsorpt - + c[1])^3 * ((c[3] - 1) * c[4] * p_adsorpt + c[1])^3) + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + first coefficient of GAB isotherm"; + Real ddx_adsorpt_dp_adsorpt_dc2 = (c[1] * c[3] * c[4] * ((c[3] - 1) * c[4]^2 * + p_adsorpt^2 + c[1]^2)) / ((c[4] * p_adsorpt - c[1])^2 * ((c[3] - 1) * c[4] * + p_adsorpt + c[1])^2) + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + second coefficient of GAB isotherm"; + Real ddx_adsorpt_dp_adsorpt_dc3 = -(c[1] * c[2] * c[4] * ((c[3] - 1) * c[4] * + p_adsorpt - c[1])) / ((c[3] - 1) * c[4] * p_adsorpt + c[1])^3 + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + third coefficient of GAB isotherm"; + Real ddx_adsorpt_dp_adsorpt_dc4 = -(c[1] * c[2] * c[3] * ((c[3]^2 - 2 * c[3] + 1) * + c[4]^4 * p_adsorpt^4 + (c[1] * c[3]^2 - 3 * c[1] * c[3] + 2 * c[1]) * c[4]^3 * + p_adsorpt^3 + (6 * c[1]^2 * c[3] - 6 * c[1]^2) * c[4]^2 * p_adsorpt^2 + (2 * + c[1]^3 - c[1]^3 * c[3]) * c[4] * p_adsorpt + c[1]^4)) / ((c[4] * p_adsorpt - + c[1])^3 * ((c[3] - 1) * c[4] * p_adsorpt + c[1])^3) + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + fourth coefficient of GAB isotherm"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + ddx_adsorpt_dp_adsorpt_dc1*dc_dT_adsorpt[1] + + ddx_adsorpt_dp_adsorpt_dc2*dc_dT_adsorpt[2] + + ddx_adsorpt_dp_adsorpt_dc3*dc_dT_adsorpt[3] + + ddx_adsorpt_dp_adsorpt_dc4*dc_dT_adsorpt[4] + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare final function extends pi_pT + "GAB isotherm model: Reduced spreading pressure as function of pressure and temperature" + + // + // Definition of variables + // +protected + Real phi = p_adsorpt/c[1] + "Relative pressure"; + + algorithm + pi := 1/M_adsorptive * + (c[2] * log((1 - c[4] * phi + c[3]*c[4] * phi) / (1 - c[4] * phi))) + "Calculation of the reduced spreading pressure"; + end pi_pT; + + redeclare final function extends p_piT + "GAB isotherm model: Pressure as function of reduced spreading pressure and temperature" + algorithm + p_adsorpt := c[1] * (1 - exp(pi * M_adsorptive / c[2])) / + (-exp(pi * M_adsorptive / c[2]) * c[4] + c[4] - c[3] * c[4]) + "Calculation of the equilibrium pressure"; + end p_piT; + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The GAB isotherm model is a four-parameter model for calculating the equilibrium +uptake <i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>. +The GAB isotherm model is suitable for type III isotherms according to the IUPAC +definition. +</p> + +<h4>Main equations</h4> +<p> +The GAB isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = x<sub>mon</sub>(T<sub>adsorpt</sub>) * c(T<sub>adsorpt</sub>) * k(T<sub>adsorpt</sub>) * φ(T<sub>adsorpt</sub>) / ((1 - k(T<sub>adsorpt</sub>) * φ(T<sub>adsorpt</sub>)) * (1 + (c(T<sub>adsorpt</sub>) - 1) * k(T<sub>adsorpt</sub>) * φ(T<sub>adsorpt</sub>))); +</pre> +<p> +with +</p> +<pre> + φ(T<sub>adsorpt</sub>) = p<sub>adsorpt</sub>/p<sub>sat</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +Herein, <i>x<sub>mon</sub>(T<sub>adsorpt</sub>)</i> is the monolayer uptake and +<i>c(T<sub>adsorpt</sub>)</i> and <i>k(T<sub>adsorpt</sub>)</i> are affinity +coefficients of the GAB isotherm model. These three parameters can be modeled +independent of temperature. When assuming these three parameters to be dependent +on temperature, typical temperature dependencies may have the following forms: +</p> +<pre> + x<sub>mon</sub>(T<sub>adsorpt</sub>) = x<sub>mon,ref</sub> * <strong>exp</strong>(Χ * (1 - T<sub>adsorpt</sub>/T<sub>ref</sub>)); +</pre> +<pre> + c(T<sub>adsorpt</sub>) = <strong>exp</strong>((E<sub>1</sub> - E<sub>10+</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<pre> + k(T<sub>adsorpt</sub>) = <strong>exp</strong>((E<sub>2-9</sub> - E<sub>10+</sub>) / (R * T<sub>adsorpt</sub>)); +</pre> +<p> +with +</p> +<pre> + E<sub>1</sub> = C - <strong>exp</strong>(D * T<sub>adsorpt</sub>); +</pre> +<pre> + E<sub>2-9</sub> = F + G * T<sub>adsorpt</sub>; +</pre> +<pre> + E<sub>10+</sub> = Δh<sub>vap</sub>(T<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>mon,ref</sub></i> is the monolayer uptake at reference temperature +<i>T<sub>ref</sub></i> and <i>Χ</i> describes the change of the monolayer uptake +with temperature. The coefficient <i>E<sub>1</sub></i> is the enthalpy of adsorption +of the first layer and <i>E<sub>2-9</sub></i> is the enthalpy of adsorption of layers +2-9: These enthalpies of adsorption can be modeled temperature-dependent as shown +in the example above, with the four fitting parameters <i>C</i>, <i>D</i>, <i>E</i>, +and <i>F</i>. The coefficient <i>E<sub>10+</sub></i> is the enthalpy of adsorptions +for layer 10 or higher layers and is assumed to correspond to the temperature-dependent +enthalpy of vaporization <i>Δh<sub>vap</sub>(T<sub>adsorpt</sub>)</i>. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = p<sub>sat</sub>(T<sub>adsorpt</sub>) in Pa + </li> + <li> + c[2] = x<sub>mon</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[3] = c(T<sub>adsorpt</sub>) in - + </li> + <li> + c[4] = k(T<sub>adsorpt</sub>) in - + </li> +</ul> + +<h4>Typical use</h4> +<p> +The isotherm model is used for type III isotherms according to the IUPAC definition. +</p> + +<h4>Example</h4> +<p> +The following figure shows the GAB isotherm model for different parameter sets. +In the upper sub-figure, the equilibrium pressure changes with time, while the +equilibrium temperature remains constant; in the lower sub-figure, the equilibrium +temperature changes with time, while the equilibrium pressure remains constant. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_gab.png\" alt=\"media_functions_equilibria_pure_gab.png\"> + +<h4>References</h4> +<ul> + <li> + Young et al. (2021). The impact of binary water – CO<sub>2</sub> isotherm models on the optimal performance of sorbent-based direct air capture processes, Energy Environ. Sci. 14: 5377. DOI: 10.1039/d1ee01272j. + </li> +</ul> +</html>")); +end GAB; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/GAB/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/GAB/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5b33869cf15d79cfe321d3ef372972c01c4559b4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/GAB/package.order @@ -0,0 +1,9 @@ +x_pT +p_xT +dx_dp +dx_dT +ddx_dp_dp +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Henry/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Henry/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b5fa2998daf0406d8f3e47d8599844324262e868 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Henry/package.mo @@ -0,0 +1,172 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package Henry "Package containing all functions regarding the Henry isotherm" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents; + + redeclare final function extends x_pT + "Henry isotherm model: Uptake as function of pressure and temperature" + algorithm + x_adsorpt := c[1]*p_adsorpt + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Henry.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Henry isotherm model: Pressure as function of uptake and temperature" + algorithm + p_adsorpt := x_adsorpt/c[1] + "Calculation of the equilibrium pressure of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Henry.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dp + "Henry isotherm model: Partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + dx_adsorpt_dp_adsorpt := c[1] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure at constant temperature"; + end dx_dp; + + redeclare final function extends dx_dT + "Henry isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + algorithm + dx_adsorpt_dT_adsorpt := p_adsorpt*dc_dT_adsorpt[1] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dp_dp + "Henry isotherm model: Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + ddx_adsorpt_dp_adsorpt_dp_adsorpt := 0 + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure at constant temperature"; + end ddx_dp_dp; + + redeclare final function extends ddx_dT_dT + "Henry isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := p_adsorpt*ddc_dT_adsorpt_dT_adsorpt[1] + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Henry isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := dc_dT_adsorpt[1] + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare final function extends pi_pT + "Henry isotherm model: Reduced spreading pressure as function of pressure and temperature" + algorithm + pi := 1/M_adsorptive * (c[1]*p_adsorpt) + "Calculation of the reduced spreading pressure"; + end pi_pT; + + redeclare final function extends p_piT + "Henry isotherm model: Pressure as function of reduced spreading pressure and temperature" + algorithm + p_adsorpt := M_adsorptive * pi / c[1] + "Calculation of the equilibrium pressure"; + end p_piT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Henry isotherm model calculates the equilibrium uptake <i>x_adsorpt</i> in +linear relation to the equilibrium pressure <i>p_adsorpt</i>. The proportionality +coefficient is the so-called Henry coefficient <i>H</i>, which may depend on the +equilibrium temperature <i>T_adsorpt</i>. +</p> + +<h4>Main equations</h4> +<p> +The Henry isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = H(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub>; +</pre> +<p> +where <i>H</i> is the temperature-dependent Henry coefficient. A typical temperature +dependency may have the following form: +</p> +<pre> + H(T<sub>adsorpt</sub>) = H<sub>ref</sub> * <strong>exp</strong>(C<sub>exp</sub> * (1/T<sub>adsorpt</sub> - 1/T<sub>ref</sub>)); +</pre> +<p> +where <i>H<sub>ref</sub></i> is the Henry coefficient at reference temperature +<i>T<sub>ref</sub></i> and <i>C<sub>exp</sub></i> describes the change of the Henry +coefficient with the temperature. All three parameters can be used as fitting +parameters. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = H(T<sub>adsorpt</sub>) in 1/Pa + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + All adsorption sites are energetically equivalent. + </li> + <li> + All adsorption sites can be occupied. + </li> + <li> + No interactions occur between the adsorbent molecules. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The isotherm model is used to calculate the equilibrium uptake <i>x_adsorpt</i> +at very low equilibrium pressures <i>p_adsorpt</i>. +</p> + +<h4>Example</h4> +<p> +The following figure shows the Henry isotherm model for different reference +values of the Henry coefficient <i>H_ref</i>. In the upper sub-figure, the +equilibrium pressure changes with time, while the equilibrium temperature +remains constant; in the lower sub-figure, the equilibrium temperature +changes with time, while the equilibrium pressure remains constant. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_henry.png\" alt=\"media_functions_equilibria_pure_henry.png\"> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> +</ul> +</html>")); +end Henry; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Henry/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Henry/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5b33869cf15d79cfe321d3ef372972c01c4559b4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Henry/package.order @@ -0,0 +1,9 @@ +x_pT +p_xT +dx_dp +dx_dT +ddx_dp_dp +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Langmuir/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Langmuir/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..422b37c4df87533d33bc5d7a073bb55a7a95738b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Langmuir/package.mo @@ -0,0 +1,243 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package Langmuir "Package containing all functions regarding the Langmuir isotherm" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents; + + redeclare final function extends x_pT + "Langmuir isotherm model: Uptake as function of pressure and temperature" + algorithm + x_adsorpt := c[1]*c[2]*p_adsorpt / (1 + c[2]*p_adsorpt) + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Langmuir isotherm model: Pressure as function of uptake and temperature" + algorithm + p_adsorpt := x_adsorpt / (c[2] * (c[1]-x_adsorpt)) + "Calculation of the equilibrium pressure of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dp + "Langmuir isotherm model: Partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + dx_adsorpt_dp_adsorpt := c[1]*c[2] / (1 + c[2]*p_adsorpt) - + c[1]*c[2]^2*p_adsorpt / (1 + c[2]*p_adsorpt)^2 + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure at constant temperature"; + end dx_dp; + + redeclare final function extends dx_dT + "Langmuir isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = c[2]*p_adsorpt / (1 + c[2]*p_adsorpt) + "Derivative of uptake w.r.t. to first coefficient of Langmuir isotherm"; + Real dx_adsorpt_dc2 = c[1]*p_adsorpt / (1 + c[2]*p_adsorpt)^2 + "Derivative of uptake w.r.t. to second coefficient of Langmuir isotherm"; + + algorithm + dx_adsorpt_dT_adsorpt := + dx_adsorpt_dc1*dc_dT_adsorpt[1] + + dx_adsorpt_dc2*dc_dT_adsorpt[2] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dp_dp + "Langmuir isotherm model: Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + ddx_adsorpt_dp_adsorpt_dp_adsorpt := + -(2 * c[1] * c[2]^2) / (c[2] * p_adsorpt + 1)^3 + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure at constant temperature"; + end ddx_dp_dp; + + redeclare final function extends ddx_dT_dT + "Langmuir isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = c[2]*p_adsorpt / (1 + c[2]*p_adsorpt) + "Partial derivative of uptake w.r.t. to first coefficient of Langmuir isotherm"; + Real dx_adsorpt_dc2 = c[1]*p_adsorpt / (1 + c[2]*p_adsorpt)^2 + "Partial derivative of uptake w.r.t. to second coefficient of Langmuir isotherm"; + + Real ddx_adsorpt_dc1_dc2 = p_adsorpt / (1 + c[2]*p_adsorpt)^2 + "Second-order partial derivative of uptake w.r.t. to first and second + coefficient of Langmuir isotherm"; + + Real ddx_adsorpt_dc2_dc2 = -2 * c[1] * p_adsorpt^2 / (1 + c[2]*p_adsorpt)^3 + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Langmuir isotherm"; + + Real ddx_adsorpt_dc1_dT_adsorpt = ddx_adsorpt_dc1_dc2*dc_dT_adsorpt[2] + "Second-order partial derivative of uptake w.r.t. to first coefficient of + Langmuir isotherm and temperature"; + Real ddx_adsorpt_dc2_dT_adsorpt = ddx_adsorpt_dc1_dc2*dc_dT_adsorpt[1] + + ddx_adsorpt_dc2_dc2*dc_dT_adsorpt[2] + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Langmuir isotherm and temperature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + (ddx_adsorpt_dc1_dT_adsorpt*dc_dT_adsorpt[1] + + dx_adsorpt_dc1*ddc_dT_adsorpt_dT_adsorpt[1]) + + (ddx_adsorpt_dc2_dT_adsorpt*dc_dT_adsorpt[2] + + dx_adsorpt_dc2*ddc_dT_adsorpt_dT_adsorpt[2]) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Langmuir isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + Real ddx_adsorpt_dp_adsorpt_dc1 = c[2] / (1 + c[2]*p_adsorpt)^2 + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + first coefficient of Langmuir isotherm"; + Real ddx_adsorpt_dp_adsorpt_dc2 = -c[1] * (c[2]*p_adsorpt - 1) / + (1 + c[2]*p_adsorpt)^3 + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + second coefficient of Langmuir isotherm"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + ddx_adsorpt_dp_adsorpt_dc1*dc_dT_adsorpt[1] + + ddx_adsorpt_dp_adsorpt_dc2*dc_dT_adsorpt[2] + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare final function extends pi_pT + "Langmuir isotherm model: Pressure as function of reduced spreading pressure and temperature" + algorithm + pi := 1/M_adsorptive * (c[1]*log(1 + c[2]*p_adsorpt)) + "Calculation of the reduced spreading pressure"; + end pi_pT; + + redeclare final function extends p_piT + "Langmuir isotherm model: Pressure as function of reduced spreading pressure and temperature" + algorithm + p_adsorpt := (exp(M_adsorptive * pi / c[1]) - 1) / c[2] + "Calculation of the equilibrium pressure"; + end p_piT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + </li> +</ul> +</html>", info="<html> +<p> +The Langmuir isotherm model is a two-parameter model for calculating the equilibrium +uptake <i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>. +The Langmuir isotherm model is suitable for type I isotherms according to the +IUPAC definition. +</p> + +<h4>Main equations</h4> +<p> +The Langmuir isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = x<sub>sat</sub>(T<sub>adsorpt</sub>) * (b(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub>) / (1 + b(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>sat</sub>(T<sub>adsorpt</sub>)</i> is the saturation uptake and +<i>b(T<sub>adsorpt</sub>)</i> is the Langmuir coefficient. Typical temperature +dependencies may have the following forms: +</p> +<pre> + x<sub>sat</sub>(T<sub>adsorpt</sub>) = a<sub>0</sub> + a<sub>1</sub>/T<sub>adsorpt</sub>; +</pre> +<pre> + b(T<sub>adsorpt</sub>) = b<sub>0</sub> * <strong>exp</strong>(-ΔH<sub>ads</sub>/(R * T<sub>adsorpt</sub>)); +</pre> +<p> +where <i>a<sub>0</sub></i>, <i>a<sub>1</sub></i>, <i>b<sub>0</sub></i>, and +<i>ΔH<sub>ads</sub></i> are fitting parameters. The parameter +<i>ΔH<sub>ads</sub></i> is the isosteric adsorption heat, which is +invariant with the surface uptake. Note that the Langmuir isotherm model only +consists of thermodynamic consistency if the saturation uptake <i>x<sub>sat</sub></i> +is constant. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = x<sub>sat</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[2] = b(T<sub>adsorpt</sub>) in 1/Pa + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + All adsorption sites are energetically equivalent. + </li> + <li> + All adsorption sites can be occupied. + </li> + <li> + No interactions occur between the adsorbent molecules. + </li> + <li> + The adsorbent surface is covered monomolecularly. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The isotherm model is used for type I isotherms according to the IUPAC definition. +</p> + +<h4>Example</h4> +<p> +The following figure shows the Langmuir isotherm model for different parameter sets. +In the upper sub-figure, the equilibrium pressure changes with time, while the +equilibrium temperature remains constant; in the lower sub-figure, the equilibrium +temperature changes with time, while the equilibrium pressure remains constant. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_langmuir.png\" alt=\"media_functions_equilibria_pure_langmuir.png\"> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>")); +end Langmuir; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Langmuir/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Langmuir/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5b33869cf15d79cfe321d3ef372972c01c4559b4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Langmuir/package.order @@ -0,0 +1,9 @@ +x_pT +p_xT +dx_dp +dx_dT +ddx_dp_dp +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Sips/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Sips/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..937644f6746d88829eea32c66a6714a547569fc7 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Sips/package.mo @@ -0,0 +1,296 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package Sips "Package containing all functions regarding the Sips isotherm" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents; + + redeclare final function extends x_pT + "Sips isotherm model: Uptake as function of pressure and temperature" + algorithm + x_adsorpt := c[1] * (c[2]*p_adsorpt)^(1/c[3]) / (1 + (c[2]*p_adsorpt)^(1/c[3])) + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Sips.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Sips isotherm model: Pressure as function of uptake and temperature" + algorithm + p_adsorpt := 1/c[2] * (x_adsorpt / (c[1] - x_adsorpt)) ^ c[3] + "Calculation of the equilibrium pressure of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Sips.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dp + "Sips isotherm model: Partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + dx_adsorpt_dp_adsorpt := c[1] * (c[2]*p_adsorpt)^(1/c[3]) / + (c[3] * p_adsorpt * (1 + (c[2]*p_adsorpt)^(1/c[3]))^2) + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure at constant temperature"; + end dx_dp; + + redeclare final function extends dx_dT + "Sips isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = (c[2]*p_adsorpt)^(1/c[3]) / + (1 + (c[2]*p_adsorpt)^(1/c[3])) + "Derivative of uptake w.r.t. to first coefficient of Sips isotherm"; + Real dx_adsorpt_dc2 = c[1] * (c[2]*p_adsorpt)^(1/c[3]) / + (c[2] * c[3] * (1 + (c[2]*p_adsorpt)^(1/c[3]))^2) + "Derivative of uptake w.r.t. to second coefficient of Sips isotherm"; + Real dx_adsorpt_dc3 = -c[1] * (c[2]*p_adsorpt)^(1/c[3]) * log(c[2]*p_adsorpt)/ + (c[3]^2 * (1 + (c[2]*p_adsorpt)^(1/c[3]))^2) + "Derivative of uptake w.r.t. to third coefficient of Sips isotherm"; + + algorithm + dx_adsorpt_dT_adsorpt := + dx_adsorpt_dc1*dc_dT_adsorpt[1] + + dx_adsorpt_dc2*dc_dT_adsorpt[2] + + dx_adsorpt_dc3*dc_dT_adsorpt[3] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dp_dp + "Sips isotherm model: Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + ddx_adsorpt_dp_adsorpt_dp_adsorpt := -(c[1] * (c[2] * p_adsorpt)^(1 / c[3]) * + ((c[3] + 1) * (c[2] * p_adsorpt)^(1 / c[3]) + c[3] - 1)) / + (c[3]^2 * p_adsorpt^2 * ((c[2] * p_adsorpt)^(1 / c[3]) + 1)^3) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure at constant temperature"; + end ddx_dp_dp; + + redeclare final function extends ddx_dT_dT + "Sips isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = (c[2]*p_adsorpt)^(1/c[3]) / + (1 + (c[2]*p_adsorpt)^(1/c[3])) + "Derivative of uptake w.r.t. to first coefficient of Sips isotherm"; + Real dx_adsorpt_dc2 = c[1] * (c[2]*p_adsorpt)^(1/c[3]) / + (c[2] * c[3] * (1 + (c[2]*p_adsorpt)^(1/c[3]))^2) + "Derivative of uptake w.r.t. to second coefficient of Sips isotherm"; + Real dx_adsorpt_dc3 = -c[1] * (c[2]*p_adsorpt)^(1/c[3]) * log(c[2]*p_adsorpt)/ + (c[3]^2 * (1 + (c[2]*p_adsorpt)^(1/c[3]))^2) + "Derivative of uptake w.r.t. to third coefficient of Sips isotherm"; + + Real ddx_adsorpt_dc1_dc2 = (c[2]*p_adsorpt)^(1/c[3]) / + (c[3] * c[2] * (1 + (c[2]*p_adsorpt)^(1/c[3]))^2) + "Second-order partial derivative of uptake w.r.t. to first and second + coefficient of Sips isotherm"; + Real ddx_adsorpt_dc1_dc3 = -(c[2]*p_adsorpt)^(1/c[3]) * log(c[2]*p_adsorpt) / + ((1 + (c[2]*p_adsorpt)^(1/c[3]))^2 * c[3]^2) + "Second-order partial derivative of uptake w.r.t. to first and third + coefficient of Sips isotherm"; + + Real ddx_adsorpt_dc2_dc2 = -c[1] * (c[2]*p_adsorpt)^(1/c[3]) * ((c[3] + 1) * + (c[2]*p_adsorpt)^(1/c[3]) + c[3] - 1) / + (c[2]^2 * c[3]^2 * (1 + (c[2]*p_adsorpt)^(1/c[3]))^3) + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Sips isotherm"; + Real ddx_adsorpt_dc2_dc3 = -(c[1] * (c[2] * p_adsorpt)^(1 / c[3]) * + (((c[2] * p_adsorpt)^(1 / c[3]) + 1) * c[3] - (c[2] * p_adsorpt)^(1 / c[3]) * + log(c[2] * p_adsorpt) + log(c[2] * p_adsorpt))) / + (c[2] * ((c[2] * p_adsorpt)^(1 / c[3]) + 1)^3 * c[3]^3) + "Second-order partial derivative of uptake w.r.t. to second and third + coefficient of Sips isotherm"; + + Real ddx_adsorpt_dc3_dc3 = (c[1] * (c[2] * p_adsorpt)^(1 / c[3]) * log(c[2] * + p_adsorpt) * ((2 * (c[2] * p_adsorpt)^(1 / c[3]) + 2) * + c[3] - (c[2] * p_adsorpt)^(1 / c[3]) * log(c[2] * p_adsorpt) + + log(c[2] * p_adsorpt))) / (((c[2] * p_adsorpt)^(1 / c[3]) + 1)^3 * c[3]^4) + "Second-order partial derivative of uptake w.r.t. to third coefficient of + Sips isotherm"; + + Real ddx_adsorpt_dc1_dT_adsorpt = ddx_adsorpt_dc1_dc2*dc_dT_adsorpt[2] + + ddx_adsorpt_dc1_dc3*dc_dT_adsorpt[3] + "Second-order partial derivative of uptake w.r.t. to first coefficient of + Sips isotherm and temperature"; + Real ddx_adsorpt_dc2_dT_adsorpt = ddx_adsorpt_dc1_dc2*dc_dT_adsorpt[1] + + ddx_adsorpt_dc2_dc2*dc_dT_adsorpt[2] + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[3] + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Sips isotherm and temperature"; + Real ddx_adsorpt_dc3_dT_adsorpt = ddx_adsorpt_dc1_dc3*dc_dT_adsorpt[1] + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[2] + + ddx_adsorpt_dc3_dc3*dc_dT_adsorpt[3] + "Second-order partial derivative of uptake w.r.t. to third coefficient of + Sips isotherm and temperature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + (ddx_adsorpt_dc1_dT_adsorpt*dc_dT_adsorpt[1] + + dx_adsorpt_dc1*ddc_dT_adsorpt_dT_adsorpt[1]) + + (ddx_adsorpt_dc2_dT_adsorpt*dc_dT_adsorpt[2] + + dx_adsorpt_dc2*ddc_dT_adsorpt_dT_adsorpt[2]) + + (ddx_adsorpt_dc3_dT_adsorpt*dc_dT_adsorpt[3] + + dx_adsorpt_dc3*ddc_dT_adsorpt_dT_adsorpt[3]) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Sips isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + Real ddx_adsorpt_dp_adsorpt_dc1 = (c[2]*p_adsorpt)^(1/c[3]) / + ((1 + (c[2]*p_adsorpt)^(1/c[3]))^2 * c[3] * p_adsorpt) + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + first coefficient of Sips isotherm"; + Real ddx_adsorpt_dp_adsorpt_dc2 = -c[1] * (c[2]*p_adsorpt)^(1/c[3]) * + ((c[2]*p_adsorpt)^(1/c[3]) - 1) / + (c[2] * c[3]^2 * p_adsorpt * (1 + (c[2]*p_adsorpt)^(1/c[3]))^3) + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + second coefficient of Sips isotherm"; + Real ddx_adsorpt_dp_adsorpt_dc3 = c[1] * (c[2]*p_adsorpt)^(1/c[3]) * + (((c[2]*p_adsorpt)^(1/c[3]) - 1) * log(c[2]*p_adsorpt) - c[3] * + (c[2]*p_adsorpt)^(1/c[3]) - c[3]) / + (c[3]^3 * p_adsorpt * (1 + (c[2]*p_adsorpt)^(1/c[3]))^3) + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + third coefficient of Sips isotherm"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + ddx_adsorpt_dp_adsorpt_dc1*dc_dT_adsorpt[1] + + ddx_adsorpt_dp_adsorpt_dc2*dc_dT_adsorpt[2] + + ddx_adsorpt_dp_adsorpt_dc3*dc_dT_adsorpt[3] + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare final function extends pi_pT + "Sips isotherm model: Reduced spreading pressure as function of pressure and temperature" + algorithm + pi := 1/M_adsorptive * (c[1]*c[3] * log(1 + (c[2]*p_adsorpt)^(1/c[3]))) + "Calculation of the reduced spreading pressure"; + end pi_pT; + + redeclare final function extends p_piT + "Sips isotherm model: Pressure as function of reduced spreading pressure and temperature" + algorithm + p_adsorpt := (exp(M_adsorptive * pi / (c[1]*c[3])) - 1) ^ c[3] / c[2] + "Calculation of the equilibrium pressure"; + end p_piT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Sips isotherm model is a three-parameter model for calculating the equilibrium +uptake <i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>. +The Sips isotherm model is suitable for type I and II isotherms according to the +IUPAC definition. +</p> + +<h4>Main equations</h4> +<p> +The Sips isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = x<sub>sat</sub>(T<sub>adsorpt</sub>) * (b(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub>) ^ (1/n(T<sub>adsorpt</sub>)) / (1 + (b(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub>) ^ (1/n(T<sub>adsorpt</sub>))); +</pre> +<p> +where <i>x<sub>sat</sub>(T<sub>adsorpt</sub>)</i> is the saturation uptake, +<i>b(T<sub>adsorpt</sub>)</i> is the Sips coefficient, and <i>n(T<sub>adsorpt</sub>)</i> +is the Sips exponent. Typical temperature dependencies may have the following forms: +</p> +</p> +<pre> + x<sub>sat</sub>(T<sub>adsorpt</sub>) = x<sub>ref</sub> * <strong>exp</strong>(Χ * (1 - T<sub>adsorpt</sub>/T<sub>ref</sub>)); +</pre> +<pre> + b(T<sub>adsorpt</sub>) = b<sub>ref</sub> * <strong>exp</strong>(Q/(R * T<sub>ref</sub>) * (T<sub>ref</sub>/T<sub>adsorpt</sub> - 1)); +</pre> +<pre> + n(T<sub>adsorpt</sub>) = (1/n<sub>ref</sub> + α * (1 - T<sub>ref</sub>/T<sub>adsorpt</sub>)) ^ (-1); +</pre> +<p> +where <i>x<sub>ref</sub></i> is the saturation uptake at reference temperature +<i>T<sub>ref</sub></i>, <i>b<sub>ref</sub></i> is the Sips coefficient at reference +temperature, and <i>n<sub>ref</sub></i> is the Sips exponent at reference temperature. +The parameter <i>Q</i> is a measure for the isosteric adsorption enthalpy at a fractional +loading of <i>x<sub>adsorpt</sub>/x<sub>sat</sub>(T<sub>adsorpt</sub>) = 0.5</i>, the +parameter <i>Χ</i> describes the change of the saturation uptake with temperature, +and the parameter <i>α</i> describes the change of the Sips exponent with +temperature. All seven parameters can be used as fitting parameters. +<br/><br/> +Note that the Sips exponent <i>n(T<sub>adsorpt</sub>)</i> is typically greater than +unity. For <i>n(T<sub>adsorpt</sub>) = 1</i>, the Sips isotherm becomes the +Langmuir isotherm. Hence, the Sips exponent <i>n(T<sub>adsorpt</sub>)</i> can be +interpreted as a parameter describing the heterogeneity of the adsorption system. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = x<sub>sat</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[2] = b(T<sub>adsorpt</sub>) in 1/Pa + </li> + <li> + c[3] = n(T<sub>adsorpt</sub>) in - + </li> +</ul> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + No proper Henry law behavior. + </li> +</ul> + +<h4>Typical use</h4> +<p> +The isotherm model is used for type I an II isotherms according to the IUPAC definition. +</p> + +<h4>Example</h4> +<p> +The following figure shows the Sips isotherm model for different parameter sets. +In the upper sub-figure, the equilibrium pressure changes with time, while the +equilibrium temperature remains constant; in the lower sub-figure, the equilibrium +temperature changes with time, while the equilibrium pressure remains constant. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_sips.png\" alt=\"media_functions_equilibria_pure_sips.png\"> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>")); +end Sips; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Sips/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Sips/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5b33869cf15d79cfe321d3ef372972c01c4559b4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Sips/package.order @@ -0,0 +1,9 @@ +x_pT +p_xT +dx_dp +dx_dT +ddx_dp_dp +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..0c0bf45b721ec3b6cbc86017dfd5a92465a833bf --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/Test_changing_pressure.mo @@ -0,0 +1,119 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.BET; +model Test_changing_pressure + "Tester for all functions of the BET isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_mon_ref = 0.15 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0.25 + "Parameter describing the change of the monolayer uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_ref(unit="1/Pa") = 50 + "BET coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q(unit="J/mol") = 35e3 + "Parameter describing the change of the BET coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_cap(unit="J/mol") = 1.5e3 + "Parameter describing extra enthalpy added due to capillary forces at high layers" + annotation (Dialog(tab="General", group="Parameters")); + parameter Integer n = 10 + "Number of layers that can be occupied" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 30, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 5, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BET, + final tolerance_p_inv = 1e-6, + final tolerance_p_pi = 1e-6, + final tolerance_pi = 1e-6, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = x_mon_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[3] = C_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/T_adsorpt - 1)); + c[4] = n+0.1/273.15*T_adsorpt; + c[5] = exp(Q_cap/(Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = -chi/T_ref * c[2]; + dc_dT[3] = -Q/Modelica.Constants.R/T_adsorpt^2 * c[3]; + dc_dT[4] = 0.1/273.15; + dc_dT[5] = -Q_cap/(Modelica.Constants.R*T_adsorpt^2)*c[5]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = -chi/T_ref * dc_dT[2]; + ddc_dT_dT[3] = -1/Modelica.Constants.R/T_adsorpt^2 * + (2*Modelica.Constants.R*T_adsorpt+Q) * dc_dT[3]; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = -1/(Modelica.Constants.R*T_adsorpt^2) * + (2*Modelica.Constants.R*T_adsorpt+Q_cap) * dc_dT[5]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[3] = C_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt+dT) - 1)); + c_pdT[4] = n+0.1/273.15*(T_adsorpt+dT); + c_pdT[5] = exp(Q_cap/(Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[3] = C_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt-dT) - 1)); + c_mdT[4] = n+0.1/273.15*(T_adsorpt-dT); + c_mdT[5] = exp(Q_cap/(Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the BET isotherm models. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..b755b89b236eaf9fad213c835bb4529df46c0af6 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/Test_changing_pressureTemperature.mo @@ -0,0 +1,120 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.BET; +model Test_changing_pressureTemperature + "Tester for all functions of the BET isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_mon_ref = 0.35 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0.25 + "Parameter describing the change of the monolayer uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_ref(unit="1/Pa") = 100 + "BET coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q(unit="J/mol") = 35e3 + "Parameter describing the change of the BET coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_cap(unit="J/mol") = 12.420e3 + "Parameter describing extra enthalpy added due to capillary forces at high layers" + annotation (Dialog(tab="General", group="Parameters")); + parameter Integer n = 10 + "Number of layers that can be occupied" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 300, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 5, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BET, + final tolerance_p_inv = 1e-6, + final tolerance_p_pi = 1e-6, + final tolerance_pi = 1e-6, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = x_mon_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[3] = C_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/T_adsorpt - 1)); + c[4] = n+0.1/273.15*T_adsorpt; + c[5] = exp(Q_cap/(Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = -chi/T_ref * c[2]; + dc_dT[3] = -Q/Modelica.Constants.R/T_adsorpt^2 * c[3]; + dc_dT[4] = 0.1/273.15; + dc_dT[5] = -Q_cap/(Modelica.Constants.R*T_adsorpt^2)*c[5]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = -chi/T_ref * dc_dT[2]; + ddc_dT_dT[3] = -1/Modelica.Constants.R/T_adsorpt^2 * + (2*Modelica.Constants.R*T_adsorpt+Q) * dc_dT[3]; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = -1/(Modelica.Constants.R*T_adsorpt^2) * + (2*Modelica.Constants.R*T_adsorpt+Q_cap) * dc_dT[5]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[3] = C_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt+dT) - 1)); + c_pdT[4] = n+0.1/273.15*(T_adsorpt+dT); + c_pdT[5] = exp(Q_cap/(Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[3] = C_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt-dT) - 1)); + c_mdT[4] = n+0.1/273.15*(T_adsorpt-dT); + c_mdT[5] = exp(Q_cap/(Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the BET isotherm models. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..b1c18b11959f7fb0471271f2e68459a0ecd76cbf --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/Test_changing_temperature.mo @@ -0,0 +1,119 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.BET; +model Test_changing_temperature + "Tester for all functions of the BET isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_mon_ref = 0.15 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0.25 + "Parameter describing the change of the monolayer uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C_ref(unit="1/Pa") = 50 + "BET coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q(unit="J/mol") = 35e3 + "Parameter describing the change of the BET coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q_cap(unit="J/mol") = 1.5e3 + "Parameter describing extra enthalpy added due to capillary forces at high layers" + annotation (Dialog(tab="General", group="Parameters")); + parameter Integer n = 10 + "Number of layers that can be occupied" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 0, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 3000, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 5, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BET, + final tolerance_p_inv = 1e-6, + final tolerance_p_pi = 1e-6, + final tolerance_pi = 1e-6, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = x_mon_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[3] = C_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/T_adsorpt - 1)); + c[4] = n+0.1/273.15*T_adsorpt; + c[5] = exp(Q_cap/(Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = -chi/T_ref * c[2]; + dc_dT[3] = -Q/Modelica.Constants.R/T_adsorpt^2 * c[3]; + dc_dT[4] = 0.1/273.15; + dc_dT[5] = -Q_cap/(Modelica.Constants.R*T_adsorpt^2)*c[5]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = -chi/T_ref * dc_dT[2]; + ddc_dT_dT[3] = -1/Modelica.Constants.R/T_adsorpt^2 * + (2*Modelica.Constants.R*T_adsorpt+Q) * dc_dT[3]; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = -1/(Modelica.Constants.R*T_adsorpt^2) * + (2*Modelica.Constants.R*T_adsorpt+Q_cap) * dc_dT[5]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[3] = C_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt+dT) - 1)); + c_pdT[4] = n+0.1/273.15*(T_adsorpt+dT); + c_pdT[5] = exp(Q_cap/(Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[3] = C_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt-dT) - 1)); + c_mdT[4] = n+0.1/273.15*(T_adsorpt-dT); + c_mdT[5] = exp(Q_cap/(Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the BET isotherm models. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..104892dfe7881ebf3849e1d944266d2e43e3d00d --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package BET "Models to test and varify functions of the BET isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the BET isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BET; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BET/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..6cbbb76b38069c6b67f6bc2e4fa20da5f50d8125 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/Test_changing_pressure.mo @@ -0,0 +1,112 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.BiLangmuir; +model Test_changing_pressure + "Tester for all functions of the Bi-Langmuir isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake a0_1 = 0.35 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake a0_2 = 0.45 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1_1(unit="kg.K/kg") = 1e-4 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1_2(unit="kg.K/kg") = 2e-4 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0_1(unit="1/Pa") = 5e-8 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0_2(unit="1/Pa") = 6e-8 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Delta_H_ads_1(unit="J/mol") = -2e4 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Delta_H_ads_2(unit="J/mol") = -2.5e4 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 1000, + final T_adsorpt_der = 0, + final p_adsorpt_start = 0, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.044, + final no_coefficients = 4, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = a0_1 + a1_1/T_adsorpt; + c[2] = b0_1*exp(-Delta_H_ads_1/(Modelica.Constants.R*T_adsorpt)); + c[3] = a0_2 + a1_2/T_adsorpt; + c[4] = b0_2*exp(-Delta_H_ads_2/(Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -a1_1/T_adsorpt^2; + dc_dT[2] = Delta_H_ads_1/(Modelica.Constants.R*T_adsorpt^2) * c[2]; + dc_dT[3] = -a1_2/T_adsorpt^2; + dc_dT[4] = Delta_H_ads_2/(Modelica.Constants.R*T_adsorpt^2) * c[4]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -2*dc_dT[1]/T_adsorpt; + ddc_dT_dT[2] = -(2*Modelica.Constants.R*T_adsorpt - Delta_H_ads_1) / + (Modelica.Constants.R*T_adsorpt^2) * dc_dT[2]; + ddc_dT_dT[3] = -2*dc_dT[3]/T_adsorpt; + ddc_dT_dT[4] = -(2*Modelica.Constants.R*T_adsorpt - Delta_H_ads_2) / + (Modelica.Constants.R*T_adsorpt^2) * dc_dT[4]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = a0_1 + a1_1/(T_adsorpt+dT); + c_pdT[2] = b0_1*exp(-Delta_H_ads_1/(Modelica.Constants.R*(T_adsorpt+dT))); + c_pdT[3] = a0_2 + a1_2/(T_adsorpt+dT); + c_pdT[4] = b0_2*exp(-Delta_H_ads_2/(Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = a0_1 + a1_1/(T_adsorpt-dT); + c_mdT[2] = b0_1*exp(-Delta_H_ads_1/(Modelica.Constants.R*(T_adsorpt-dT))); + c_mdT[3] = a0_2 + a1_2/(T_adsorpt-dT); + c_mdT[4] = b0_2*exp(-Delta_H_ads_2/(Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Bi-Langmuir isotherm model. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..dd2c9a3af7bd7d8dbb7b34fe94c93ae5d5c15929 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/Test_changing_pressureTemperature.mo @@ -0,0 +1,113 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.BiLangmuir; +model Test_changing_pressureTemperature + "Tester for all functions of the Bi-Langmuir isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake a0_1 = 0.35 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake a0_2 = 0.45 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1_1(unit="kg.K/kg") = 1e-4 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1_2(unit="kg.K/kg") = 2e-4 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0_1(unit="1/Pa") = 5e-8 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0_2(unit="1/Pa") = 6e-8 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Delta_H_ads_1(unit="J/mol") = -2e4 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Delta_H_ads_2(unit="J/mol") = -2.5e4 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 1000, + final T_adsorpt_der = 1.5, + final p_adsorpt_start = 0, + final T_adsorpt_start = 273.15, + final M_adsorptive = 0.044, + final no_coefficients = 4, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = a0_1 + a1_1/T_adsorpt; + c[2] = b0_1*exp(-Delta_H_ads_1/(Modelica.Constants.R*T_adsorpt)); + c[3] = a0_2 + a1_2/T_adsorpt; + c[4] = b0_2*exp(-Delta_H_ads_2/(Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -a1_1/T_adsorpt^2; + dc_dT[2] = Delta_H_ads_1/(Modelica.Constants.R*T_adsorpt^2) * c[2]; + dc_dT[3] = -a1_2/T_adsorpt^2; + dc_dT[4] = Delta_H_ads_2/(Modelica.Constants.R*T_adsorpt^2) * c[4]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -2*dc_dT[1]/T_adsorpt; + ddc_dT_dT[2] = -(2*Modelica.Constants.R*T_adsorpt - Delta_H_ads_1) / + (Modelica.Constants.R*T_adsorpt^2) * dc_dT[2]; + ddc_dT_dT[3] = -2*dc_dT[3]/T_adsorpt; + ddc_dT_dT[4] = -(2*Modelica.Constants.R*T_adsorpt - Delta_H_ads_2) / + (Modelica.Constants.R*T_adsorpt^2) * dc_dT[4]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = a0_1 + a1_1/(T_adsorpt+dT); + c_pdT[2] = b0_1*exp(-Delta_H_ads_1/(Modelica.Constants.R*(T_adsorpt+dT))); + c_pdT[3] = a0_2 + a1_2/(T_adsorpt+dT); + c_pdT[4] = b0_2*exp(-Delta_H_ads_2/(Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = a0_1 + a1_1/(T_adsorpt-dT); + c_mdT[2] = b0_1*exp(-Delta_H_ads_1/(Modelica.Constants.R*(T_adsorpt-dT))); + c_mdT[3] = a0_2 + a1_2/(T_adsorpt-dT); + c_mdT[4] = b0_2*exp(-Delta_H_ads_2/(Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Bi-Langmuir isotherm model. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..2c4fbfbc20920adf783bbb1281129b8c5410acad --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/Test_changing_temperature.mo @@ -0,0 +1,112 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.BiLangmuir; +model Test_changing_temperature + "Tester for all functions of the Bi-Langmuir isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake a0_1 = 0.35 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.Uptake a0_2 = 0.45 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1_1(unit="kg.K/kg") = 1e-4 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1_2(unit="kg.K/kg") = 2e-4 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0_1(unit="1/Pa") = 5e-8 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0_2(unit="1/Pa") = 6e-8 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Delta_H_ads_1(unit="J/mol") = -2e4 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Delta_H_ads_2(unit="J/mol") = -2.5e4 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 0, + final T_adsorpt_der = 1, + final p_adsorpt_start = 1000, + final T_adsorpt_start = 273.15, + final M_adsorptive = 0.044, + final no_coefficients = 4, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.BiLangmuir, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = a0_1 + a1_1/T_adsorpt; + c[2] = b0_1*exp(-Delta_H_ads_1/(Modelica.Constants.R*T_adsorpt)); + c[3] = a0_2 + a1_2/T_adsorpt; + c[4] = b0_2*exp(-Delta_H_ads_2/(Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -a1_1/T_adsorpt^2; + dc_dT[2] = Delta_H_ads_1/(Modelica.Constants.R*T_adsorpt^2) * c[2]; + dc_dT[3] = -a1_2/T_adsorpt^2; + dc_dT[4] = Delta_H_ads_2/(Modelica.Constants.R*T_adsorpt^2) * c[4]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -2*dc_dT[1]/T_adsorpt; + ddc_dT_dT[2] = -(2*Modelica.Constants.R*T_adsorpt - Delta_H_ads_1) / + (Modelica.Constants.R*T_adsorpt^2) * dc_dT[2]; + ddc_dT_dT[3] = -2*dc_dT[3]/T_adsorpt; + ddc_dT_dT[4] = -(2*Modelica.Constants.R*T_adsorpt - Delta_H_ads_2) / + (Modelica.Constants.R*T_adsorpt^2) * dc_dT[4]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = a0_1 + a1_1/(T_adsorpt+dT); + c_pdT[2] = b0_1*exp(-Delta_H_ads_1/(Modelica.Constants.R*(T_adsorpt+dT))); + c_pdT[3] = a0_2 + a1_2/(T_adsorpt+dT); + c_pdT[4] = b0_2*exp(-Delta_H_ads_2/(Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = a0_1 + a1_1/(T_adsorpt-dT); + c_mdT[2] = b0_1*exp(-Delta_H_ads_1/(Modelica.Constants.R*(T_adsorpt-dT))); + c_mdT[3] = a0_2 + a1_2/(T_adsorpt-dT); + c_mdT[4] = b0_2*exp(-Delta_H_ads_2/(Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Bi-Langmuir isotherm model. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..653d630992d82ae377f7392c5b10121d312b43ce --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package BiLangmuir "Models to test and varify functions of the Bi-Langmuir isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Bi-Langmuir isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BiLangmuir; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/BiLangmuir/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..7b3ad39d375843134b9743d3d01a220ce378381e --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/Test_changing_pressure.mo @@ -0,0 +1,110 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininAstakhov; +model Test_changing_pressure + "Tester for all functions of the Dubinin-Astakhov isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume W_0 = 4.32e-4 + "Maximum filled pore volume" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real E(unit="J/mol") = 2.364e3 + "Characteristic energy" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real n(unit="1") = 2.283 + "Parameter describing the heterogenity of the system" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 25, + final T_adsorpt_der = 0, + final p_adsorpt_start = 400, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 5, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov, + final p_lb_pi=Modelica.Constants.small, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = W_0+T_adsorpt/273.15*1e-4; + c[4] = E+1*T_adsorpt; + c[5] = n+T_adsorpt/273.15; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = 1e-4/273.15; + dc_dT[4] = 1; + dc_dT[5] = 1/273.15; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = 0; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = W_0+(T_adsorpt+dT)/273.15*1e-4; + c_pdT[4] = E+1*(T_adsorpt+dT); + c_pdT[5] = n+(T_adsorpt+dT)/273.15; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = W_0+(T_adsorpt-dT)/273.15*1e-4; + c_mdT[4] = E+1*(T_adsorpt-dT); + c_mdT[5] = n+(T_adsorpt-dT)/273.15; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Astakhov isotherm models. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..91235d24ac38e50ba0fab3eca2388e6d04993504 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/Test_changing_pressureTemperature.mo @@ -0,0 +1,111 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininAstakhov; +model Test_changing_pressureTemperature + "Tester for all functions of the Dubinin-Astakhov isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume W_0 = 4.32e-4 + "Maximum filled pore volume" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real E(unit="J/mol") = 2.364e3 + "Characteristic energy" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real n(unit="1") = 2.283 + "Parameter describing the heterogenity of the system" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 300, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 400, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 5, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov, + final p_lb_pi=Modelica.Constants.small, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = W_0+T_adsorpt/273.15*1e-4; + c[4] = E+1*T_adsorpt; + c[5] = n+T_adsorpt/273.15; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = 1e-4/273.15; + dc_dT[4] = 1; + dc_dT[5] = 1/273.15; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = 0; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = W_0+(T_adsorpt+dT)/273.15*1e-4; + c_pdT[4] = E+1*(T_adsorpt+dT); + c_pdT[5] = n+(T_adsorpt+dT)/273.15; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = W_0+(T_adsorpt-dT)/273.15*1e-4; + c_mdT[4] = E+1*(T_adsorpt-dT); + c_mdT[5] = n+(T_adsorpt-dT)/273.15; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Astakhov isotherm models. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..1851b0d5a3c2df3fbdbdd82435155633dbf00116 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/Test_changing_temperature.mo @@ -0,0 +1,110 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininAstakhov; +model Test_changing_temperature + "Tester for all functions of the Dubinin-Astakhov isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume W_0 = 4.32e-4 + "Maximum filled pore volume" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real E(unit="J/mol") = 2.364e3 + "Characteristic energy" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real n(unit="1") = 2.283 + "Parameter describing the heterogenity of the system" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 0, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1000, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 5, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininAstakhov, + final p_lb_pi=Modelica.Constants.small, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = W_0+T_adsorpt/273.15*1e-4; + c[4] = E+1*T_adsorpt; + c[5] = n+T_adsorpt/273.15; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = 1e-4/273.15; + dc_dT[4] = 1; + dc_dT[5] = 1/273.15; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = 0; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = W_0+(T_adsorpt+dT)/273.15*1e-4; + c_pdT[4] = E+1*(T_adsorpt+dT); + c_pdT[5] = n+(T_adsorpt+dT)/273.15; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = W_0+(T_adsorpt-dT)/273.15*1e-4; + c_mdT[4] = E+1*(T_adsorpt-dT); + c_mdT[5] = n+(T_adsorpt-dT)/273.15; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Astakhov isotherm models. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b82ab65ead12f27f74b50701fdd9d2a34bf61829 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package DubininAstakhov "Models to test and varify functions of the Dubinin-Astakhov isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Dubinin-Astakhov isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end DubininAstakhov; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininAstakhov/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..ddbcb244126d7fadf1970a840ebd95d768ec9326 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/Test_changing_pressure.mo @@ -0,0 +1,162 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininChebyshevSeriesRaionalOrder33; +model Test_changing_pressure + "Tester for all functions of the Dubinin-Chebyshev-Series-3/3 isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 3.472616e-2 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b = 1.322831 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_c = 9.401171e-3 / 1000 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_d = 5.760414e-1 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_e = 1.350676e-3 / 1000 + "Fivth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_f = 1.313913e-1 + "Sixth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_g(min=-1) = -1.926730e-4 / 1000 + "Seventh fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.MolarAdsorptionPotential char_curve_h = 1061.930 * 1000 * 0.018 + "Ninth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.MolarAdsorptionPotential char_curve_i = 1065.595 * 1000 * 0.018 + "Tenth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 30, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1e-2, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 11, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33, + final p_lb_pi=1e-2, + final tolerance_p_pi=1e-6, + final tolerance_pi=1e-6, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-10*T_adsorpt^2; + c[4] = char_curve_b-1e-10*T_adsorpt^2; + c[5] = char_curve_c-1e-10*T_adsorpt^2; + c[6] = char_curve_d-1e-10*T_adsorpt^2; + c[7] = char_curve_e-1e-10*T_adsorpt^2; + c[8] = char_curve_f-1e-10*T_adsorpt^2; + c[9] = char_curve_g-1e-10*T_adsorpt^2; + c[10] = char_curve_h-1e-10*T_adsorpt^2; + c[11] = char_curve_i-1e-10*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-10*T_adsorpt; + dc_dT[4] = -2*1e-10*T_adsorpt; + dc_dT[5] = -2*1e-10*T_adsorpt; + dc_dT[6] = -2*1e-10*T_adsorpt; + dc_dT[7] = -2*1e-10*T_adsorpt; + dc_dT[8] = -2*1e-10*T_adsorpt; + dc_dT[9] = -2*1e-10*T_adsorpt; + dc_dT[10] = -2*1e-10*T_adsorpt; + dc_dT[11] = -2*1e-10*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-10; + ddc_dT_dT[4] = -2*1e-10; + ddc_dT_dT[5] = -2*1e-10; + ddc_dT_dT[6] = -2*1e-10; + ddc_dT_dT[7] = -2*1e-10; + ddc_dT_dT[8] = -2*1e-10; + ddc_dT_dT[9] = -2*1e-10; + ddc_dT_dT[10] = -2*1e-10; + ddc_dT_dT[11] = -2*1e-10; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-10*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b-1e-10*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-10*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-10*(T_adsorpt+dT)^2; + c_pdT[7] = char_curve_e-1e-10*(T_adsorpt+dT)^2; + c_pdT[8] = char_curve_f-1e-10*(T_adsorpt+dT)^2; + c_pdT[9] = char_curve_g-1e-10*(T_adsorpt+dT)^2; + c_pdT[10] = char_curve_h-1e-10*(T_adsorpt+dT)^2; + c_pdT[11] = char_curve_i-1e-10*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-10*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b-1e-10*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-10*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-10*(T_adsorpt-dT)^2; + c_mdT[7] = char_curve_e-1e-10*(T_adsorpt-dT)^2; + c_mdT[8] = char_curve_f-1e-10*(T_adsorpt-dT)^2; + c_mdT[9] = char_curve_g-1e-10*(T_adsorpt-dT)^2; + c_mdT[10] = char_curve_h-1e-10*(T_adsorpt-dT)^2; + c_mdT[11] = char_curve_i-1e-10*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment( + StopTime=100, + Interval=0.01, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Chebyshev-Series-3/3 +isotherm models. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..64ebdca7a8055617b9c2a9c716591b655a09d700 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/Test_changing_pressureTemperature.mo @@ -0,0 +1,163 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininChebyshevSeriesRaionalOrder33; +model Test_changing_pressureTemperature + "Tester for all functions of the Dubinin-Chebyshev-Series-3/3 isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 3.472616e-2 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b = 1.322831 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_c = 9.401171e-3 / 1000 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_d = 5.760414e-1 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_e = 1.350676e-3 / 1000 + "Fivth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_f = 1.313913e-1 + "Sixth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_g(min=-1) = -1.926730e-4 / 1000 + "Seventh fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.MolarAdsorptionPotential char_curve_h = 1061.930 * 1000 * 0.018 + "Ninth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.MolarAdsorptionPotential char_curve_i = 1065.595 * 1000 * 0.018 + "Tenth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 300, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1e-2, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 11, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33, + final p_lb_pi=1e-2, + final tolerance_p_pi=1e-6, + final tolerance_pi=1e-6, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-10*T_adsorpt^2; + c[4] = char_curve_b-1e-10*T_adsorpt^2; + c[5] = char_curve_c-1e-10*T_adsorpt^2; + c[6] = char_curve_d-1e-10*T_adsorpt^2; + c[7] = char_curve_e-1e-10*T_adsorpt^2; + c[8] = char_curve_f-1e-10*T_adsorpt^2; + c[9] = char_curve_g-1e-10*T_adsorpt^2; + c[10] = char_curve_h-1e-10*T_adsorpt^2; + c[11] = char_curve_i-1e-10*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-10*T_adsorpt; + dc_dT[4] = -2*1e-10*T_adsorpt; + dc_dT[5] = -2*1e-10*T_adsorpt; + dc_dT[6] = -2*1e-10*T_adsorpt; + dc_dT[7] = -2*1e-10*T_adsorpt; + dc_dT[8] = -2*1e-10*T_adsorpt; + dc_dT[9] = -2*1e-10*T_adsorpt; + dc_dT[10] = -2*1e-10*T_adsorpt; + dc_dT[11] = -2*1e-10*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-10; + ddc_dT_dT[4] = -2*1e-10; + ddc_dT_dT[5] = -2*1e-10; + ddc_dT_dT[6] = -2*1e-10; + ddc_dT_dT[7] = -2*1e-10; + ddc_dT_dT[8] = -2*1e-10; + ddc_dT_dT[9] = -2*1e-10; + ddc_dT_dT[10] = -2*1e-10; + ddc_dT_dT[11] = -2*1e-10; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-10*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b-1e-10*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-10*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-10*(T_adsorpt+dT)^2; + c_pdT[7] = char_curve_e-1e-10*(T_adsorpt+dT)^2; + c_pdT[8] = char_curve_f-1e-10*(T_adsorpt+dT)^2; + c_pdT[9] = char_curve_g-1e-10*(T_adsorpt+dT)^2; + c_pdT[10] = char_curve_h-1e-10*(T_adsorpt+dT)^2; + c_pdT[11] = char_curve_i-1e-10*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-10*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b-1e-10*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-10*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-10*(T_adsorpt-dT)^2; + c_mdT[7] = char_curve_e-1e-10*(T_adsorpt-dT)^2; + c_mdT[8] = char_curve_f-1e-10*(T_adsorpt-dT)^2; + c_mdT[9] = char_curve_g-1e-10*(T_adsorpt-dT)^2; + c_mdT[10] = char_curve_h-1e-10*(T_adsorpt-dT)^2; + c_mdT[11] = char_curve_i-1e-10*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment( + StopTime=100, + Interval=0.01, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Chebyshev-Series-3/3 +isotherm models. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..eaf37ad034d0c5589f0488e4337b7765f22490f7 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/Test_changing_temperature.mo @@ -0,0 +1,162 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininChebyshevSeriesRaionalOrder33; +model Test_changing_temperature + "Tester for all functions of the Dubinin-Chebyshev-Series-3/3 isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 3.472616e-2 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b = 1.322831 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_c = 9.401171e-3 / 1000 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_d = 5.760414e-1 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_e = 1.350676e-3 / 1000 + "Fivth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_f = 1.313913e-1 + "Sixth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_g(min=-1) = -1.926730e-4 / 1000 + "Seventh fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.MolarAdsorptionPotential char_curve_h = 1061.930 * 1000 * 0.018 + "Ninth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.MolarAdsorptionPotential char_curve_i = 1065.595 * 1000 * 0.018 + "Tenth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 0, + final T_adsorpt_der = 40/100, + final p_adsorpt_start = 10000, + final T_adsorpt_start = 323.15, + final M_adsorptive = 0.018, + final no_coefficients = 11, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininChebyshevSeriesRaionalOrder33, + final p_lb_pi=1e-2, + final tolerance_p_pi=1e-6, + final tolerance_pi=1e-6, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-10*T_adsorpt^2; + c[4] = char_curve_b-1e-10*T_adsorpt^2; + c[5] = char_curve_c-1e-10*T_adsorpt^2; + c[6] = char_curve_d-1e-10*T_adsorpt^2; + c[7] = char_curve_e-1e-10*T_adsorpt^2; + c[8] = char_curve_f-1e-10*T_adsorpt^2; + c[9] = char_curve_g-1e-10*T_adsorpt^2; + c[10] = char_curve_h-1e-10*T_adsorpt^2; + c[11] = char_curve_i-1e-10*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-10*T_adsorpt; + dc_dT[4] = -2*1e-10*T_adsorpt; + dc_dT[5] = -2*1e-10*T_adsorpt; + dc_dT[6] = -2*1e-10*T_adsorpt; + dc_dT[7] = -2*1e-10*T_adsorpt; + dc_dT[8] = -2*1e-10*T_adsorpt; + dc_dT[9] = -2*1e-10*T_adsorpt; + dc_dT[10] = -2*1e-10*T_adsorpt; + dc_dT[11] = -2*1e-10*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-10; + ddc_dT_dT[4] = -2*1e-10; + ddc_dT_dT[5] = -2*1e-10; + ddc_dT_dT[6] = -2*1e-10; + ddc_dT_dT[7] = -2*1e-10; + ddc_dT_dT[8] = -2*1e-10; + ddc_dT_dT[9] = -2*1e-10; + ddc_dT_dT[10] = -2*1e-10; + ddc_dT_dT[11] = -2*1e-10; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-10*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b-1e-10*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-10*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-10*(T_adsorpt+dT)^2; + c_pdT[7] = char_curve_e-1e-10*(T_adsorpt+dT)^2; + c_pdT[8] = char_curve_f-1e-10*(T_adsorpt+dT)^2; + c_pdT[9] = char_curve_g-1e-10*(T_adsorpt+dT)^2; + c_pdT[10] = char_curve_h-1e-10*(T_adsorpt+dT)^2; + c_pdT[11] = char_curve_i-1e-10*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-10*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b-1e-10*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-10*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-10*(T_adsorpt-dT)^2; + c_mdT[7] = char_curve_e-1e-10*(T_adsorpt-dT)^2; + c_mdT[8] = char_curve_f-1e-10*(T_adsorpt-dT)^2; + c_mdT[9] = char_curve_g-1e-10*(T_adsorpt-dT)^2; + c_mdT[10] = char_curve_h-1e-10*(T_adsorpt-dT)^2; + c_mdT[11] = char_curve_i-1e-10*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment( + StopTime=100, + Interval=0.01, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Chebyshev-Series-3/3 +isotherm models. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..8d8f8a01ae0467f05095ef8c07246d1d8ef806ba --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package DubininChebyshevSeriesRaionalOrder33 "Models to test and varify functions of the Dubinin-Chebyshev-Series-3/3 isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Dubinin-Chebyshev series 3/3 isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end DubininChebyshevSeriesRaionalOrder33; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininChebyshevSeriesRaionalOrder33/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..817b6bbb1feee36e619a81894805e94a7a1835d8 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/Test_changing_pressure.mo @@ -0,0 +1,121 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininEmpirical1; +model Test_changing_pressure + "Tester for all functions of the Dubinin-Empirical-1 isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 3.570644 * 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b = 8.569149e-6 * 1000 * (1 / 1000 / 0.018)^2 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c = 1 / 1000 / 0.018 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_d = 9.597209e-8 * 1000 * (1 / 1000 / 0.018)^3 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 30, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1e-2, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1, + final p_lb_pi=1e-12, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-14*T_adsorpt^2; + c[4] = char_curve_b-1e-14*T_adsorpt^2; + c[5] = char_curve_c-1e-14*T_adsorpt^2; + c[6] = char_curve_d-1e-14*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-14*T_adsorpt; + dc_dT[4] = -2*1e-14*T_adsorpt; + dc_dT[5] = -2*1e-14*T_adsorpt; + dc_dT[6] = -2*1e-14*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-14; + ddc_dT_dT[4] = -2*1e-14; + ddc_dT_dT[5] = -2*1e-14; + ddc_dT_dT[6] = -2*1e-14; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-14*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b-1e-14*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-14*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-14*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-14*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b-1e-14*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-14*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-14*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment( + StopTime=100, + Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 3, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Empirical-1 +isotherm model. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..7f7c774d95ec60e7b62b553ffd978e03702ef4d6 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/Test_changing_pressureTemperature.mo @@ -0,0 +1,122 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininEmpirical1; +model Test_changing_pressureTemperature + "Tester for all functions of the Dubinin-Empirical-1 isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 3.570644 * 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b = 8.569149e-6 * 1000 * (1 / 1000 / 0.018)^2 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c = 1 / 1000 / 0.018 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_d = 9.597209e-8 * 1000 * (1 / 1000 / 0.018)^3 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 300, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1e-2, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1, + final p_lb_pi=1e-12, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-14*T_adsorpt^2; + c[4] = char_curve_b-1e-14*T_adsorpt^2; + c[5] = char_curve_c-1e-14*T_adsorpt^2; + c[6] = char_curve_d-1e-14*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-14*T_adsorpt; + dc_dT[4] = -2*1e-14*T_adsorpt; + dc_dT[5] = -2*1e-14*T_adsorpt; + dc_dT[6] = -2*1e-14*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-14; + ddc_dT_dT[4] = -2*1e-14; + ddc_dT_dT[5] = -2*1e-14; + ddc_dT_dT[6] = -2*1e-14; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-14*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b-1e-14*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-14*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-14*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-14*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b-1e-14*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-14*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-14*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment( + StopTime=100, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 3, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Empirical-1 +isotherm model. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..a1579158e52d9a2671c07df27a9d1c294ea3fefc --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/Test_changing_temperature.mo @@ -0,0 +1,121 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininEmpirical1; +model Test_changing_temperature + "Tester for all functions of the Dubinin-Empirical-1 isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 3.570644 * 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b = 8.569149e-6 * 1000 * (1 / 1000 / 0.018)^2 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c = 1 / 1000 / 0.018 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_d = 9.597209e-8 * 1000 * (1 / 1000 / 0.018)^3 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 0, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1000, + final T_adsorpt_start = 293.15, + final M_adsorptive = 0.018, + final no_coefficients = 6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1, + final p_lb_pi=1e-12, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-14*T_adsorpt^2; + c[4] = char_curve_b-1e-14*T_adsorpt^2; + c[5] = char_curve_c-1e-14*T_adsorpt^2; + c[6] = char_curve_d-1e-14*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-14*T_adsorpt; + dc_dT[4] = -2*1e-14*T_adsorpt; + dc_dT[5] = -2*1e-14*T_adsorpt; + dc_dT[6] = -2*1e-14*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-14; + ddc_dT_dT[4] = -2*1e-14; + ddc_dT_dT[5] = -2*1e-14; + ddc_dT_dT[6] = -2*1e-14; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-14*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b-1e-14*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-14*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-14*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-14*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b-1e-14*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-14*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-14*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment( + StopTime=100, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 3, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Empirical-1 +isotherm model. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b8ecc0b1fa6bee0cce2db9c3fb523f353bb28f85 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package DubininEmpirical1 "Models to test and varify functions of the Dubinin-Empirical-1 isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Dubinin-Empirical-1 +isotherm model. The test models check the implementation of the functions and enable +verification of the function behavior. Three test models are implemented, in which +the pressure and temperature change over time. In addition, the test models demonstrate +the functions' general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end DubininEmpirical1; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical1/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..92028600aed87dd975553498a1afd9b376a29b10 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/Test_changing_pressure.mo @@ -0,0 +1,145 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininEmpirical2; +model Test_changing_pressure + "Tester for all functions of the Dubinin-Empirical-2 isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 3.083531e-1 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b = -5.415506e-2 * sqrt(1 / 1000 / 0.018) + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c = -1.969937e-2 / 1000 * sqrt(1 / 1000 / 0.018) + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_d = 8.174501e-4 / 1000 / 0.018 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_e = 4.362905e-4 / 1000 / 1000 / 0.018 + "Fifth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_f = 2.339058e-6 / 1000 / 0.018 * sqrt(1 / 1000 / 0.018) + "Sixth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_g = -3.199002e-6 / 1000 / 1000 / 0.018 * sqrt(1 / 1000 / 0.018) + "Seventh fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 30, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1e-2, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 9, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2, + final p_lb_pi=1e-12, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-14*T_adsorpt^2; + c[4] = char_curve_b+1e-14*T_adsorpt^2; + c[5] = char_curve_c-1e-14*T_adsorpt^2; + c[6] = char_curve_d+1e-14*T_adsorpt^2; + c[7] = char_curve_e-1e-18*T_adsorpt^2; + c[8] = char_curve_f+1e-14*T_adsorpt^2; + c[9] = char_curve_g-1e-18*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-14*T_adsorpt; + dc_dT[4] = +2*1e-14*T_adsorpt; + dc_dT[5] = -2*1e-14*T_adsorpt; + dc_dT[6] = +2*1e-14*T_adsorpt; + dc_dT[7] = -2*1e-18*T_adsorpt; + dc_dT[8] = +2*1e-14*T_adsorpt; + dc_dT[9] = -2*1e-18*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-14; + ddc_dT_dT[4] = +2*1e-14; + ddc_dT_dT[5] = -2*1e-14; + ddc_dT_dT[6] = +2*1e-14; + ddc_dT_dT[7] = -2*1e-18; + ddc_dT_dT[8] = +2*1e-14; + ddc_dT_dT[9] = -2*1e-18; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-14*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b+1e-14*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-14*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d+1e-14*(T_adsorpt+dT)^2; + c_pdT[7] = char_curve_e-1e-18*(T_adsorpt+dT)^2; + c_pdT[8] = char_curve_f+1e-14*(T_adsorpt+dT)^2; + c_pdT[9] = char_curve_g-1e-18*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-14*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b+1e-14*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-14*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d+1e-14*(T_adsorpt-dT)^2; + c_mdT[7] = char_curve_e-1e-18*(T_adsorpt-dT)^2; + c_mdT[8] = char_curve_f+1e-14*(T_adsorpt-dT)^2; + c_mdT[9] = char_curve_g-1e-18*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment( + StopTime=100, + Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 6, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Empirical-2 +isotherm model. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..8c770b7ca3e367fd41fe9cad3d8d4f9f44b97a99 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/Test_changing_pressureTemperature.mo @@ -0,0 +1,146 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininEmpirical2; +model Test_changing_pressureTemperature + "Tester for all functions of the Dubinin-Empirical-2 isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 3.083531e-1 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b = -5.415506e-2 * sqrt(1 / 1000 / 0.018) + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c = -1.969937e-2 / 1000 * sqrt(1 / 1000 / 0.018) + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_d = 8.174501e-4 / 1000 / 0.018 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_e = 4.362905e-4 / 1000 / 1000 / 0.018 + "Fifth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_f = 2.339058e-6 / 1000 / 0.018 * sqrt(1 / 1000 / 0.018) + "Sixth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_g = -3.199002e-6 / 1000 / 1000 / 0.018 * sqrt(1 / 1000 / 0.018) + "Seventh fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 300, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1e-2, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 9, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2, + final p_lb_pi=1e-12, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-14*T_adsorpt^2; + c[4] = char_curve_b+1e-14*T_adsorpt^2; + c[5] = char_curve_c-1e-14*T_adsorpt^2; + c[6] = char_curve_d+1e-14*T_adsorpt^2; + c[7] = char_curve_e-1e-18*T_adsorpt^2; + c[8] = char_curve_f+1e-14*T_adsorpt^2; + c[9] = char_curve_g-1e-18*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-14*T_adsorpt; + dc_dT[4] = +2*1e-14*T_adsorpt; + dc_dT[5] = -2*1e-14*T_adsorpt; + dc_dT[6] = +2*1e-14*T_adsorpt; + dc_dT[7] = -2*1e-18*T_adsorpt; + dc_dT[8] = +2*1e-14*T_adsorpt; + dc_dT[9] = -2*1e-18*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-14; + ddc_dT_dT[4] = +2*1e-14; + ddc_dT_dT[5] = -2*1e-14; + ddc_dT_dT[6] = +2*1e-14; + ddc_dT_dT[7] = -2*1e-18; + ddc_dT_dT[8] = +2*1e-14; + ddc_dT_dT[9] = -2*1e-18; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-14*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b+1e-14*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-14*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d+1e-14*(T_adsorpt+dT)^2; + c_pdT[7] = char_curve_e-1e-18*(T_adsorpt+dT)^2; + c_pdT[8] = char_curve_f+1e-14*(T_adsorpt+dT)^2; + c_pdT[9] = char_curve_g-1e-18*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-14*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b+1e-14*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-14*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d+1e-14*(T_adsorpt-dT)^2; + c_mdT[7] = char_curve_e-1e-18*(T_adsorpt-dT)^2; + c_mdT[8] = char_curve_f+1e-14*(T_adsorpt-dT)^2; + c_mdT[9] = char_curve_g-1e-18*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment( + StopTime=100, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 6, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Empirical-2 +isotherm model. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..b646714fe84808f9db97bad8c6a32042cf85df4c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/Test_changing_temperature.mo @@ -0,0 +1,145 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininEmpirical2; +model Test_changing_temperature + "Tester for all functions of the Dubinin-Empirical-2 isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 3.083531e-1 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b = -5.415506e-2 * sqrt(1 / 1000 / 0.018) + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c = -1.969937e-2 / 1000 * sqrt(1 / 1000 / 0.018) + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_d = 8.174501e-4 / 1000 / 0.018 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_e = 4.362905e-4 / 1000 / 1000 / 0.018 + "Fifth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_f = 2.339058e-6 / 1000 / 0.018 * sqrt(1 / 1000 / 0.018) + "Sixth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_g = -3.199002e-6 / 1000 / 1000 / 0.018 * sqrt(1 / 1000 / 0.018) + "Seventh fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 0, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1000, + final T_adsorpt_start = 293.15, + final M_adsorptive = 0.018, + final no_coefficients = 9, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2, + final p_lb_pi=1e-12, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-14*T_adsorpt^2; + c[4] = char_curve_b+1e-14*T_adsorpt^2; + c[5] = char_curve_c-1e-14*T_adsorpt^2; + c[6] = char_curve_d+1e-14*T_adsorpt^2; + c[7] = char_curve_e-1e-18*T_adsorpt^2; + c[8] = char_curve_f+1e-14*T_adsorpt^2; + c[9] = char_curve_g-1e-18*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-14*T_adsorpt; + dc_dT[4] = +2*1e-14*T_adsorpt; + dc_dT[5] = -2*1e-14*T_adsorpt; + dc_dT[6] = +2*1e-14*T_adsorpt; + dc_dT[7] = -2*1e-18*T_adsorpt; + dc_dT[8] = +2*1e-14*T_adsorpt; + dc_dT[9] = -2*1e-18*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-14; + ddc_dT_dT[4] = +2*1e-14; + ddc_dT_dT[5] = -2*1e-14; + ddc_dT_dT[6] = +2*1e-14; + ddc_dT_dT[7] = -2*1e-18; + ddc_dT_dT[8] = +2*1e-14; + ddc_dT_dT[9] = -2*1e-18; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-14*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b+1e-14*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-14*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d+1e-14*(T_adsorpt+dT)^2; + c_pdT[7] = char_curve_e-1e-18*(T_adsorpt+dT)^2; + c_pdT[8] = char_curve_f+1e-14*(T_adsorpt+dT)^2; + c_pdT[9] = char_curve_g-1e-18*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-14*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b+1e-14*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-14*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d+1e-14*(T_adsorpt-dT)^2; + c_mdT[7] = char_curve_e-1e-18*(T_adsorpt-dT)^2; + c_mdT[8] = char_curve_f+1e-14*(T_adsorpt-dT)^2; + c_mdT[9] = char_curve_g-1e-18*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment( + StopTime=100, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 6, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Empirical-2 +isotherm model. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9ac858b3ba0ae5a20745a7bbe8b0f13537a0758c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package DubininEmpirical2 "Models to test and varify functions of the Dubinin-Empirical-2 isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Dubinin-Empirical-2 +isotherm model. The test models check the implementation of the functions and enable +verification of the function behavior. Three test models are implemented, in which +the pressure and temperature change over time. In addition, the test models demonstrate +the functions' general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end DubininEmpirical2; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininEmpirical2/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..a89a9f0a55dee84e745cdf8a4a799e6e35ad29d2 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/Test_changing_pressure.mo @@ -0,0 +1,119 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininLorentzianCumulative; +model Test_changing_pressure + "Tester for all functions of the Dubinin-Lorentzian-Cumulative isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 5.072313e-1 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b(unit="J/mol") = 1.305531e2 * 1000 * 0.018 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c(unit="J/mol") = -8.492403e1 * 1000 * 0.018 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_d = 4.128962e-3 / 1000 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 30, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + final p_lb_pi=1e-12, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a+1e-6*T_adsorpt; + c[4] = char_curve_b+1e-4*T_adsorpt^2; + c[5] = char_curve_c-1e-4*T_adsorpt^2; + c[6] = char_curve_d-1e-8*T_adsorpt; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = 1e-6; + dc_dT[4] = 2*1e-4*T_adsorpt; + dc_dT[5] = -2*1e-4*T_adsorpt; + dc_dT[6] = -1e-8; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 2*1e-4; + ddc_dT_dT[5] = -2*1e-4; + ddc_dT_dT[6] = 0; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a+1e-6*(T_adsorpt+dT); + c_pdT[4] = char_curve_b+1e-4*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-4*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-8*(T_adsorpt+dT); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a+1e-6*(T_adsorpt-dT); + c_mdT[4] = char_curve_b+1e-4*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-4*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-8*(T_adsorpt-dT); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Lorentzian-Cumulative +isotherm models. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..bf74b2ae3a82d68033e706d5968ede15c6bd4fec --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/Test_changing_pressureTemperature.mo @@ -0,0 +1,120 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininLorentzianCumulative; +model Test_changing_pressureTemperature + "Tester for all functions of the Dubinin-Lorentzian-Cumulative model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 5.072313e-1 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b(unit="J/mol") = 1.305531e2 * 1000 * 0.018 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c(unit="J/mol") = -8.492403e1 * 1000 * 0.018 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_d = 4.128962e-3 / 1000 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 300, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + final p_lb_pi=1e-12, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a+1e-6*T_adsorpt; + c[4] = char_curve_b+1e-4*T_adsorpt^2; + c[5] = char_curve_c-1e-4*T_adsorpt^2; + c[6] = char_curve_d-1e-8*T_adsorpt; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = 1e-6; + dc_dT[4] = 2*1e-4*T_adsorpt; + dc_dT[5] = -2*1e-4*T_adsorpt; + dc_dT[6] = -1e-8; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 2*1e-4; + ddc_dT_dT[5] = -2*1e-4; + ddc_dT_dT[6] = 0; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a+1e-6*(T_adsorpt+dT); + c_pdT[4] = char_curve_b+1e-4*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-4*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-8*(T_adsorpt+dT); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a+1e-6*(T_adsorpt-dT); + c_mdT[4] = char_curve_b+1e-4*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-4*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-8*(T_adsorpt-dT); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Lorentzian-Cumulative +isotherm models. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..6b994eecefa4879aaf24f8cd60632fa286260cd5 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/Test_changing_temperature.mo @@ -0,0 +1,119 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininLorentzianCumulative; +model Test_changing_temperature + "Tester for all functions of the Dubinin-Lorentzian-Cumulative isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a = 5.072313e-1 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b(unit="J/mol") = 1.305531e2 * 1000 * 0.018 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c(unit="J/mol") = -8.492403e1 * 1000 * 0.018 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_d = 4.128962e-3 / 1000 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 0, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1000, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + final p_lb_pi=1e-12, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a+1e-6*T_adsorpt; + c[4] = char_curve_b+1e-4*T_adsorpt^2; + c[5] = char_curve_c-1e-4*T_adsorpt^2; + c[6] = char_curve_d-1e-8*T_adsorpt; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = 1e-6; + dc_dT[4] = 2*1e-4*T_adsorpt; + dc_dT[5] = -2*1e-4*T_adsorpt; + dc_dT[6] = -1e-8; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 2*1e-4; + ddc_dT_dT[5] = -2*1e-4; + ddc_dT_dT[6] = 0; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a+1e-6*(T_adsorpt+dT); + c_pdT[4] = char_curve_b+1e-4*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-4*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-8*(T_adsorpt+dT); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a+1e-6*(T_adsorpt-dT); + c_mdT[4] = char_curve_b+1e-4*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-4*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-8*(T_adsorpt-dT); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Lorentzian-Cumulative +isotherm models. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..3aa9ccfeb8e6d5ffa2c219510e4256ce1c8e79a3 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package DubininLorentzianCumulative "Models to test and varify functions of the Dubinin-Lorentzian-Cumulative isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Dubinin-Lorentzian-Cumulative +isotherm model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end DubininLorentzianCumulative; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininLorentzianCumulative/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..41288b2060291524612f7540e9126cf944ce0620 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/Test_changing_pressure.mo @@ -0,0 +1,135 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininPearsonIV; +model Test_changing_pressure + "Tester for all functions of the Dubinin-Pearson-IV isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a(min=-1) = -7.689279e-1 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b(unit="J/mol") = 1.176831 / 1000 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c(unit="J/mol") = 1.485965e1 * 1000 * 0.018 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_d = 4.244922e1 * 1000 * 0.018 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_e = 2.207797e-2 + "Fivth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_f = 1.146067e-1 + "Sixth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 24, + final T_adsorpt_der = 0, + final p_adsorpt_start = 100, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 8, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV, + final p_lb_pi=1e-2, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-10*T_adsorpt^2; + c[4] = char_curve_b-1e-10*T_adsorpt^2; + c[5] = char_curve_c-1e-10*T_adsorpt^2; + c[6] = char_curve_d-1e-10*T_adsorpt^2; + c[7] = char_curve_e-1e-10*T_adsorpt^2; + c[8] = char_curve_f-1e-10*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-10*T_adsorpt; + dc_dT[4] = -2*1e-10*T_adsorpt; + dc_dT[5] = -2*1e-10*T_adsorpt; + dc_dT[6] = -2*1e-10*T_adsorpt; + dc_dT[7] = -2*1e-10*T_adsorpt; + dc_dT[8] = -2*1e-10*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-10; + ddc_dT_dT[4] = -2*1e-10; + ddc_dT_dT[5] = -2*1e-10; + ddc_dT_dT[6] = -2*1e-10; + ddc_dT_dT[7] = -2*1e-10; + ddc_dT_dT[8] = -2*1e-10; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-10*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b-1e-10*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-10*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-10*(T_adsorpt+dT)^2; + c_pdT[7] = char_curve_e-1e-10*(T_adsorpt+dT)^2; + c_pdT[8] = char_curve_f-1e-10*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-10*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b-1e-10*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-10*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-10*(T_adsorpt-dT)^2; + c_mdT[7] = char_curve_e-1e-10*(T_adsorpt-dT)^2; + c_mdT[8] = char_curve_f-1e-10*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Pearson-IV +isotherm models. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..8b634ed695d362637b64826b9664dbf5f8203d68 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/Test_changing_pressureTemperature.mo @@ -0,0 +1,137 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininPearsonIV; +model Test_changing_pressureTemperature + "Tester for all functions of the Dubinin-Pearson-IV isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a(min=-1) = -7.689279e-1 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b(unit="J/mol") = 1.176831 / 1000 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c(unit="J/mol") = 1.485965e1 * 1000 * 0.018 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_d = 4.244922e1 * 1000 * 0.018 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_e = 2.207797e-2 + "Fivth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_f = 1.146067e-1 + "Sixth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 300, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 8, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV, + final p_lb_pi=1e-2, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3, + check_func_p_piT=false); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-10*T_adsorpt^2; + c[4] = char_curve_b-1e-10*T_adsorpt^2; + c[5] = char_curve_c-1e-10*T_adsorpt^2; + c[6] = char_curve_d-1e-10*T_adsorpt^2; + c[7] = char_curve_e-1e-10*T_adsorpt^2; + c[8] = char_curve_f-1e-10*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-10*T_adsorpt; + dc_dT[4] = -2*1e-10*T_adsorpt; + dc_dT[5] = -2*1e-10*T_adsorpt; + dc_dT[6] = -2*1e-10*T_adsorpt; + dc_dT[7] = -2*1e-10*T_adsorpt; + dc_dT[8] = -2*1e-10*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-10; + ddc_dT_dT[4] = -2*1e-10; + ddc_dT_dT[5] = -2*1e-10; + ddc_dT_dT[6] = -2*1e-10; + ddc_dT_dT[7] = -2*1e-10; + ddc_dT_dT[8] = -2*1e-10; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-10*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b-1e-10*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-10*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-10*(T_adsorpt+dT)^2; + c_pdT[7] = char_curve_e-1e-10*(T_adsorpt+dT)^2; + c_pdT[8] = char_curve_f-1e-10*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-10*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b-1e-10*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-10*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-10*(T_adsorpt-dT)^2; + c_mdT[7] = char_curve_e-1e-10*(T_adsorpt-dT)^2; + c_mdT[8] = char_curve_f-1e-10*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Pearson-IV +isotherm models. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..88cf670180c861c8368046e83ba0d71d8452bfce --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/Test_changing_temperature.mo @@ -0,0 +1,136 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.DubininPearsonIV; +model Test_changing_temperature + "Tester for all functions of the Dubinin-Pearson-IV isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.FilledPoreVolume char_curve_a(min=-1) = -7.689279e-1 / 1000 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_b(unit="J/mol") = 1.176831 / 1000 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real char_curve_c(unit="J/mol") = 1.485965e1 * 1000 * 0.018 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_d = 4.244922e1 * 1000 * 0.018 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_e = 2.207797e-2 + "Fivth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter SorpLib.Units.FilledPoreVolume char_curve_f = 1.146067e-1 + "Sixth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPureDubinin( + final p_adsorpt_der = 0, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1000, + final T_adsorpt_start = 293.15, + final M_adsorptive = 0.018, + final no_coefficients = 8, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV, + final p_lb_pi=1e-2, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3, + final dA=1e-3, + check_func_p_piT=false); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt); + c[3] = char_curve_a-1e-10*T_adsorpt^2; + c[4] = char_curve_b-1e-10*T_adsorpt^2; + c[5] = char_curve_c-1e-10*T_adsorpt^2; + c[6] = char_curve_d-1e-10*T_adsorpt^2; + c[7] = char_curve_e-1e-10*T_adsorpt^2; + c[8] = char_curve_f-1e-10*T_adsorpt^2; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c[1]) * + dc_dT[1]; + dc_dT[3] = -2*1e-10*T_adsorpt; + dc_dT[4] = -2*1e-10*T_adsorpt; + dc_dT[5] = -2*1e-10*T_adsorpt; + dc_dT[6] = -2*1e-10*T_adsorpt; + dc_dT[7] = -2*1e-10*T_adsorpt; + dc_dT[8] = -2*1e-10*T_adsorpt; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_pdT[1]) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) * + Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.drhol_dp(p=c_mdT[1])) / (2*dT); + ddc_dT_dT[3] = -2*1e-10; + ddc_dT_dT[4] = -2*1e-10; + ddc_dT_dT[5] = -2*1e-10; + ddc_dT_dT[6] = -2*1e-10; + ddc_dT_dT[7] = -2*1e-10; + ddc_dT_dT[8] = -2*1e-10; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt+dT); + c_pdT[3] = char_curve_a-1e-10*(T_adsorpt+dT)^2; + c_pdT[4] = char_curve_b-1e-10*(T_adsorpt+dT)^2; + c_pdT[5] = char_curve_c-1e-10*(T_adsorpt+dT)^2; + c_pdT[6] = char_curve_d-1e-10*(T_adsorpt+dT)^2; + c_pdT[7] = char_curve_e-1e-10*(T_adsorpt+dT)^2; + c_pdT[8] = char_curve_f-1e-10*(T_adsorpt+dT)^2; + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Regions.rhol_T(T=T_adsorpt-dT); + c_mdT[3] = char_curve_a-1e-10*(T_adsorpt-dT)^2; + c_mdT[4] = char_curve_b-1e-10*(T_adsorpt-dT)^2; + c_mdT[5] = char_curve_c-1e-10*(T_adsorpt-dT)^2; + c_mdT[6] = char_curve_d-1e-10*(T_adsorpt-dT)^2; + c_mdT[7] = char_curve_e-1e-10*(T_adsorpt-dT)^2; + c_mdT[8] = char_curve_f-1e-10*(T_adsorpt-dT)^2; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Dubinin-Pearson-IV +isotherm models. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..609c3fa5a54ad3a23e7fb5302fe9aedfbf972e87 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package DubininPearsonIV "Models to test and varify functions of the Dubinin-Pearson-IV isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Dubinin-Pearson-IV isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end DubininPearsonIV; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/DubininPearsonIV/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..c9f15ff5a4014ed927db42142fe6213ed7ee350f --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/Test_changing_pressure.mo @@ -0,0 +1,88 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Freundlich; +model Test_changing_pressure + "Tester for all functions of the Freundlich isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter Real a0 = 0.01 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1(unit="1/K") = 1/273.15 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0(unit="1") = 2 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b1(unit="K") = 50 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 100, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Freundlich, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = a0*exp(-a1*T_adsorpt); + c[2] = b0 + b1/T_adsorpt; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -a1 * c[1]; + dc_dT[2] = -b1/T_adsorpt^2; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -a1 * dc_dT[1]; + ddc_dT_dT[2] = -2 / T_adsorpt * dc_dT[2]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = a0*exp(-a1*(T_adsorpt+dT)); + c_pdT[2] = b0 + b1/(T_adsorpt+dT); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = a0*exp(-a1*(T_adsorpt-dT)); + c_mdT[2] = b0 + b1/(T_adsorpt-dT); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Freundlich isotherm models. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..bec086bc70d8747508aee3a393f1b1a0f3a05193 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/Test_changing_pressureTemperature.mo @@ -0,0 +1,89 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Freundlich; +model Test_changing_pressureTemperature + "Tester for all functions of the Freundlich isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter Real a0 = 0.01 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1(unit="1/K") = 1/273.15 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0(unit="1") = 2 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b1(unit="K") = 50 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 100, + final T_adsorpt_der = 1, + final p_adsorpt_start = 1, + final T_adsorpt_start = 273.15, + final M_adsorptive = 0.018, + final no_coefficients = 2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Freundlich, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = a0*exp(-a1*T_adsorpt); + c[2] = b0 + b1/T_adsorpt; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -a1 * c[1]; + dc_dT[2] = -b1/T_adsorpt^2; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -a1 * dc_dT[1]; + ddc_dT_dT[2] = -2 / T_adsorpt * dc_dT[2]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = a0*exp(-a1*(T_adsorpt+dT)); + c_pdT[2] = b0 + b1/(T_adsorpt+dT); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = a0*exp(-a1*(T_adsorpt-dT)); + c_mdT[2] = b0 + b1/(T_adsorpt-dT); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Freundlich isotherm models. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..bf665dd6b7492cc28a2ab220952a6ee333676404 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/Test_changing_temperature.mo @@ -0,0 +1,88 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Freundlich; +model Test_changing_temperature + "Tester for all functions of the Freundlich isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter Real a0 = 0.01 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1(unit="1/K") = 1/273.15 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0(unit="1") = 2 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b1(unit="K") = 50 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 0, + final T_adsorpt_der = 1, + final p_adsorpt_start = 5000, + final T_adsorpt_start = 273.15, + final M_adsorptive = 0.018, + final no_coefficients = 2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Freundlich, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = a0*exp(-a1*T_adsorpt); + c[2] = b0 + b1/T_adsorpt; + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -a1 * c[1]; + dc_dT[2] = -b1/T_adsorpt^2; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -a1 * dc_dT[1]; + ddc_dT_dT[2] = -2 / T_adsorpt * dc_dT[2]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = a0*exp(-a1*(T_adsorpt+dT)); + c_pdT[2] = b0 + b1/(T_adsorpt+dT); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = a0*exp(-a1*(T_adsorpt-dT)); + c_mdT[2] = b0 + b1/(T_adsorpt-dT); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Freundlich isotherm models. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2c99dcec08da7118b100d30a2f0a91ef42ca0e66 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package Freundlich "Models to test and varify functions of the Freundlich isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Freundlich isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Freundlich; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Freundlich/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..feaf22fe0378a42c4bb87f1985167eaee8de26e4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/Test_changing_pressure.mo @@ -0,0 +1,129 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.GAB; +model Test_changing_pressure + "Tester for all functions of the GAB isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_mon_ref = 0.06534 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0 + "Parameter describing the change of the monolayer uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C(unit="J/mol") = 47110 + "Adsorption enthalpy of first layer: First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D(unit="1/K") = 0.023744 + "Adsorption enthalpy of first layer: Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F(unit="J/mol") = 57706 + "Adsorption enthalpy of layers 2-9: First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G(unit="J/(mol.K)") = -47.814 + "Adsorption enthalpy of layers 2-9: Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real H(unit="J/mol") = 57220 + "Adsorption enthalpy of layer 10 or higher layers: First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I(unit="J/(mol.K)") = -44.38 + "Adsorption enthalpy of layer 10 or higher layers: Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 30, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 4, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = x_mon_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[3] = exp(((C - exp(D*T_adsorpt)) - (H + I*T_adsorpt)) / + (Modelica.Constants.R*T_adsorpt)); + c[4] = exp(((F + G*T_adsorpt) - (H + I*T_adsorpt)) / + (Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = -chi/T_ref * c[2]; + dc_dT[3] = -((D*T_adsorpt - 1) * exp(D*T_adsorpt) - H + C) / + (Modelica.Constants.R*T_adsorpt^2) * c[3]; + dc_dT[4] = (H - F) / (Modelica.Constants.R*T_adsorpt^2) * c[4]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = -chi/T_ref * dc_dT[2]; + ddc_dT_dT[3] = (((D^2 * T_adsorpt^2 - 2 * D * T_adsorpt + 1) * + exp(2 * D * T_adsorpt) + (-D^2 * Modelica.Constants.R * T_adsorpt^3 + + 2 * D * Modelica.Constants.R * T_adsorpt^2 + (-2 * Modelica.Constants.R - + 2 * D * H + 2 * C * D) * T_adsorpt + 2 * H - 2 * C) * exp(D * T_adsorpt) + + (2 * C - 2 * H) * Modelica.Constants.R * T_adsorpt + H^2 - 2 * C * H + C^2) * + exp((-exp(D * T_adsorpt) - I * T_adsorpt - H + C) / (Modelica.Constants.R * + T_adsorpt))) / (Modelica.Constants.R^2 * T_adsorpt^4); + ddc_dT_dT[4] = -1 / (Modelica.Constants.R*T_adsorpt^2) * + (2*Modelica.Constants.R*T_adsorpt - H + F) * dc_dT[2]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[3] = exp(((C - exp(D*(T_adsorpt+dT))) - (H + I*(T_adsorpt+dT))) / + (Modelica.Constants.R*(T_adsorpt+dT))); + c_pdT[4] = exp(((F + G*(T_adsorpt+dT)) - (H + I*(T_adsorpt+dT))) / + (Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[3] = exp(((C - exp(D*(T_adsorpt-dT))) - (H + I*(T_adsorpt-dT))) / + (Modelica.Constants.R*(T_adsorpt-dT))); + c_mdT[4] = exp(((F + G*(T_adsorpt-dT)) - (H + I*(T_adsorpt-dT))) / + (Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the GAB isotherm models. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..08d10aa120502fb3eebd54669f14f5a09024997a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/Test_changing_pressureTemperature.mo @@ -0,0 +1,130 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.GAB; +model Test_changing_pressureTemperature + "Tester for all functions of the GAB isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_mon_ref = 0.06534 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0 + "Parameter describing the change of the monolayer uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C(unit="J/mol") = 47110 + "Adsorption enthalpy of first layer: First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D(unit="1/K") = 0.023744 + "Adsorption enthalpy of first layer: Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F(unit="J/mol") = 57706 + "Adsorption enthalpy of layers 2-9: First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G(unit="J/(mol.K)") = -47.814 + "Adsorption enthalpy of layers 2-9: Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real H(unit="J/mol") = 57220 + "Adsorption enthalpy of layer 10 or higher layers: First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I(unit="J/(mol.K)") = -44.38 + "Adsorption enthalpy of layer 10 or higher layers: Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 300, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 4, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = x_mon_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[3] = exp(((C - exp(D*T_adsorpt)) - (H + I*T_adsorpt)) / + (Modelica.Constants.R*T_adsorpt)); + c[4] = exp(((F + G*T_adsorpt) - (H + I*T_adsorpt)) / + (Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = -chi/T_ref * c[2]; + dc_dT[3] = -((D*T_adsorpt - 1) * exp(D*T_adsorpt) - H + C) / + (Modelica.Constants.R*T_adsorpt^2) * c[3]; + dc_dT[4] = (H - F) / (Modelica.Constants.R*T_adsorpt^2) * c[4]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = -chi/T_ref * dc_dT[2]; + ddc_dT_dT[3] = (((D^2 * T_adsorpt^2 - 2 * D * T_adsorpt + 1) * + exp(2 * D * T_adsorpt) + (-D^2 * Modelica.Constants.R * T_adsorpt^3 + + 2 * D * Modelica.Constants.R * T_adsorpt^2 + (-2 * Modelica.Constants.R - + 2 * D * H + 2 * C * D) * T_adsorpt + 2 * H - 2 * C) * exp(D * T_adsorpt) + + (2 * C - 2 * H) * Modelica.Constants.R * T_adsorpt + H^2 - 2 * C * H + C^2) * + exp((-exp(D * T_adsorpt) - I * T_adsorpt - H + C) / (Modelica.Constants.R * + T_adsorpt))) / (Modelica.Constants.R^2 * T_adsorpt^4); + ddc_dT_dT[4] = -1 / (Modelica.Constants.R*T_adsorpt^2) * + (2*Modelica.Constants.R*T_adsorpt - H + F) * dc_dT[2]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[3] = exp(((C - exp(D*(T_adsorpt+dT))) - (H + I*(T_adsorpt+dT))) / + (Modelica.Constants.R*(T_adsorpt+dT))); + c_pdT[4] = exp(((F + G*(T_adsorpt+dT)) - (H + I*(T_adsorpt+dT))) / + (Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[3] = exp(((C - exp(D*(T_adsorpt-dT))) - (H + I*(T_adsorpt-dT))) / + (Modelica.Constants.R*(T_adsorpt-dT))); + c_mdT[4] = exp(((F + G*(T_adsorpt-dT)) - (H + I*(T_adsorpt-dT))) / + (Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the GAB isotherm models. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..5531c52e62734521ab01f004451c4699cdff4f14 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/Test_changing_temperature.mo @@ -0,0 +1,129 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.GAB; +model Test_changing_temperature + "Tester for all functions of the BET isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_mon_ref = 0.06534 + "Monolayer uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0 + "Parameter describing the change of the monolayer uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real C(unit="J/mol") = 47110 + "Adsorption enthalpy of first layer: First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real D(unit="1/K") = 0.023744 + "Adsorption enthalpy of first layer: Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real F(unit="J/mol") = 57706 + "Adsorption enthalpy of layers 2-9: First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real G(unit="J/(mol.K)") = -47.814 + "Adsorption enthalpy of layers 2-9: Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real H(unit="J/mol") = 57220 + "Adsorption enthalpy of layer 10 or higher layers: First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real I(unit="J/(mol.K)") = -44.38 + "Adsorption enthalpy of layer 10 or higher layers: Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 0, + final T_adsorpt_der = 80/100, + final p_adsorpt_start = 3000, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 4, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.GAB, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt); + c[2] = x_mon_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[3] = exp(((C - exp(D*T_adsorpt)) - (H + I*T_adsorpt)) / + (Modelica.Constants.R*T_adsorpt)); + c[4] = exp(((F + G*T_adsorpt) - (H + I*T_adsorpt)) / + (Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt); + dc_dT[2] = -chi/T_ref * c[2]; + dc_dT[3] = -((D*T_adsorpt - 1) * exp(D*T_adsorpt) - H + C) / + (Modelica.Constants.R*T_adsorpt^2) * c[3]; + dc_dT[4] = (H - F) / (Modelica.Constants.R*T_adsorpt^2) * c[4]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + - Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT)) / + (2*dT); + ddc_dT_dT[2] = -chi/T_ref * dc_dT[2]; + ddc_dT_dT[3] = (((D^2 * T_adsorpt^2 - 2 * D * T_adsorpt + 1) * + exp(2 * D * T_adsorpt) + (-D^2 * Modelica.Constants.R * T_adsorpt^3 + + 2 * D * Modelica.Constants.R * T_adsorpt^2 + (-2 * Modelica.Constants.R - + 2 * D * H + 2 * C * D) * T_adsorpt + 2 * H - 2 * C) * exp(D * T_adsorpt) + + (2 * C - 2 * H) * Modelica.Constants.R * T_adsorpt + H^2 - 2 * C * H + C^2) * + exp((-exp(D * T_adsorpt) - I * T_adsorpt - H + C) / (Modelica.Constants.R * + T_adsorpt))) / (Modelica.Constants.R^2 * T_adsorpt^4); + ddc_dT_dT[4] = -1 / (Modelica.Constants.R*T_adsorpt^2) * + (2*Modelica.Constants.R*T_adsorpt - H + F) * dc_dT[2]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT); + c_pdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[3] = exp(((C - exp(D*(T_adsorpt+dT))) - (H + I*(T_adsorpt+dT))) / + (Modelica.Constants.R*(T_adsorpt+dT))); + c_pdT[4] = exp(((F + G*(T_adsorpt+dT)) - (H + I*(T_adsorpt+dT))) / + (Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT); + c_mdT[2] = x_mon_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[3] = exp(((C - exp(D*(T_adsorpt-dT))) - (H + I*(T_adsorpt-dT))) / + (Modelica.Constants.R*(T_adsorpt-dT))); + c_mdT[4] = exp(((F + G*(T_adsorpt-dT)) - (H + I*(T_adsorpt-dT))) / + (Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the BET isotherm models. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..fd2d0d8580234fbc3e2d0dff00bc897174880893 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package GAB "Models to test and varify functions of the GAB isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the GAB isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end GAB; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/GAB/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..aaaebfa8887d2b01671cf4d6e38774baaa4b9140 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/Test_changing_pressure.mo @@ -0,0 +1,80 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Henry; +model Test_changing_pressure + "Tester for all functions of the Henry isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter Real H_ref(unit="kg/(kg.Pa)") = 0.01 + "Henry constant at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + final parameter Real C_exp(unit="K") = 2400 + "Exponent describing change of Henry constant with temperature" + annotation (Dialog(tab="General", group="Parameters")); + final parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature for Henry constant" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 1, + final T_adsorpt_der = 0, + final p_adsorpt_start = 0, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.018, + final no_coefficients = 1, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Henry, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = H_ref * exp(C_exp * (1/T_adsorpt - 1 / T_ref)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -C_exp * c[1] / (T_adsorpt^2); + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -dc_dT[1] * (2 * T_adsorpt + C_exp) / (T_adsorpt^2); + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = H_ref * exp(C_exp * (1/(T_adsorpt + dT) - 1 / T_ref)); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = H_ref * exp(C_exp * (1/(T_adsorpt - dT) - 1 / T_ref)); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Henry isotherm model. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..f27800a34d6e08ee9c7e967eb4541b76c24accea --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/Test_changing_pressureTemperature.mo @@ -0,0 +1,81 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Henry; +model Test_changing_pressureTemperature + "Tester for all functions of the Henry isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter Real H_ref(unit="kg/(kg.Pa)") = 0.01 + "Henry constant at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + final parameter Real C_exp(unit="K") = 2400 + "Exponent describing change of Henry constant with temperature" + annotation (Dialog(tab="General", group="Parameters")); + final parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature for Henry constant" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 1, + final T_adsorpt_der = 1, + final p_adsorpt_start = 0, + final T_adsorpt_start = 273.15, + final M_adsorptive = 0.018, + final no_coefficients = 1, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Henry, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = H_ref * exp(C_exp * (1/T_adsorpt - 1 / T_ref)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -C_exp * c[1] / (T_adsorpt^2); + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -dc_dT[1] * (2 * T_adsorpt + C_exp) / (T_adsorpt^2); + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = H_ref * exp(C_exp * (1/(T_adsorpt + dT) - 1 / T_ref)); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = H_ref * exp(C_exp * (1/(T_adsorpt - dT) - 1 / T_ref)); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Henry isotherm model. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..ccdb66d785b4c5d15f4c353c6099f12a431ce075 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/Test_changing_temperature.mo @@ -0,0 +1,80 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Henry; +model Test_changing_temperature + "Tester for all functions of the Henry isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter Real H_ref(unit="kg/(kg.Pa)") = 0.01 + "Henry constant at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + final parameter Real C_exp(unit="K") = 2400 + "Exponent describing change of Henry constant with temperature" + annotation (Dialog(tab="General", group="Parameters")); + final parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature for Henry constant" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 0, + final T_adsorpt_der = 1, + final p_adsorpt_start = 100, + final T_adsorpt_start = 273.15, + final M_adsorptive = 0.018, + final no_coefficients = 1, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Henry, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = H_ref * exp(C_exp * (1/T_adsorpt - 1 / T_ref)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -C_exp * c[1] / (T_adsorpt^2); + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -dc_dT[1] * (2 * T_adsorpt + C_exp) / (T_adsorpt^2); + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = H_ref * exp(C_exp * (1/(T_adsorpt + dT) - 1 / T_ref)); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = H_ref * exp(C_exp * (1/(T_adsorpt - dT) - 1 / T_ref)); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Henry isotherm model. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..63f5f0c2518a29bb29295d8b845a08e19b920e25 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package Henry "Models to test and varify functions of the Henry isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Henry isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Henry; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Henry/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..e595e6f4319762f88025242100429e188149affe --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/Test_changing_pressure.mo @@ -0,0 +1,92 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Langmuir; +model Test_changing_pressure + "Tester for all functions of the Langmuir isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake a0 = 0.35 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1(unit="kg.K/kg") = 1e-4 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0(unit="1/Pa") = 5e-8 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Delta_H_ads(unit="J/mol") = -2e4 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 100, + final T_adsorpt_der = 0, + final p_adsorpt_start = 0, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.044, + final no_coefficients = 2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = a0 + a1/T_adsorpt; + c[2] = b0*exp(-Delta_H_ads/(Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -a1/T_adsorpt^2; + dc_dT[2] = Delta_H_ads/(Modelica.Constants.R*T_adsorpt^2) * c[2]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -2*dc_dT[1]/T_adsorpt; + ddc_dT_dT[2] = -(2*Modelica.Constants.R*T_adsorpt - Delta_H_ads) / + (Modelica.Constants.R*T_adsorpt^2) * dc_dT[2]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = a0 + a1/(T_adsorpt+dT); + c_pdT[2] = b0*exp(-Delta_H_ads/(Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = a0 + a1/(T_adsorpt-dT); + c_mdT[2] = b0*exp(-Delta_H_ads/(Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment( + StopTime=100, + Tolerance=1e-06, + __Dymola_Algorithm="Dassl"), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Langmuir isotherm model. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..57085151e18cb4706e64182512ab6f3d6d41b7ac --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/Test_changing_pressureTemperature.mo @@ -0,0 +1,90 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Langmuir; +model Test_changing_pressureTemperature + "Tester for all functions of the Langmuir isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake a0 = 0.35 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1(unit="kg.K/kg") = 1e-4 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0(unit="1/Pa") = 5e-8 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Delta_H_ads(unit="J/mol") = -2e4 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 100, + final T_adsorpt_der = 1, + final p_adsorpt_start = 0, + final T_adsorpt_start = 273.15, + final M_adsorptive = 0.044, + final no_coefficients = 2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = a0 + a1/T_adsorpt; + c[2] = b0*exp(-Delta_H_ads/(Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -a1/T_adsorpt^2; + dc_dT[2] = Delta_H_ads/(Modelica.Constants.R*T_adsorpt^2) * c[2]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -2*dc_dT[1]/T_adsorpt; + ddc_dT_dT[2] = -(2*Modelica.Constants.R*T_adsorpt - Delta_H_ads) / + (Modelica.Constants.R*T_adsorpt^2) * dc_dT[2]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = a0 + a1/(T_adsorpt+dT); + c_pdT[2] = b0*exp(-Delta_H_ads/(Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = a0 + a1/(T_adsorpt-dT); + c_mdT[2] = b0*exp(-Delta_H_ads/(Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Langmuir isotherm model. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..fcd12ca1991ff95fcd0db071318dfb6250e4736c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/Test_changing_temperature.mo @@ -0,0 +1,89 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Langmuir; +model Test_changing_temperature + "Tester for all functions of the Langmuir isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake a0 = 0.35 + "First fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real a1(unit="kg.K/kg") = 1e-4 + "Second fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b0(unit="1/Pa") = 5e-8 + "Third fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Delta_H_ads(unit="J/mol") = -2e4 + "Fourth fitting parameter" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 0, + final T_adsorpt_der = 1, + final p_adsorpt_start = 100, + final T_adsorpt_start = 273.15, + final M_adsorptive = 0.044, + final no_coefficients = 2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = a0 + a1/T_adsorpt; + c[2] = b0*exp(-Delta_H_ads/(Modelica.Constants.R*T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -a1/T_adsorpt^2; + dc_dT[2] = Delta_H_ads/(Modelica.Constants.R*T_adsorpt^2) * c[2]; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -2*dc_dT[1]/T_adsorpt; + ddc_dT_dT[2] = -(2*Modelica.Constants.R*T_adsorpt - Delta_H_ads) / + (Modelica.Constants.R*T_adsorpt^2) * dc_dT[2]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = a0 + a1/(T_adsorpt+dT); + c_pdT[2] = b0*exp(-Delta_H_ads/(Modelica.Constants.R*(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = a0 + a1/(T_adsorpt-dT); + c_mdT[2] = b0*exp(-Delta_H_ads/(Modelica.Constants.R*(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Langmuir isotherm model. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..92bbd1e756425f6cb580b0f4022afb3dbf3b4e56 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package Langmuir "Models to test and varify functions of the Langmuir isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Langmuir isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Langmuir; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Langmuir/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..5842516eb887df1e944bb5e3033ab98588884ded --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/Test_changing_pressure.mo @@ -0,0 +1,104 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Sips; +model Test_changing_pressure + "Tester for all functions of the Sips isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_ref = 0.32 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0.01 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref(unit="1/Pa") = 1.075e-4 + "Sips coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q(unit="J/mol") = 28.752e3 + "Parameter describing the change of the Sips coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real n_ref(unit="1") = 2.312 + "Sips exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha(unit="1") = 0.5559 + "Parameter describing the change of the Sips exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 283 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 1400, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.044, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Sips, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = x_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/T_adsorpt - 1)); + c[3] = 1 / (1/n_ref + alpha * (1 - T_ref/T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -chi/T_ref * c[1]; + dc_dT[2] = -Q/Modelica.Constants.R/T_adsorpt^2 * c[2]; + dc_dT[3] = -T_ref*alpha/T_adsorpt^2 / (1/n_ref + alpha * (1 - T_ref/T_adsorpt))^2; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -chi/T_ref * dc_dT[1]; + ddc_dT_dT[2] = -1/Modelica.Constants.R/T_adsorpt^2 * + (2*Modelica.Constants.R*T_adsorpt + Q) * dc_dT[2]; + ddc_dT_dT[3] = 2 * T_ref * n_ref^2 * alpha * (n_ref * alpha + 1) / + ((n_ref * alpha + 1) * T_adsorpt - T_ref * n_ref * alpha)^3; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = x_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt+dT) - 1)); + c_pdT[3] = 1 / (1/n_ref + alpha * (1 - T_ref/(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = x_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt-dT) - 1)); + c_mdT[3] = 1 / (1/n_ref + alpha * (1 - T_ref/(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Sips isotherm models. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..28ef8fe800b5df40718d1e7d3817849a7941e995 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/Test_changing_pressureTemperature.mo @@ -0,0 +1,105 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Sips; +model Test_changing_pressureTemperature + "Tester for all functions of the Sips isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_ref = 0.32 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0.01 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref(unit="1/Pa") = 1.075e-4 + "Sips coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q(unit="J/mol") = 28.752e3 + "Parameter describing the change of the Sips coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real n_ref(unit="1") = 2.312 + "Sips exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha(unit="1") = 0.5559 + "Parameter describing the change of the Sips exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 283 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 1400, + final T_adsorpt_der = 1, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.044, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Sips, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = x_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/T_adsorpt - 1)); + c[3] = 1 / (1/n_ref + alpha * (1 - T_ref/T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -chi/T_ref * c[1]; + dc_dT[2] = -Q/Modelica.Constants.R/T_adsorpt^2 * c[2]; + dc_dT[3] = -T_ref*alpha/T_adsorpt^2 / (1/n_ref + alpha * (1 - T_ref/T_adsorpt))^2; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -chi/T_ref * dc_dT[1]; + ddc_dT_dT[2] = -1/Modelica.Constants.R/T_adsorpt^2 * + (2*Modelica.Constants.R*T_adsorpt + Q) * dc_dT[2]; + ddc_dT_dT[3] = 2 * T_ref * n_ref^2 * alpha * (n_ref * alpha + 1) / + ((n_ref * alpha + 1) * T_adsorpt - T_ref * n_ref * alpha)^3; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = x_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt+dT) - 1)); + c_pdT[3] = 1 / (1/n_ref + alpha * (1 - T_ref/(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = x_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt-dT) - 1)); + c_mdT[3] = 1 / (1/n_ref + alpha * (1 - T_ref/(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Sips isotherm models. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..e90de1256ed38d99e9c762c8c34a3b273bace8ea --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/Test_changing_temperature.mo @@ -0,0 +1,104 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Sips; +model Test_changing_temperature + "Tester for all functions of the Sips isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_ref = 0.32 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0.01 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref(unit="1/Pa") = 1.075e-4 + "Sips coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q(unit="J/mol") = 28.752e3 + "Parameter describing the change of the Sips coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real n_ref(unit="1") = 2.312 + "Sips exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha(unit="1") = 0.5559 + "Parameter describing the change of the Sips exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 283 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 0, + final T_adsorpt_der = 1, + final p_adsorpt_start = 50000, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.044, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Sips, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = x_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/T_adsorpt - 1)); + c[3] = 1 / (1/n_ref + alpha * (1 - T_ref/T_adsorpt)); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -chi/T_ref * c[1]; + dc_dT[2] = -Q/Modelica.Constants.R/T_adsorpt^2 * c[2]; + dc_dT[3] = -T_ref*alpha/T_adsorpt^2 / (1/n_ref + alpha * (1 - T_ref/T_adsorpt))^2; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -chi/T_ref * dc_dT[1]; + ddc_dT_dT[2] = -1/Modelica.Constants.R/T_adsorpt^2 * + (2*Modelica.Constants.R*T_adsorpt + Q) * dc_dT[2]; + ddc_dT_dT[3] = 2 * T_ref * n_ref^2 * alpha * (n_ref * alpha + 1) / + ((n_ref * alpha + 1) * T_adsorpt - T_ref * n_ref * alpha)^3; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = x_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt+dT) - 1)); + c_pdT[3] = 1 / (1/n_ref + alpha * (1 - T_ref/(T_adsorpt+dT))); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = x_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt-dT) - 1)); + c_mdT[3] = 1 / (1/n_ref + alpha * (1 - T_ref/(T_adsorpt-dT))); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Sips isotherm models. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e3f036c0d735b8aa610b30c1bc74a0a76272f650 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package Sips "Models to test and varify functions of the Sips isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Sips isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Sips; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Sips/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/Test_changing_pressure.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/Test_changing_pressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..917a734891c85adf64bf60c3239965ac9e5e8639 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/Test_changing_pressure.mo @@ -0,0 +1,105 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Toth; +model Test_changing_pressure + "Tester for all functions of the Toth isotherm model: Changing pressure" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_ref = 0.38 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0.01 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref(unit="1/Pa") = 10.54e-3 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q(unit="J/mol") = 46.093e3 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref(unit="1") = 0.2842 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha(unit="1") = 0.284 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 283 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 1400, + final T_adsorpt_der = 0, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.044, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = x_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/T_adsorpt - 1)); + c[3] = t_ref + alpha * (1 - T_ref/T_adsorpt); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -chi/T_ref * c[1]; + dc_dT[2] = -Q/Modelica.Constants.R/T_adsorpt^2 * c[2]; + dc_dT[3] = T_ref*alpha/T_adsorpt^2; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -chi/T_ref * dc_dT[1]; + ddc_dT_dT[2] = -1/Modelica.Constants.R/T_adsorpt^2 * + (2*Modelica.Constants.R*T_adsorpt + Q) * dc_dT[2]; + ddc_dT_dT[3] = -2/T_adsorpt * dc_dT[3]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = x_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt+dT) - 1)); + c_pdT[3] = t_ref + alpha * (1 - T_ref/(T_adsorpt+dT)); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = x_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt-dT) - 1)); + c_mdT[3] = t_ref + alpha * (1 - T_ref/(T_adsorpt-dT)); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth isotherm models. +<br/><br/> +As an example, this tester increases the pressure with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_pressure; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/Test_changing_pressureTemperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/Test_changing_pressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..c1f1a3860674faa27aeba3d64281ca0c93c7889a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/Test_changing_pressureTemperature.mo @@ -0,0 +1,106 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Toth; +model Test_changing_pressureTemperature + "Tester for all functions of the Toth isotherm model: Changing pressure and temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_ref = 0.38 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0.01 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref(unit="1/Pa") = 10.54e-3 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q(unit="J/mol") = 46.093e3 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref(unit="1") = 0.2842 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha(unit="1") = 0.284 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 283 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 1400, + final T_adsorpt_der = 1, + final p_adsorpt_start = 1, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.044, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + final tolerance_p_pi=1e-6, + final tolerance_pi=1e-4, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = x_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/T_adsorpt - 1)); + c[3] = t_ref + alpha * (1 - T_ref/T_adsorpt); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -chi/T_ref * c[1]; + dc_dT[2] = -Q/Modelica.Constants.R/T_adsorpt^2 * c[2]; + dc_dT[3] = T_ref*alpha/T_adsorpt^2; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -chi/T_ref * dc_dT[1]; + ddc_dT_dT[2] = -1/Modelica.Constants.R/T_adsorpt^2 * + (2*Modelica.Constants.R*T_adsorpt + Q) * dc_dT[2]; + ddc_dT_dT[3] = -2/T_adsorpt * dc_dT[3]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = x_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt+dT) - 1)); + c_pdT[3] = t_ref + alpha * (1 - T_ref/(T_adsorpt+dT)); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = x_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt-dT) - 1)); + c_mdT[3] = t_ref + alpha * (1 - T_ref/(T_adsorpt-dT)); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth isotherm models. +<br/><br/> +As an example, this tester increases the pressure and temperature with time. To +see the behavior of all functions, plot the variables <i>x_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, and <i>red_spreading_pressure</i> over +the variable <i>p_adsorpt</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 100 s). +</p> +</html>")); +end Test_changing_pressureTemperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/Test_changing_temperature.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/Test_changing_temperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..7e56e39fe4c851af8120dc75fe6789a68e444e56 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/Test_changing_temperature.mo @@ -0,0 +1,105 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers.Toth; +model Test_changing_temperature + "Tester for all functions of the Toth isotherm model: Changing temperature" + + // + // Definition of parameters + // + parameter SorpLib.Units.Uptake x_ref = 0.38 + "Saturation uptake at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real chi(unit="1") = 0.01 + "Parameter describing the change of the saturation uptake with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real b_ref(unit="1/Pa") = 10.54e-3 + "Toth coefficient at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real Q(unit="J/mol") = 46.093e3 + "Parameter describing the change of the Toth coefficient with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real t_ref(unit="1") = 0.2842 + "Toth exponent at reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real alpha(unit="1") = 0.284 + "Parameter describing the change of the Toth exponent with temperature" + annotation (Dialog(tab="General", group="Parameters")); + parameter Modelica.Units.SI.Temperature T_ref = 283 + "Reference temperature" + annotation (Dialog(tab="General", group="Parameters")); + + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialTestPure( + final p_adsorpt_der = 0, + final T_adsorpt_der = 1, + final p_adsorpt_start = 50000, + final T_adsorpt_start = 298.15, + final M_adsorptive = 0.044, + final no_coefficients = 3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + final tolerance_p_pi=1e-6, + final tolerance_pi=100*Modelica.Constants.eps, + final dp=1e-3, + final dT=1e-3); + +equation + // + // Coefficients of the isotherm model + // + c[1] = x_ref * exp(chi * (1 - T_adsorpt/T_ref)); + c[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/T_adsorpt - 1)); + c[3] = t_ref + alpha * (1 - T_ref/T_adsorpt); + + // + // Partial derivative of coefficients of isotherm model w.r.t. temperature + // + dc_dT[1] = -chi/T_ref * c[1]; + dc_dT[2] = -Q/Modelica.Constants.R/T_adsorpt^2 * c[2]; + dc_dT[3] = T_ref*alpha/T_adsorpt^2; + + // + // Second-oder partial derivative of coefficients of isotherm model w.r.t. temperature + // + ddc_dT_dT[1] = -chi/T_ref * dc_dT[1]; + ddc_dT_dT[2] = -1/Modelica.Constants.R/T_adsorpt^2 * + (2*Modelica.Constants.R*T_adsorpt + Q) * dc_dT[2]; + ddc_dT_dT[3] = -2/T_adsorpt * dc_dT[3]; + + // + // Coefficients of isotherm model: T + dT K + // + c_pdT[1] = x_ref * exp(chi * (1 - (T_adsorpt+dT)/T_ref)); + c_pdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt+dT) - 1)); + c_pdT[3] = t_ref + alpha * (1 - T_ref/(T_adsorpt+dT)); + + // + // Coefficients of isotherm model: T - dT K + // + c_mdT[1] = x_ref * exp(chi * (1 - (T_adsorpt-dT)/T_ref)); + c_mdT[2] = b_ref * exp(Q/Modelica.Constants.R/T_ref * (T_ref/(T_adsorpt-dT) - 1)); + c_mdT[3] = t_ref + alpha * (1 - T_ref/(T_adsorpt-dT)); + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=100, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of all functions of the Toth isotherm models. +<br/><br/> +As an example, this tester increases the temperature with time. To see the behavior of +all functions, plot the variables <i>x_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt</i>, +<i>dx_adsorpt_dT_adsorpt</i>, <i>dx_adsorpt_dp_adsorpt_dT_adsorpt</i>, +<i>dx_adsorpt_dp_adsorpt_dp_adsorpt</i>, <i>dx_adsorpt_dT_adsorpt_dT_adsorpt</i>, +and <i>red_spreading_pressure</i> over the variable <i>p_adsorpt</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 100 s). +</p> +</html>")); +end Test_changing_temperature; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..fb61ae80829075174a74a0df1027e58587f40f97 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/package.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Testers; +package Toth "Models to test and varify functions of the Toth isotherm" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the Toth isotherm +model. The test models check the implementation of the functions and enable verification +of the function behavior. Three test models are implemented, in which the pressure and +temperature change over time. In addition, the test models demonstrate the functions' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Toth; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bdb9f26937c80222d4122b5df1f4dfaea19ffc9b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/Toth/package.order @@ -0,0 +1,3 @@ +Test_changing_pressure +Test_changing_temperature +Test_changing_pressureTemperature diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..424b1d7c5af2902bdbefc333f94112256eb470a9 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package Testers "This package contains test models to check and varify pure component isotherm models" +extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented isotherm models. Each +isotherm model has its test models saved in a separate package. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..db10ed0d73adaa28d5f3a518140307d67d6e8e68 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Testers/package.order @@ -0,0 +1,14 @@ +Henry +Langmuir +BiLangmuir +Freundlich +Sips +Toth +BET +GAB +DubininAstakhov +DubininLorentzianCumulative +DubininPearsonIV +DubininChebyshevSeriesRaionalOrder33 +DubininEmpirical1 +DubininEmpirical2 diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Toth/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Toth/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..7e347947ff41c24d09cdb41a840ddb91f7741f7b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Toth/package.mo @@ -0,0 +1,304 @@ +within SorpLib.Media.Functions.SorptionEquilibria.PureComponents; +package Toth "Package containing all functions regarding the Toth isotherm" +extends + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents; + + redeclare final function extends x_pT + "Toth isotherm model: Uptake as function of pressure and temperature" + algorithm + x_adsorpt := c[1] * (c[2]*p_adsorpt) / ((1 + (c[2]*p_adsorpt)^c[3])^(1/c[3])) + "Calculation of the equilibrium uptake of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.p_xT(x_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end x_pT; + + redeclare final function extends p_xT + "Toth isotherm model: Pressure as function of uptake and temperature" + algorithm + p_adsorpt := x_adsorpt/c[2] * 1 / (c[1]^c[3] - x_adsorpt^c[3]) ^ (1/c[3]) + "Calculation of the equilibrium pressure of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(x_adsorpt=SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT(p_adsorpt, T_adsorpt, c, p_adsorpt_lb_start, p_adsorpt_ub_start, tolerance))); + end p_xT; + + redeclare final function extends dx_dp + "Toth isotherm model: Partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + dx_adsorpt_dp_adsorpt := c[1]*c[2] * ((c[2]*p_adsorpt)^c[3] + 1) ^ + (-1/c[3] - 1) + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium pressure at constant temperature"; + end dx_dp; + + redeclare final function extends dx_dT + "Toth isotherm model: Partial derivative of uptake w.r.t. temperature at constant pressure" + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = c[2] * p_adsorpt / + ((1 + (c[2]*p_adsorpt)^c[3])^(1/c[3])) + "Derivative of uptake w.r.t. to first coefficient of Toth isotherm"; + Real dx_adsorpt_dc2 = c[1] * p_adsorpt * + ((c[2]*p_adsorpt)^c[3] + 1) ^ (-1/c[3] - 1) + "Derivative of uptake w.r.t. to second coefficient of Toth isotherm"; + Real dx_adsorpt_dc3 = c[1] * c[2] * p_adsorpt * + (log(1 + (c[2]*p_adsorpt)^c[3]) / c[3]^2 - + (c[2]*p_adsorpt)^c[3] * log(c[2]*p_adsorpt) / + (c[3] * (1 + (c[2]*p_adsorpt)^c[3]))) / + ((1 + (c[2]*p_adsorpt)^c[3])^(1/c[3])) + "Derivative of uptake w.r.t. to third coefficient of Toth isotherm"; + + algorithm + dx_adsorpt_dT_adsorpt := + dx_adsorpt_dc1*dc_dT_adsorpt[1] + + dx_adsorpt_dc2*dc_dT_adsorpt[2] + + dx_adsorpt_dc3*dc_dT_adsorpt[3] + "Calculation of the partial derivative of the equilibrium uptake w.r.t. the + equilibrium temperature at constant pressure"; + end dx_dT; + + redeclare final function extends ddx_dp_dp + "Toth isotherm model: Second-order partial derivative of uptake w.r.t. pressure at constant temperature" + algorithm + ddx_adsorpt_dp_adsorpt_dp_adsorpt := -(c[1] * c[2] * (c[3] + 1) * + (c[2] * p_adsorpt)^c[3]) / + (p_adsorpt * ((c[2] * p_adsorpt)^c[3] + 1)^((2 * c[3] + 1) / c[3])) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure at constant temperature"; + end ddx_dp_dp; + + redeclare final function extends ddx_dT_dT + "Toth isotherm model: Second-order partial derivative of uptake w.r.t. temperature at constant pressure" + + // + // Definition of variables + // +protected + Real dx_adsorpt_dc1 = c[2] * p_adsorpt / + ((1 + (c[2]*p_adsorpt)^c[3])^(1/c[3])) + "Derivative of uptake w.r.t. to first coefficient of Toth isotherm"; + Real dx_adsorpt_dc2 = c[1] * p_adsorpt * + ((c[2]*p_adsorpt)^c[3] + 1) ^ (-1/c[3] - 1) + "Derivative of uptake w.r.t. to second coefficient of Toth isotherm"; + Real dx_adsorpt_dc3 = c[1] * c[2] * p_adsorpt * + (log(1 + (c[2]*p_adsorpt)^c[3]) / c[3]^2 - + (c[2]*p_adsorpt)^c[3] * log(c[2]*p_adsorpt) / + (c[3] * (1 + (c[2]*p_adsorpt)^c[3]))) / + ((1 + (c[2]*p_adsorpt)^c[3])^(1/c[3])) + "Derivative of uptake w.r.t. to third coefficient of Toth isotherm"; + + Real ddx_adsorpt_dc1_dc2 = p_adsorpt * ((p_adsorpt * c[2])^c[3] + 1) ^ + (-1 / c[3] - 1) + "Second-order partial derivative of uptake w.r.t. to first and second + coefficient of Toth isotherm"; + Real ddx_adsorpt_dc1_dc3 = (c[2] * p_adsorpt * (log((c[2] * p_adsorpt)^c[3] + 1) / + c[3]^2 - ((c[2] * p_adsorpt)^c[3] * log(c[2] * p_adsorpt)) / + (((c[2] * p_adsorpt)^c[3] + 1) * c[3]))) / + ((c[2] * p_adsorpt)^c[3] + 1)^(1 / c[3]) + "Second-order partial derivative of uptake w.r.t. to first and third + coefficient of Toth isotherm"; + + Real ddx_adsorpt_dc2_dc2 = -(c[1] * (c[3] + 1) * p_adsorpt * + (p_adsorpt * c[2])^c[3] * ((p_adsorpt * c[2])^c[3] + 1)^(-1 / c[3] - 2)) / c[2] + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Toth isotherm"; + Real ddx_adsorpt_dc2_dc3 = c[1] * p_adsorpt * ((c[2] * p_adsorpt)^c[3] + 1) ^ + (-1 / c[3] - 1) * (((c[2] * p_adsorpt)^c[3] * log(c[2] * p_adsorpt) * + (-1 / c[3] - 1)) / ((c[2] * p_adsorpt)^c[3] + 1) + + log((c[2] * p_adsorpt)^c[3] + 1) / c[3]^2) + "Second-order partial derivative of uptake w.r.t. to second and third + coefficient of Toth isotherm"; + + Real ddx_adsorpt_dc3_dc3 = (c[1] * c[2] * p_adsorpt * (-((c[2] * p_adsorpt)^c[3] * + log(c[2] * p_adsorpt)^2) / (((c[2] * p_adsorpt)^c[3] + 1) * c[3]) + + ((c[2] * p_adsorpt)^(2 * c[3]) * log(c[2] * p_adsorpt)^2) / + (((c[2] * p_adsorpt)^c[3] + 1)^2 * c[3]) + (2 * (c[2] * p_adsorpt)^c[3] * + log(c[2] * p_adsorpt)) / (((c[2] * p_adsorpt)^c[3] + 1) * c[3]^2) - + (2 * log((c[2] * p_adsorpt)^c[3] + 1)) / c[3]^3)) / + ((c[2] * p_adsorpt)^c[3] + 1)^(1 / c[3]) + (c[1] * c[2] * p_adsorpt * + (log((c[2] * p_adsorpt)^c[3] + 1) / c[3]^2 - ((c[2] * p_adsorpt)^c[3] * + log(c[2] * p_adsorpt)) / (((c[2] * p_adsorpt)^c[3] + 1) * c[3]))^2) / + ((c[2] * p_adsorpt)^c[3] + 1)^(1 / c[3]) + "Second-order partial derivative of uptake w.r.t. to third coefficient of + Toth isotherm"; + + Real ddx_adsorpt_dc1_dT_adsorpt = ddx_adsorpt_dc1_dc2*dc_dT_adsorpt[2] + + ddx_adsorpt_dc1_dc3*dc_dT_adsorpt[3] + "Second-order partial derivative of uptake w.r.t. to first coefficient of + Toth isotherm and temperature"; + Real ddx_adsorpt_dc2_dT_adsorpt = ddx_adsorpt_dc1_dc2*dc_dT_adsorpt[1] + + ddx_adsorpt_dc2_dc2*dc_dT_adsorpt[2] + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[3] + "Second-order partial derivative of uptake w.r.t. to second coefficient of + Toth isotherm and temperature"; + Real ddx_adsorpt_dc3_dT_adsorpt = ddx_adsorpt_dc1_dc3*dc_dT_adsorpt[1] + + ddx_adsorpt_dc2_dc3*dc_dT_adsorpt[2] + + ddx_adsorpt_dc3_dc3*dc_dT_adsorpt[3] + "Second-order partial derivative of uptake w.r.t. to third coefficient of + Toth isotherm and temperature"; + + algorithm + ddx_adsorpt_dT_adsorpt_dT_adsorpt := + (ddx_adsorpt_dc1_dT_adsorpt*dc_dT_adsorpt[1] + + dx_adsorpt_dc1*ddc_dT_adsorpt_dT_adsorpt[1]) + + (ddx_adsorpt_dc2_dT_adsorpt*dc_dT_adsorpt[2] + + dx_adsorpt_dc2*ddc_dT_adsorpt_dT_adsorpt[2]) + + (ddx_adsorpt_dc3_dT_adsorpt*dc_dT_adsorpt[3] + + dx_adsorpt_dc3*ddc_dT_adsorpt_dT_adsorpt[3]) + "Calculation of the second-order partial derivative of the equilibrium uptake + w.r.t. the equilibrium temperature at constant pressure"; + end ddx_dT_dT; + + redeclare final function extends ddx_dp_dT + "Toth isotherm model: Second-order partial derivative of uptake w.r.t. pressure and temperature" + + // + // Definition of variables + // +protected + Real ddx_adsorpt_dp_adsorpt_dc1 = c[2] * ((c[2] * p_adsorpt)^c[3] + 1) ^ + (-1 / c[3] - 1) + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + first coefficient of Toth isotherm"; + Real ddx_adsorpt_dp_adsorpt_dc2 = -c[1] * ((c[2] * p_adsorpt)^c[3] + 1) ^ + (-1 / c[3] - 2) * (c[3] * (c[2] * p_adsorpt)^c[3] - 1) + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + second coefficient of Toth isotherm"; + Real ddx_adsorpt_dp_adsorpt_dc3 = (c[1] * c[2] * ((c[2] * p_adsorpt)^c[3] + 1) ^ + (-1 / c[3] - 2) * (((c[2] * p_adsorpt)^c[3] + 1) * + log((c[2] * p_adsorpt)^c[3] + 1) + (-c[3]^2 - c[3]) * (c[2] * p_adsorpt)^c[3] * + log(c[2] * p_adsorpt))) / c[3]^2 + "Second-order partial derivative of uptake w.r.t. to equilibrium pressure and + third coefficient of Toth isotherm"; + + algorithm + ddx_adsorpt_dp_adsorpt_dT_adsorpt := + ddx_adsorpt_dp_adsorpt_dc1*dc_dT_adsorpt[1] + + ddx_adsorpt_dp_adsorpt_dc2*dc_dT_adsorpt[2] + + ddx_adsorpt_dp_adsorpt_dc3*dc_dT_adsorpt[3] + "Calculation of the second-oder partial derivative of the equilibrium uptake + w.r.t. the equilibrium pressure and temperature"; + end ddx_dp_dT; + + redeclare function pi_pT + "Toth isotherm model: Reduced spreading pressure as function of pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_pi_pT_num( + redeclare final function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.x_pT); + end pi_pT; + + redeclare function p_piT + "Toth isotherm model: Pressure as function of reduced spreading pressure and temperature (numerical solution)" + extends + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_piT_num( + redeclare final function func_pi_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth.pi_pT); + end p_piT; + // + // Annotations + // +annotation (Documentation(revisions="<html> +<ul> + <li> + November 1, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +The Toth isotherm model is a three-parameter model for calculating the equilibrium +uptake <i>x_adsorpt</i> as a function of the equilibrium pressure <i>p_adsorpt</i>. +The Toth isotherm model is suitable for type I-III isotherms according to the +IUPAC definition. +</p> + +<h4>Main equations</h4> +<p> +The Toth isotherm model has the following form: +</p> +<pre> + x<sub>adsorpt</sub> = x<sub>sat</sub>(T<sub>adsorpt</sub>) * b(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub> / ((1 + (b(T<sub>adsorpt</sub>) * p<sub>adsorpt</sub>) ^ t(T<sub>adsorpt</sub>)) ^ (1/t(T<sub>adsorpt</sub>))); +</pre> +<p> +where <i>x<sub>sat</sub>(T<sub>adsorpt</sub>)</i> is the saturation uptake, +<i>b(T<sub>adsorpt</sub>)</i> is the Toth coefficient, and <i>t(T<sub>adsorpt</sub>)</i> +is the Toth exponent. Typical temperature dependencies may have the following forms: +</p> +<pre> + x<sub>sat</sub>(T<sub>adsorpt</sub>) = x<sub>ref</sub> * <strong>exp</strong>(Χ * (1 - T<sub>adsorpt</sub>/T<sub>ref</sub>)); +</pre> +<pre> + b(T<sub>adsorpt</sub>) = b<sub>ref</sub> * <strong>exp</strong>(Q/(R * T<sub>ref</sub>) * (T<sub>ref</sub>/T<sub>adsorpt</sub> - 1)); +</pre> +<pre> + t(T<sub>adsorpt</sub>) = t<sub>ref</sub> + α * (1 - T<sub>ref</sub>/T<sub>adsorpt</sub>); +</pre> +<p> +where <i>x<sub>ref</sub></i> is the saturation uptake at reference temperature +<i>T<sub>ref</sub></i>, <i>b<sub>ref</sub></i> is the Toth coefficient at reference +temperature, and <i>t<sub>ref</sub></i> is the Toth exponent at reference temperature. +The parameter <i>Q</i> is a measure for the isosteric adsorption enthalpy at a fractional +loading of <i>x<sub>adsorpt</sub>/x<sub>sat</sub>(T<sub>adsorpt</sub>) = 0.0</i>, the +parameter <i>Χ</i> describes the change of the saturation uptake with temperature, +and the parameter <i>α</i> describes the change of the Toth exponent with +temperature. All seven parameters can be used as fitting parameters. +<br/><br/> +Note that the Toth exponent <i>t(T<sub>adsorpt</sub>)</i> is typically lower than +unity. For <i>t(T<sub>adsorpt</sub>) = 1</i>, the Toth isotherm becomes the +Langmuir isotherm. Hence, the Toth exponent <i>t(T<sub>adsorpt</sub>)</i> can be +interpreted as a parameter describing the heterogeneity of the adsorption system. +</p> + +<h4>Required parameter order in function input c[:]:</h4> +<ul> + <li> + c[1] = x<sub>sat</sub>(T<sub>adsorpt</sub>) in kg/kg + </li> + <li> + c[2] = b(T<sub>adsorpt</sub>) in 1/Pa + </li> + <li> + c[3] = t(T<sub>adsorpt</sub>) in - + </li> +</ul> + +<h4>Typical use</h4> +<p> +The isotherm model is used for type I-III isotherms according to the IUPAC definition. +</p> + +<h4>Example</h4> +<p> +The following figure shows the Toth isotherm model for different parameter sets. +In the upper sub-figure, the equilibrium pressure changes with time, while the +equilibrium temperature remains constant; in the lower sub-figure, the equilibrium +temperature changes with time, while the equilibrium pressure remains constant. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/media_functions_equilibria_pure_toth.png\" alt=\"media_functions_equilibria_pure_toth.png\"> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>")); +end Toth; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Toth/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Toth/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5b33869cf15d79cfe321d3ef372972c01c4559b4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/Toth/package.order @@ -0,0 +1,9 @@ +x_pT +p_xT +dx_dp +dx_dT +ddx_dp_dp +ddx_dT_dT +ddx_dp_dT +pi_pT +p_piT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..932ae384ac145c39c69df110ee346728bb261f0b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/package.mo @@ -0,0 +1,95 @@ +within SorpLib.Media.Functions.SorptionEquilibria; +package PureComponents "Functions required to calculate sorption equlibria for pure components" +extends Modelica.Icons.VariantsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains isotherm models for pure component adsorption. Each isotherm +model is stored as a separate package. There are also test models for each isotherm +model, which test all functions of the isotherm models regarding their implementation. +The isotherm models already implemented can be found in the package content. +</p> + +<h4>Implemented functions for each isotherm model</h4> +<p> +The following functions are provided for each isotherm model: +</p> +<ul> + <li> + Equilibrium uptake as function of equilibrium pressure and eqiulibrium temperature. + </li> + <li> + Equilibrium pressure as function of equilibrium uptake and eqiulibrium temperature. + </li> + <li> + Partial derivative of equilibrium uptake w.r.t. equilibrium pressure at constant + pressure. + </li> + <li> + Partial derivative of equilibrium uptake w.r.t. equilibrium temperature at constant + pressure. + </li> + <li> + Second-order partial derivative of equilibrium uptake w.r.t. equilibrium pressure at + constant temperature. + </li> + <li> + Second-order partial derivative of equilibrium uptake w.r.t. equilibrium temperature + at constant pressure. + </li> + <li> + Second-order partial derivative of equilibrium uptake w.r.t. equilibrium pressure and + temperature. + </li> + <li> + Reduced spreading pressure as function of equilibrium pressure and eqiulibrium + temperature. + </li> + <li> + Equilibrium pressure as function of reduced spreading pressure and eqiulibrium + temperature. + </li> +</ul> +<p> +The following additional functions are provided for isotherm models based on the model +of Dubinin: +</p> +<ul> + <li> + Filled pore volume as function of adsorption potential. + </li> + <li> + Adsorption potential as function of filled pore volume. + </li> + <li> + Partial derivative of filled pore volume w.r.t. adsorption potential at constant pressure + and temperature. + </li> + <li> + Second-order partial derivative of filled pore volume w.r.t. adsorption potential at + constant pressure and temperature. + </li> + <li> + Second-order partial derivative of filled pore volume w.r.t. adsorption potential and + temperature at constant pressure. + </li> +</ul> + +<h4>How to add new isotherm models</h4> +<p> +To add a new isotherm model, duplicate the package of a similar isotherm model that is +already implemented. Then, customise all functions of the isotherm model. If new +functions are implemented (e.g., equilibrium temperature as function of equilibrium +pressure and uptake), add these for all existing isotherm models as well. Then, adapt +the test models and check the functions of the new isotherm model regarding their +implementation. Finally, write the documentation for each function, model, and package. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end PureComponents; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/package.order b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e772968ffadb6a7b207a892f2d1454681ce181b3 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/PureComponents/package.order @@ -0,0 +1,15 @@ +Henry +Langmuir +BiLangmuir +Freundlich +Sips +Toth +BET +GAB +DubininAstakhov +DubininLorentzianCumulative +DubininPearsonIV +DubininChebyshevSeriesRaionalOrder33 +DubininEmpirical1 +DubininEmpirical2 +Testers diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Records/NumericsIAST.mo b/SorpLib/Media/Functions/SorptionEquilibria/Records/NumericsIAST.mo new file mode 100644 index 0000000000000000000000000000000000000000..40c846832e495afbd944ec3e60866a866b42c6bb --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Records/NumericsIAST.mo @@ -0,0 +1,72 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Records; +record NumericsIAST + "This record contains entries defining the numerics of IAST algorithms" + extends Modelica.Icons.Record; + + // + // Definition of paramters + // + parameter SorpLib.Choices.IASTAlgorithm IASTAlgorithm=SorpLib.Choices.IASTAlgorithm.NewtonRaphson + "Algorithm used to solve the IAST" + annotation (Dialog(tab="General", group="Basic setup")); + + parameter Integer no_max = 250 + "Maximal number of iterations" + annotation (Dialog(tab="General", group="Newton-Raphson and Fast IAST", + enable=IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST + or IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NewtonRaphson)); + parameter Real tolerance = 1e-10 + "Tolereance for loop" + annotation (Dialog(tab="General", group="Newton-Raphson and Fast IAST", + enable=IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST + or IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NewtonRaphson)); + + parameter Integer no_max_inner = 25 + "Maximal number of iterations for inner loop" + annotation (Dialog(tab="General", group="Nested Loop - Inner loop", + enable=IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop)); + parameter Real tolerance_inner = 1e-10 + "Tolerance for inner loop" + annotation (Dialog(tab="General", group="Nested Loop - Inner loop", + enable=IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop)); + + parameter Integer no_max_outer = 25 + "Maximal number of iterations for outer loop" + annotation (Dialog(tab="General", group="Nested Loop - Outer loop", + enable=IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop)); + parameter Real tolerance_outer = 1e-10 + "Tolerance for outer loop" + annotation (Dialog(tab="General", group="Nested Loop - Outer loop", + enable=IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.NestedLoop)); + + parameter Integer no_max_inv = 250 + "Maximal number of iterations" + annotation (Dialog(tab="General", group="Inverses of IAST")); + parameter Real tolerance_inv = 1e-10 + "Tolereance for loop" + annotation (Dialog(tab="General", group="Inverses of IAST")); + + parameter Modelica.Units.SI.Pressure p_K_0 = 1e-6 + "Pressure used to estimated Henry constants" + annotation (Dialog(tab="General", group="Initial values")); + parameter Modelica.Units.SI.Pressure p_sat_0 = 1e15 + "Pressure used to estimated saturation uptake" + annotation (Dialog(tab="General", group="Initial values", + enable=IASTAlgorithm == SorpLib.Choices.IASTAlgorithm.FastIAST)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains entries defining the numerics of IAST algorithms. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end NumericsIAST; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Records/NumericsIAST_PureComponents.mo b/SorpLib/Media/Functions/SorptionEquilibria/Records/NumericsIAST_PureComponents.mo new file mode 100644 index 0000000000000000000000000000000000000000..424a9a76ea618e3e5ba7fa24de008dcbd7ae0c33 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Records/NumericsIAST_PureComponents.mo @@ -0,0 +1,47 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Records; +record NumericsIAST_PureComponents + "This record contains entries defining the numerics of pure component isotherm models used within IAST algorithms" + extends Modelica.Icons.Record; + + // + // Definition of paramters + // + parameter Modelica.Units.SI.Pressure p_adsorpt_lb_start = 1 + "Lower bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Equilibrium pressure")); + parameter Modelica.Units.SI.Pressure p_adsorpt_ub_start = 10 + "Upper bound of equilibrium pressure (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Equilibrium pressure")); + parameter Real tolerance_p_adsorpt = 100*Modelica.Constants.eps + "Tolerance for numerical calculation (required if pressure is calculated + numerically (i.e., root finding))" + annotation (Dialog(tab="General", group="Equilibrium pressure")); + + parameter Modelica.Units.SI.Pressure integral_pi_lb = 0 + "Lower limit of integral when calculating the reduced spreading pressure + numerically (should be 0)" + annotation (Dialog(tab="General", group="Reduced spreading pressure")); + parameter Real tolerance_pi = 100*Modelica.Constants.eps + "Tolerance for numerical calculation (required if reduced spreading pressure + is calculated numerically (i.e., integral))" + annotation (Dialog(tab="General", group="Reduced spreading pressure")); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains entries defining the numerics of pure component isotherm +models used within IAST algorithms. +</p> +</html>", revisions="<html> +<ul> + <li> + November 10, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end NumericsIAST_PureComponents; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Records/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/Records/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c5cab9063043a29f30a9bfb83267e013016bbed7 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Records/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.Functions.SorptionEquilibria; +package Records "Package containing records used as function inputs" + extends Modelica.Icons.RecordsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains definitions of records that are used as function inputs. +Using records reduces the number of function inputs. In addition, the functions +are easier to expand if the function prototype needs to remain unchanged, as only +more entries need to be added to the data set if necessary. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Records; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Records/package.order b/SorpLib/Media/Functions/SorptionEquilibria/Records/package.order new file mode 100644 index 0000000000000000000000000000000000000000..6f3376e92368133b2267848bd61eb750ea5fef8e --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Records/package.order @@ -0,0 +1,2 @@ +NumericsIAST +NumericsIAST_PureComponents diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/A_ppsT.mo b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/A_ppsT.mo new file mode 100644 index 0000000000000000000000000000000000000000..06040b416ae5cfec63c8ebfa059a20cca6450168 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/A_ppsT.mo @@ -0,0 +1,73 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Utilities; +function A_ppsT "Calculates the molar adsorption potential" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure p_sat + "Saturation pressure at the equilibrium temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.MolarAdsorptionPotential A "Molar adsorption potential" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + +algorithm + A := Modelica.Constants.R * T_adsorpt * log(p_sat/p_adsorpt) + "Molar adsorption potential"; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=false, +LateInline=true, +inverse(p_adsorpt=p_ApsT(A,p_sat,T_adsorpt)), +Documentation(info="<html> +<p> +This function calculates the molar adsorption potential <i>A</i>. The molar adsorption +potential <i>A</i> is an important quantity for isotherm models following the model +of Dubinin. +</p> + +<h4>Main equations</h4> +<p> +The molar adsorption potential <i>A</i> is defined as follows: +</p> +<pre> + A(T<sub>adsorpt</sub>) = R * T<sub>adsorpt</sub> * <strong>ln</strong>(p<sub>sat</sub>(T<sub>adsorpt</sub>) / p<sub>adsorpt</sub>); +</pre> + +<h4>Typical use</h4> +<p> +The molar adsorption potential <i>A</i> is used to calculate the characteristic +curve of isotherm models following the model of Dubinin. +</p> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end A_ppsT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/Testers/Test_A_ppsT.mo b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/Testers/Test_A_ppsT.mo new file mode 100644 index 0000000000000000000000000000000000000000..b0ab14f8e9447c12d5fb981310395c44cd31726d --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/Testers/Test_A_ppsT.mo @@ -0,0 +1,308 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Utilities.Testers; +model Test_A_ppsT + "Tester for the function 'calc_A_ppsT' and all corresponding functions" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference used to calculate partial derivatives numerically" + annotation (Dialog(tab="General", group="Numerical parameters"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculate partial derivatives numerically" + annotation (Dialog(tab="General", group="Numerical parameters"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_adsorpt(start=100, fixed=true) + "Equilibrium pressure"; + Modelica.Units.SI.Temperature T_adsorpt(start=278.15, fixed=true) + "Equilibrium temperature"; + + Modelica.Units.SI.Pressure p_sat + "Saturation pressure at equilibrium temperature"; + Modelica.Units.SI.DerPressureByTemperature dp_sat_dT + "Partial derivative of saturation pressure w.r.t. equilibrium temperature"; + Real ddp_sat_dT_dT(unit="Pa/K2") + "Second-order partial derivative of saturation pressure w.r.t. equilibrium + temperature"; + + SorpLib.Units.MolarAdsorptionPotential A + "Molar adsorption potential"; + + Modelica.Units.SI.Pressure p_adsorpt_inv + "Equilibrium pressure calculated via inverse function of the molar adsorption + potential"; + + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt + "Partial derivative of the molar adsorption potential w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt_num + "Partial derivative of the molar adsorption potential w.r.t. pressure at + constant temperature calculated numerically"; + + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt + "Partial derivative of the molar adsorption potential w.r.t. temperature at + constant pressure"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt_num + "Partial derivative of the molar adsorption potential w.r.t. temperature at + constant pressure calculated numerically"; + + SorpLib.Units.DerMolarAdsorptionPotentialByPressurePressure ddA_dp_adsorpt_dp_adsorpt + "Second-order partial derivative of the molar adsorption potential w.r.t. + pressure at constant temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressurePressure ddA_dp_adsorpt_dp_adsorpt_num + "Second-order partial derivative of the molar adsorption potential w.r.t. + pressure at constant temperature calculated numerically"; + + SorpLib.Units.DerMolarAdsorptionPotentialByTemperatureTemperature ddA_dT_adsorpt_dT_adsorpt + "Second-order partial derivative of the molar adsorption potential w.r.t. + temperature at constant pressure"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperatureTemperature ddA_dT_adsorpt_dT_adsorpt_num + "Second-order partial derivative of the molar adsorption potential w.r.t. + temperature at constant pressure calculated numerically"; + + SorpLib.Units.DerMolarAdsorptionPotentialByPressureTemperature ddA_dp_adsorpt_dT_adsorpt + "Second-order partial derivative of the molar adsorption potential w.r.t. + pressure and temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressureTemperature ddA_dp_adsorpt_dT_adsorpt_num + "Second-order partial derivative of the molar adsorption potential w.r.t. + pressure and temperature calculated numerically"; + +protected + Modelica.Units.SI.Pressure p_sat_pdT + "Saturation pressure at equilibrium temperature: T + 1e-6 K"; + Modelica.Units.SI.Pressure p_sat_mdT + "Saturation pressure at equilibrium temperature: T - 1e-6 K"; + + Modelica.Units.SI.DerPressureByTemperature dp_sat_dT_pdT + "Partial derivative of saturation pressure w.r.t. equilibrium temperature: + T + 1e-6 K"; + Modelica.Units.SI.DerPressureByTemperature dp_sat_dT_mdT + "Partial derivative of saturation pressure w.r.t. equilibrium temperature: + T - 1e-6 K"; + +equation + // + // Definition of derivatives + // + der(p_adsorpt) = 500 + "Predecsriped slope of p_adsorpt"; + der(T_adsorpt) = 95/20 + "Predecsriped slope of T_adsorpt"; + + // + // Calculation of properties + // + p_sat= Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt) + "Saturation pressure at equilibrium temperature"; + dp_sat_dT= Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt) + "Partial derivative of saturation pressure w.r.t. equilibrium temperature"; + ddp_sat_dT_dT= + (Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt + dT) - + Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt - dT)) / + (2*dT) + "Second-order partial derivative of saturation pressure w.r.t. equilibrium + temperature"; + + p_adsorpt_inv= SorpLib.Media.Functions.SorptionEquilibria.Utilities.p_ApsT( + A=A, + p_sat=p_sat, + T_adsorpt=T_adsorpt) + "Equilibrium pressure calculated via inverse function of the molar adsorption + potential"; + + A= SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=p_sat, + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + + // + // Calculation of derivatives + // + dA_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=p_sat, + T_adsorpt=T_adsorpt) + "Partial derivative of the molar adsorption potential w.r.t. pressure at + constant temperature"; + + dA_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=p_sat, + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dp_sat_dT) + "Partial derivative of the molar adsorption potential w.r.t. temperature at + constant pressure"; + + ddA_dp_adsorpt_dp_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dp_dp( + p_adsorpt=p_adsorpt, + p_sat=p_sat, + T_adsorpt=T_adsorpt) + "Second-order partial derivative of the molar adsorption potential w.r.t. + pressure at constant temperature"; + ddA_dT_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dT_dT( + p_adsorpt=p_adsorpt, + p_sat=p_sat, + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dp_sat_dT, + ddp_sat_dT_adsorpt_dT_adsorpt=ddp_sat_dT_dT) + "Second-order partial derivative of the molar adsorption potential w.r.t. + temperature at constant pressure"; + ddA_dp_adsorpt_dT_adsorpt= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.ddA_dp_dT( + p_adsorpt=p_adsorpt, + p_sat=p_sat, + T_adsorpt=T_adsorpt) + "Second-order partial derivative of the molar adsorption potential w.r.t. + pressure and temperature"; + + // + // Calculation of numerical derivatives + // + p_sat_pdT= Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt+dT) + "Saturation pressure at equilibrium temperature: T + 1e-6 K"; + p_sat_mdT= Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.psat(T=T_adsorpt-dT) + "Saturation pressure at equilibrium temperature: T - 1e-6 K"; + + dp_sat_dT_pdT= Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt+dT) + "Partial derivative of saturation pressure w.r.t. equilibrium temperature: + T + 1e-6 K"; + dp_sat_dT_mdT= Modelica.Media.Water.IF97_Utilities.BaseIF97.Basic.dptofT(T=T_adsorpt-dT) + "Partial derivative of saturation pressure w.r.t. equilibrium temperature: + T - 1e-6 K"; + + dA_dp_adsorpt_num=( + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt + dp, + p_sat=p_sat, + T_adsorpt=T_adsorpt) - + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt - dp, + p_sat=p_sat, + T_adsorpt=T_adsorpt))/(2*dp) + "Partial derivative of the molar adsorption potential w.r.t. pressure at + constant temperature calculated numerically"; + dA_dT_adsorpt_num=( + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=p_sat_pdT, + T_adsorpt=T_adsorpt + dT) - + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=p_sat_mdT, + T_adsorpt=T_adsorpt - dT))/(2*dT) + "Partial derivative of the molar adsorption potential w.r.t. temperature at + constant pressure calculated numerically"; + + ddA_dp_adsorpt_dp_adsorpt_num=( + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt + dp, + p_sat=p_sat, + T_adsorpt=T_adsorpt) - + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt - dp, + p_sat=p_sat, + T_adsorpt=T_adsorpt))/(2*dp) + "Second-order partial derivative of the molar adsorption potential w.r.t. + pressure at constant temperature calculated numerically"; + ddA_dT_adsorpt_dT_adsorpt_num=( + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=p_sat_pdT, + T_adsorpt=T_adsorpt + dT, + dp_sat_dT_adsorpt=dp_sat_dT_pdT) - + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=p_sat_mdT, + T_adsorpt=T_adsorpt - dT, + dp_sat_dT_adsorpt=dp_sat_dT_mdT))/(2*dT) + "Second-order partial derivative of the molar adsorption potential w.r.t. + temperature at constant pressure calculated numerically"; + ddA_dp_adsorpt_dT_adsorpt_num=( + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=p_sat_pdT, + T_adsorpt=T_adsorpt + dT) - + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=p_sat_mdT, + T_adsorpt=T_adsorpt - dT))/(2*dT) + "Second-order partial derivative of the molar adsorption potential w.r.t. + pressure and temperature calculated numerically"; + + // + // Definition of assertions: Check numerical implementation of isotherm model + // + assert(abs(p_adsorpt-p_adsorpt_inv) < 1e-6, + "Inverse function of molar adsorption potential is not valid: Deviation (|" + + String(abs(p_adsorpt-p_adsorpt_inv)) + + "|) is greater than 1e-6 Pa!", + level = AssertionLevel.warning); + assert(abs(dA_dp_adsorpt-dA_dp_adsorpt_num) < 1e-6, + "Partial derivative of molar adsorption potential w.r.t. pressure at " + + "constant temperature is not valid: Deviation (|" + + String(abs(dA_dp_adsorpt-dA_dp_adsorpt_num)) + + "|) is greater than 1e-6 J/mol/Pa!", + level = AssertionLevel.warning); + assert(abs(dA_dT_adsorpt-dA_dT_adsorpt_num) < 1e-6, + "Partial derivative of molar adsorption potential w.r.t. temperature at " + + "constant pressure is not valid: Deviation (|" + + String(abs(dA_dT_adsorpt-dA_dT_adsorpt_num)) + + "|) is greater than 1e-6 J/mol/K!", + level = AssertionLevel.warning); + assert(abs(ddA_dp_adsorpt_dp_adsorpt-ddA_dp_adsorpt_dp_adsorpt_num) < 1e-6, + "Second-order partial derivative of molar adsorption potential w.r.t. " + + "pressure at constant temperature is not valid: Deviation (|" + + String(abs(ddA_dp_adsorpt_dp_adsorpt-ddA_dp_adsorpt_dp_adsorpt_num)) + + "|) is greater than 1e-6 J/mol/Pa!", + level = AssertionLevel.warning); + assert(abs(ddA_dT_adsorpt_dT_adsorpt-ddA_dT_adsorpt_dT_adsorpt_num) < 1e-6, + "Second-order partial derivative of molar adsorption potential w.r.t. " + + "temperature at constant pressure is not valid: Deviation (|" + + String(abs(ddA_dT_adsorpt_dT_adsorpt-ddA_dT_adsorpt_dT_adsorpt_num)) + + "|) is greater than 1e-6 J/mol/K2!", + level = AssertionLevel.warning); + assert(abs(ddA_dp_adsorpt_dT_adsorpt-ddA_dp_adsorpt_dT_adsorpt_num) < 1e-6, + "Second-order partial derivative of molar adsorption potential w.r.t. " + + "pressure and temperature is not valid: Deviation (|" + + String(abs(ddA_dp_adsorpt_dT_adsorpt-ddA_dp_adsorpt_dT_adsorpt_num)) + + "|) is greater than 1e-6 J/mol/Pa/K!", + level = AssertionLevel.warning); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-08), +Documentation(revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'calc_A_ppsT' function and its corresponding +functions, such as inverse functions of partial derivatives. +<br/><br/> +To see the function behavior, plot the variable <i>A</i>, <i>dA_dp_adsorpt</i>, +<i>dA_dT_adsorpt</i>, <i>ddA_dp_adsorpt_dp_adsorpt</i>, <i>ddA_dT_adsorpt_dT_adsorpt</i>, +and <i>ddA_dp_adsorpt_dT_adsorpt</i> over the time. The simulation time is correctly +preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_A_ppsT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/Testers/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..34d508e217aeb40d2440b476e91b15cee6784b6c --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/Testers/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Utilities; +package Testers "Models to test and/or varify utility functions or models" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions and models of the +'Utilities' package. The test models check the implementation of the functions and +models and enable verification of their behavior. In addition, the test models +demonstrate the functions' and models' general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/Testers/package.order b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c52810741ba137e6685ac1f34313002eed4b9c62 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/Testers/package.order @@ -0,0 +1 @@ +Test_A_ppsT diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/dA_dT.mo b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/dA_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..4d824582208af9ee4ce38a00e1c7a6db88bb0ecd --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/dA_dT.mo @@ -0,0 +1,61 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Utilities; +function dA_dT + "Calculates the partial derivative of molar adsorption potential w.r.t. equilibrium temperature at constant pressure" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure p_sat + "Saturation pressure at the equilibrium temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Real dp_sat_dT_adsorpt(unit="Pa/K") + "Partial derivative of saturation pressure at the equilibrium temperature + w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT_adsorpt + "Partial derivative of the molar adsorption potential w.r.t. equilibrium + temperature at constant pressure" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + +algorithm + dA_dT_adsorpt := Modelica.Constants.R * ( + log(p_sat / p_adsorpt) + + T_adsorpt / p_sat * dp_sat_dT_adsorpt) + "Partial derivative of the molar adsorption potential w.r.t. equilibrium + temperature at constant pressure"; + + // + // Annotations + // + annotation (Inline=true, +Documentation(info="<html> +<p> +This function calculates the partial derivative of the molar adsorption potential +with respect to the equilibrium temperature <i>dA_dT_adsorpt</i> at constant pressure. +For more information about the molar adsorption potential <i>A</i>, check the +documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT\">SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end dA_dT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/dA_dp.mo b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/dA_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..1e322f10b3e681f146bad370635650c94f0df753 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/dA_dp.mo @@ -0,0 +1,55 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Utilities; +function dA_dp + "Calculates the partial derivative of molar adsorption potential w.r.t. equilibrium pressure at constant temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure p_sat + "Saturation pressure at the equilibrium temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp_adsorpt + "Partial derivative of the molar adsorption potential w.r.t. equilibrium + pressure at constant temperature" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + +algorithm + dA_dp_adsorpt := -Modelica.Constants.R * T_adsorpt / p_adsorpt + "Partial derivative of the molar adsorption potential w.r.t. equilibrium + pressure at constant temperature"; + + // + // Annotations + // + annotation (Inline=true, +Documentation(info="<html> +<p> +This function calculates the partial derivative of the molar adsorption potential +with respect to the equilibrium pressure <i>dA_dp_adsorpt</i> at constant temperature. +For more information about the molar adsorption potential <i>A</i>, check the +documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT\">SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end dA_dp; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/ddA_dT_dT.mo b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/ddA_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..93a16d8faecc1a3d94b136fc232d514e59a33dd5 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/ddA_dT_dT.mo @@ -0,0 +1,67 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Utilities; +function ddA_dT_dT + "Calculates the second-order partial derivative of molar adsorption potential w.r.t. equilibrium temperature at constant pressure" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure p_sat + "Saturation pressure at the equilibrium temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Real dp_sat_dT_adsorpt(unit="Pa/K") + "Partial derivative of saturation pressure at the equilibrium temperature + w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real ddp_sat_dT_adsorpt_dT_adsorpt(unit="Pa/K2") + "Second-order partial derivative of saturation pressure at the equilibrium + temperature w.r.t. temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerMolarAdsorptionPotentialByTemperatureTemperature ddA_dT_adsorpt_dT_adsorpt + "Second-order partial derivative of the molar adsorption potential w.r.t. + equilibrium temperature at constant pressure" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + +algorithm + ddA_dT_adsorpt_dT_adsorpt := Modelica.Constants.R * ( + 1 / p_sat * dp_sat_dT_adsorpt + + (1 / p_sat * dp_sat_dT_adsorpt - + T_adsorpt / p_sat^2 * dp_sat_dT_adsorpt^2 + + T_adsorpt / p_sat * ddp_sat_dT_adsorpt_dT_adsorpt)) + "Second-order partial derivative of the molar adsorption potential w.r.t. + equilibrium temperature at constant pressure"; + + // + // Annotations + // + annotation (Inline=true, +Documentation(info="<html> +<p> +This function calculates the second-order partial derivative of the molar adsorption +potential with respect to the equilibrium temperature <i>ddA_dT_adsorpt_dT_adsorpt</i> +at constant pressure. For more information about the molar adsorption potential +<i>A</i>, check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT\">SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddA_dT_dT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/ddA_dp_dT.mo b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/ddA_dp_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..7927936d541d70f9a45a560de0bf6ef04106ccc4 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/ddA_dp_dT.mo @@ -0,0 +1,55 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Utilities; +function ddA_dp_dT + "Calculates the second-order partial derivative of molar adsorption potential w.r.t. equilibrium pressure and temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure p_sat + "Saturation pressure at the equilibrium temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerMolarAdsorptionPotentialByPressureTemperature ddA_dp_adsorpt_dT_adsorpt + "Second-order partial derivative of the molar adsorption potential w.r.t. + equilibrium pressure and temperature" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + +algorithm + ddA_dp_adsorpt_dT_adsorpt := -Modelica.Constants.R / p_adsorpt + "Second-order partial derivative of the molar adsorption potential w.r.t. + equilibrium pressure and temperature"; + + // + // Annotations + // + annotation (Inline=true, +Documentation(info="<html> +<p> +This function calculates the second-prder partial derivative of the molar adsorption +potential with respect to the equilibrium pressure and temperature +<i>ddA_dp_adsorpt_dT_adsorpt</i>. For more information about the molar adsorption +potential <i>A</i>, check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT\">SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddA_dp_dT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/ddA_dp_dp.mo b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/ddA_dp_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..43def63411f32dc939fd9dffc306526f101db250 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/ddA_dp_dp.mo @@ -0,0 +1,56 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Utilities; +function ddA_dp_dp + "Calculates the second-order partial derivative of molar adsorption potential w.r.t. equilibrium pressure at constant temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure p_sat + "Saturation pressure at the equilibrium temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output + SorpLib.Units.DerMolarAdsorptionPotentialByPressurePressure dA_dp_adsorpt + "Second-order partial derivative of the molar adsorption potential w.r.t. + equilibrium pressure at constant temperature" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + +algorithm + dA_dp_adsorpt := Modelica.Constants.R * T_adsorpt / p_adsorpt^2 + "Second-order partial derivative of the molar adsorption potential w.r.t. + equilibrium pressure at constant temperature"; + + // + // Annotations + // + annotation (Inline=true, +Documentation(info="<html> +<p> +This function calculates the second-orderpartial derivative of the molar adsorption +potential with respect to the equilibrium pressure <i>ddA_dp_adsorpt_dp_adsorpt</i> +at constant temperature. For more information about the molar adsorption potential +<i>A</i>, check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT\">SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddA_dp_dp; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/p_ApsT.mo b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/p_ApsT.mo new file mode 100644 index 0000000000000000000000000000000000000000..75319873c52fa6e47f83c0ebb9ba27309fba46c3 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/p_ApsT.mo @@ -0,0 +1,65 @@ +within SorpLib.Media.Functions.SorptionEquilibria.Utilities; +function p_ApsT + "Calculates the inverse of the molar adsorption potential" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input SorpLib.Units.MolarAdsorptionPotential A "Molar adsorption potential" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure p_sat + "Saturation pressure at the equilibrium temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature of the adsorpt phase" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure of the adsorpt phase" + annotation (Dialog(tab="General", group="Outputs", + enable=false)); + +algorithm + p_adsorpt := p_sat / exp(A / (Modelica.Constants.R * T_adsorpt)) + "Equilibrium pressure of the adsorpt phase"; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=false, +LateInline=true, +inverse(A=A_ppsT(p_adsorpt,p_sat,T_adsorpt)), +Documentation(info="<html> +<p> +This function calculates the equilibrium pressure <i>p<sub>adsorpt</sub></i> for +a given molar adsorption potential <i>A</i>. +</p> + +<h4>Main equations</h4> +<p> +The equilibrium pressure <i>p<sub>adsorpt</sub></i> is defined as follows: +</p> +<pre> + p<sub>adsorpt</sub> = p<sub>sat</sub> * <strong>exp</strong>(-A / (R * T<sub>adsorpt</sub>)); +</pre> + +<h4>References</h4> +<ul> + <li> + Do, D. D. (1998). Adsorption Analysis: Equilibria and Kinetics, 1st Edition, ISBN 978-1-86094-130-6, Imperial College Press. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 2, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end p_ApsT; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..bc3bd7005b2c94a355976f8b4ecac4fb0f7fb29a --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SorptionEquilibria; +package Utilities "Package containing utility functions and models for calculating sorption equilibria" +extends Modelica.Icons.UtilitiesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains utility functions and models required to calculate sorption +equilibria of pure component or multicomponent adsorption. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Utilities; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/Utilities/package.order b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/package.order new file mode 100644 index 0000000000000000000000000000000000000000..d798135a1b51e5943ca6b129648bb368c6629d2b --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/Utilities/package.order @@ -0,0 +1,8 @@ +A_ppsT +p_ApsT +dA_dp +dA_dT +ddA_dp_dp +ddA_dT_dT +ddA_dp_dT +Testers diff --git a/SorpLib/Media/Functions/SorptionEquilibria/package.mo b/SorpLib/Media/Functions/SorptionEquilibria/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..4d9634ca9a7aae27ef535e3fcf93492bc007f480 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.Functions; +package SorptionEquilibria "Functions required to calculate sorption equilibria" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains isotherm models for pure component and multi-component +adsorption. Please check the documentation of the individual packages for more +details on the implemented isotherm models and functions provided for each +isotherm model. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end SorptionEquilibria; diff --git a/SorpLib/Media/Functions/SorptionEquilibria/package.order b/SorpLib/Media/Functions/SorptionEquilibria/package.order new file mode 100644 index 0000000000000000000000000000000000000000..89e2f432abec48aad617588acdb4b8e03bbc27e1 --- /dev/null +++ b/SorpLib/Media/Functions/SorptionEquilibria/package.order @@ -0,0 +1,6 @@ +BaseClasses +Interfaces +Records +PureComponents +MultiComponents +Utilities diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialPureIntegrad_cp.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialPureIntegrad_cp.mo new file mode 100644 index 0000000000000000000000000000000000000000..0c5fe5019c77bf70fefcee92662aef99cd8b96e0 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialPureIntegrad_cp.mo @@ -0,0 +1,77 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses; +partial function PartialPureIntegrad_cp + "Base function for integrand-based functions calculating the specific heat capacities of adsorpt phases for pure components" + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPure_cp; + input SorpLib.Units.Uptake x_adsorpt + "Uptake" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input Real dc_dT[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + input Real ddc_dT_dT[:] + "Second-order partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT + "Pressure as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dT func_dx_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dp_dp func_ddx_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dT_dT func_ddx_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dp_dT func_ddx_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate the +specific heat capacities of the adsorpt phase for pure components. These function +use integrals and, thus, integrad functions to calculate the specific heat +capacity. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureIntegrad_cp; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialPureIntegrand.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialPureIntegrand.mo new file mode 100644 index 0000000000000000000000000000000000000000..bb41a7e0f18f37ae95868cc1861985c028d0928f --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialPureIntegrand.mo @@ -0,0 +1,96 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses; +partial function PartialPureIntegrand + "Base function for integrand functions for pure components" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real ddc_dT_dT[:] + "Second-order partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT func_p_xT + "Pressure as function of uptake and temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp func_dx_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dT func_dx_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dp_dp func_ddx_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dT_dT func_ddx_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dp_dT func_ddx_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at contant + temperature"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at contant + pressure"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for integrand functions that may be +required to calculate specific heat capacities of the adsorpt phase for pure +components. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureIntegrand; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialPure_cp.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialPure_cp.mo new file mode 100644 index 0000000000000000000000000000000000000000..77d8d081a876ebb7f12ae9fbe899d0d3f1a9b572 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialPure_cp.mo @@ -0,0 +1,42 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses; +partial function PartialPure_cp + "Base function for functions calculating the specific heat capacities of adsorpt phases for pure components" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificHeatCapacity cp_adsorpt + "Specific heat capacitiy of adsorpt" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate the +specific heat capacities of the adsorpt phase for pure components. +<br/><br/> +This partial function defines the temperature <i>T_adsorpt</i> as input and the +specific heat capacity <i>cp_adsorpt</i> as output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPure_cp; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialTestPure.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialTestPure.mo new file mode 100644 index 0000000000000000000000000000000000000000..ceb1764589e9d1e4f2baafd4891a532639fc21de --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/PartialTestPure.mo @@ -0,0 +1,173 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses; +partial model PartialTestPure + "Base model for testers of specific heat capacity models of the adsorpt phase describing pure component adsorption" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_ph + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Medium"), + choicesAllMatching = true); + + parameter Integer no_coefficients = 6 + "Number of coefficients of selected isotherm model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Pressure p_adsorpt_start = 700 + "Start value of equilibrium pressure" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Temperature T_adsorpt_start = 278.15 + "Start value of equilibrium temperature" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.MolarMass M_adsorptive = 0.018 + "Molar mass of adsorptive" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference used to calculated partial derivatives numerically" + annotation (Dialog(tab="General",group="Numerics"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculated partial derivatives numerically" + annotation (Dialog(tab="General",group="Numerics"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Units.Uptake dx = 1e-3 + "Uptake difference used to calculated partial derivatives numerically" + annotation (Dialog(tab="General",group="Numerics"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_adsorpt(start=p_adsorpt_start, fixed=true) + "Pressure"; + Modelica.Units.SI.Temperature T_adsorpt(start=T_adsorpt_start, fixed=true) + "Temperature"; + SorpLib.Units.Uptake x_adsorpt + "Uptake"; + + Medium.ThermodynamicState state_adsorptive_pT + "State properties of adsorptive at p_adsorpt and T_adsorpt"; + Medium.ThermodynamicState state_bubble_T + "State properties of bubble point at T_adsorpt"; + Medium.ThermodynamicState state_dew_T + "State properties of dew point at T_adsorpt"; + + Modelica.Units.SI.SpecificHeatCapacity cp_adsorptive + "Specific heat capacitiy of adsorptive"; + Modelica.Units.SI.SpecificHeatCapacity cp_sat_bubble + "Specific heat capacitiy at saturated bubble line at T_adsorpt"; + Modelica.Units.SI.SpecificHeatCapacity cp_sat_dew + "Specific heat capacitiy at saturated dew line at T_adsorpt"; + + Modelica.Units.SI.SpecificHeatCapacity cp_adsorpt + "Specific heat capacitiy of adsorpt"; + Modelica.Units.SI.SpecificHeatCapacity cp_adsorpt_CC + "Specific heat capacitiy of adsorpt calculated using molar adsorption enthalpy + according to Clausius Clapeyron"; + Modelica.Units.SI.SpecificHeatCapacity cp_adsorpt_Dubinin + "Specific heat capacitiy of adsorptive using molar adsorption enthalpy + according to Dubinin model"; + +protected + Real c[no_coefficients] + "Coefficients of the isotherm model"; + Real c_pdT[no_coefficients] + "Coefficients of the isotherm model: T + dT"; + Real c_mdT[no_coefficients] + "Coefficients of the isotherm model: T - dT"; + + Real dc_dT[no_coefficients] + "Partial derivative of coefficients of the isotherm model w.r.t. temperature"; + Real dc_dT_pdT[no_coefficients] + "Partial derivative of coefficients of the isotherm model w.r.t. temperature: + T + dT"; + Real dc_dT_mdT[no_coefficients] + "Partial derivative of coefficients of the isotherm model w.r.t. temperature: + T - dT"; + + Real ddc_dT_dT[no_coefficients] + "Second-order partial derivative of coefficients of the isotherm model w.r.t. + temperature"; + + Medium.SaturationProperties sat_T + "Saturated state properties at T_adsorpt"; + Medium.SaturationProperties sat_T_pdT + "Saturated state properties at T_adsorpt: T + dT"; + Medium.SaturationProperties sat_T_mdT + "Saturated state properties at T_adsorpt: T - dT"; + +equation + // + // Calculation of state properties + // + sat_T = Medium.setSat_T(T=T_adsorpt) + "Saturated state properties at T_adsorpt"; + sat_T_pdT = Medium.setSat_T(T=T_adsorpt+dT) + "Saturated state properties at T_adsorpt: T + dT"; + sat_T_mdT = Medium.setSat_T(T=T_adsorpt-dT) + "Saturated state properties at T_adsorpt: T - dT"; + + state_adsorptive_pT = Medium.setState_pTX( + p=p_adsorpt, + T=T_adsorpt) + "State properties of adsorptive at p_adsorpt and T_adsorpt"; + + state_bubble_T = Medium.setBubbleState(sat=sat_T) + "State properties of bubble point at T_adsorpt"; + state_dew_T = Medium.setDewState(sat=sat_T) + "State properties of dew point at T_adsorpt"; + + // + // Calculate properties + // + cp_adsorptive = Medium.specificHeatCapacityCp(state=state_adsorptive_pT) + "Specific heat capacitiy of adsorptive"; + cp_sat_bubble = Medium.specificHeatCapacityCp(state=state_bubble_T) + "Specific heat capacitiy at saturated bubble line at T_adsorpt"; + cp_sat_dew = Medium.specificHeatCapacityCp(state=state_dew_T) + "Specific heat capacitiy at saturated dew line at T_adsorpt"; + + // + // Annotations + // + annotation ( + Icon(coordinateSystem(preserveAspectRatio=false)), + Diagram(coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the basic model for all testers of specific heat capacities +of the adsorpt phase for pure components. This partial model defines all some +relevant parameters and variables that are required for most specific heat capacity +models. +<br/><br/> +Models that inherit properties from this partial model have to specify the +<i>medium</i> and test setup. Besides, the coefficients of the isotherm model +(i.e., <i>c</i>, <i>c_pdT</i>, and <i>c_mdT</i>) and their partial derivatives +with respect to temperature (i.e., <i>dc_dT</i>, <i>dc_dT_pdT</i>, <i>dc_dT_mdT</i>, +and <i>ddc_dT_dT</i>) have to be implemented. Additionally, equations for the +following variables must be implemted: <i>p_adsorpt</i>, <i>T_adsorpt</i>, +<i>x_adsorpt</i>, <i>cp_adsorpt</i>, <i>cp_adsorpt_CC</i>, and <i>cp_adsorpt_Dubinin</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialTestPure; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/package.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..99f2c02f10bd57b86bfd0e58ed6fb12908da7102 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt; +package BasesClasses "Base classes used to build new functions calculating specific heat capacities" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This package contains partial basic functions and models. These partial functions +and models contain fundamental definitions of functions calculating specific heat +capacities of adsorpt phases for pure and multi-component adsorption. The content +of this package is only of interest when adding new functions to the library. +</p> +</html>")); +end BasesClasses; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/package.order b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..282c03fcd4e49c11cafac3e5073f96348aacb91f --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/BasesClasses/package.order @@ -0,0 +1,4 @@ +PartialPureIntegrand +PartialPure_cp +PartialPureIntegrad_cp +PartialTestPure diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_beta_pT.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_beta_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..9c30424e956e39469d7006e4782e767ca83d74c4 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_beta_pT.mo @@ -0,0 +1,46 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces; +partial function Partial_beta_pT + "Base function for functions calculating isobaric expansion coefficients as function of pressure and temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.RelativePressureCoefficient beta + "Isobaric expansion coefficient" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotation + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate isobaric +expansion coefficients <i>beta</i> as function of pressure <i>p</i> and temperature +<i>T</i>. +<br/><br/> +Specific functions derived from this partial function can be used as functional +arguments in the integrad functions. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_beta_pT; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dbeta_dT.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dbeta_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..32a32259175c1476be79b7b95ecb0619cc385687 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dbeta_dT.mo @@ -0,0 +1,52 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces; +partial function Partial_dbeta_dT + "Base function for functions calculating the partial derivative of isobaric expansion coefficients w.r.t. temperature at constant pressure" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. temperature + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerIsobaricExpansionCoefficientByTemperature dbeta_dT + "Partial derivative of isobaric expansion coefficients w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotation + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate partial +derivatives of isobaric expansion coefficients with respect to temperature at constant +pressure <i>dbeta_dT</i> as function of pressure <i>p</i> and temperature <i>T</i>. +<br/><br/> +Specific functions derived from this partial function can be used as functional +arguments in the integrad functions. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_dbeta_dT; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dbeta_dp.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dbeta_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..68782f98413efaa2ff52d0f286ad51f84ff707e8 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dbeta_dp.mo @@ -0,0 +1,52 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces; +partial function Partial_dbeta_dp + "Base function for functions calculating the partial derivative of isobaric expansion coefficients w.r.t. pressure at constant temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerIsobaricExpansionCoefficientByPressure dbeta_dp + "Partial derivative of isobaric expansion coefficients w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotation + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate partial +derivatives of isobaric expansion coefficients with respect to pressure at constant +temperature <i>dbeta_dp</i> as function of pressure <i>p</i> and temperature <i>T</i>. +<br/><br/> +Specific functions derived from this partial function can be used as functional +arguments in the integrad functions. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_dbeta_dp; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dh_adsorptiveToLiquid_dT.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dh_adsorptiveToLiquid_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..a6677db3a265d142c43d8f976e5a0c2b7a084fac --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dh_adsorptiveToLiquid_dT.mo @@ -0,0 +1,53 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces; +partial function Partial_dh_adsorptiveToLiquid_dT + "Base function for functions calculating the partial derivative of specific enthalpy differences between adsorptive state and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant pressure" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. temperature + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificHeatCapacity dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotation + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate the partial +derivative of specific enthalpies of vaprozation with respect to temperature at constant +pressure <i>dh_vap_dp</i> as function of temperature <i>T</i>. +<br/><br/> +Specific functions derived from this partial function can be used as functional +arguments in the integrad functions. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_dh_adsorptiveToLiquid_dT; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dh_adsorptiveToLiquid_dp.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dh_adsorptiveToLiquid_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..1e1cd11d27e352d6a4cc9450418e25c628440975 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dh_adsorptiveToLiquid_dp.mo @@ -0,0 +1,53 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces; +partial function Partial_dh_adsorptiveToLiquid_dp + "Base function for functions calculating the partial derivative of specific enthalpy differences between adsorptive state and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerSpecificEnthalpyByPressure dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotation + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate the partial +derivative of specific enthalpies of vaprozation with respect to pressure at constant +temperature <i>dh_vap_dp</i> as function of temperature <i>T</i>. +<br/><br/> +Specific functions derived from this partial function can be used as functional +arguments in the integrad functions. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_dh_adsorptiveToLiquid_dp; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dh_dT.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dh_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..89a63616fb22357bccf55c214842c4c9cc6cbd11 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dh_dT.mo @@ -0,0 +1,52 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces; +partial function Partial_dh_dT + "Base function for functions calculating the partial derivative of specific enthalpies w.r.t. temperautre at constant pressure" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. temperature + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificHeatCapacity dh_dT + "Partial derivative of the specific enthalpy w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotation + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate the partial +derivative of specific enthalpies w.r.t. temperature at constant pressure <i>dh_dT</i> +as function of pressure <i>p</i> and temperature <i>T</i>. +<br/><br/> +Specific functions derived from this partial function can be used as functional +arguments in the integrad functions. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_dh_dT; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dv_dT.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dv_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..c634b72ce00ebf397ce1772d2f565d5e94f8346c --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dv_dT.mo @@ -0,0 +1,51 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces; +partial function Partial_dv_dT + "Base function for functions calculating the partial derivative of specific volumes w.r.t. temperature at constant pressure" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. temperature + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerSpecificVolumeByTemperature dv_dT + "Partial derivative of specific volume w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotation + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate partial +derivatives of specific volumes with respect to temperature at constant pressure +<i>dv_dT</i> as function of pressure <i>p</i> and temperature <i>T</i>. +<br/><br/> +Specific functions derived from this partial function can be used as functional +arguments in the integrad functions. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_dv_dT; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dv_dp.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dv_dp.mo new file mode 100644 index 0000000000000000000000000000000000000000..39aa0ee4b8dcb7efe1b49a3f2ab20a2006987724 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_dv_dp.mo @@ -0,0 +1,51 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces; +partial function Partial_dv_dp + "Base function for functions calculating the partial derivative of specific volumes w.r.t. pressure at constant temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerSpecificVolumeByPressure dv_dp + "Partial derivative of specific volume w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotation + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate partial +derivatives of specific volumes with respect to pressure at constant temperature +<i>dv_dp</i> as function of pressure <i>p</i> and temperature <i>T</i>. +<br/><br/> +Specific functions derived from this partial function can be used as functional +arguments in the integrad functions. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_dv_dp; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_h_adsorptiveToLiquid_pT.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_h_adsorptiveToLiquid_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..7cd6213520fb45a9549a478a56a934bcaa8ff628 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_h_adsorptiveToLiquid_pT.mo @@ -0,0 +1,46 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces; +partial function Partial_h_adsorptiveToLiquid_pT + "Base function for functions calculating specific enthalpy differences between adsorptive state and saturated liquid state (i.e., bubble point)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotation + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate specific +enthalpies of vaprozation <i>h_vap</i> as function of temperature <i>T</i>. +<br/><br/> +Specific functions derived from this partial function can be used as functional +arguments in the integrad functions. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_h_adsorptiveToLiquid_pT; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_v_pT.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_v_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..7e04c07876f816f6fd66c5193d040de9e8326c31 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/Partial_v_pT.mo @@ -0,0 +1,45 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces; +partial function Partial_v_pT + "Base function for functions calculating specific volumes as function of pressure and temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificVolume v + "Specific volume" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotation + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for functions that calculate specific +volumes <i>v</i> as function of pressure <i>p</i> and temperature <i>T</i>. +<br/><br/> +Specific functions derived from this partial function can be used as functional +arguments in the integrad functions. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_v_pT; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/package.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e16ea8e6b0043f0e1c596b80e1c615f21f7539e7 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands; +package Interfaces "Package containing interfaces used as function inputs" +extends Modelica.Icons.InterfacesPackage; + +annotation (Documentation(revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This package contains partial functions used as functional arguments for integrand +functions. +</p> +</html>")); +end Interfaces; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/package.order b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/package.order new file mode 100644 index 0000000000000000000000000000000000000000..daec3ed1a176f15dbb5b43ffe0e609e3d355cf41 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/Interfaces/package.order @@ -0,0 +1,10 @@ +Partial_v_pT +Partial_dv_dp +Partial_dv_dT +Partial_beta_pT +Partial_dbeta_dp +Partial_dbeta_dT +Partial_dh_dT +Partial_h_adsorptiveToLiquid_pT +Partial_dh_adsorptiveToLiquid_dp +Partial_dh_adsorptiveToLiquid_dT diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_ads_dT_x.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_ads_dT_x.mo new file mode 100644 index 0000000000000000000000000000000000000000..3f739d8a186caa8814ce13fb0d67a8cb2d5db7d2 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_ads_dT_x.mo @@ -0,0 +1,284 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands; +function dh_ads_dT_x + "Partial derivative of the molar adsorption enthalpy w.r.t. temperature at constant uptake" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrand; + + // + // Definition of inputs + // + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorptive_pT "Specific volume of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorptive_dp "Partial derivative of the specific volume of the adsorptive w.r.t. pressure + at constant temperature" annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorptive_dT "Partial derivative of the specific volume of the adsorptive w.r.t. temperature + at constant pressure" annotation (Dialog(tab="General", group="Inputs")); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorpt_pT "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorpt_dp "Partial derivative of the specific volume of the adsorpt w.r.t. pressure + at constant temperature" annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorpt_dT "Partial derivative of the specific volume of the adsorpt w.r.t. temperature + at constant pressure" annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables +protected + Modelica.Units.SI.SpecificVolume v_adsorptive + "Specific volume of the adsorptive"; + SorpLib.Units.DerSpecificVolumeByPressure dv_adsorptive_dp + "Partial derivative of specific volume of the adsorptive w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorptive_dT + "Partial derivative of specific volume of the adsorptive w.r.t. temperature at + constant pressure"; + + Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt"; + SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := func_p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := func_dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := func_dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp := func_ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT := func_ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT := func_ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius Clyperon assumptions + // + v_adsorptive := func_v_adsorptive_pT( + p=p_adsorpt, + T=T_adsorpt) + "Specific volume of the adsorptive"; + dv_adsorptive_dp :=func_dv_adsorptive_dp( + p=p_adsorpt, + T=T_adsorpt, + dp=dp) + "Partial derivative of specific volume of the adsorptive w.r.t. pressure at + constant temperature"; + dv_adsorptive_dT :=func_dv_adsorptive_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of specific volume of the adsorptive w.r.t. temperature at + constant pressure"; + + v_adsorpt :=func_v_adsorpt_pT( + p=p_adsorpt, + T=T_adsorpt) + "Specific volume of the adsorpt"; + dv_adsorpt_dp :=func_dv_adsorpt_dp( + p=p_adsorpt, + T=T_adsorpt, + dp=dp) + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature"; + dv_adsorpt_dT :=func_dv_adsorpt_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure"; + + // + // Calculation of partial derivatives of molar sorption enthalpy + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=v_adsorptive, + v_adsorpt=v_adsorpt, + dv_adsorptive_dp=dv_adsorptive_dp, + dv_adsorpt_dp=dv_adsorpt_dp, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=v_adsorptive, + v_adsorpt=v_adsorpt, + dv_adsorptive_dT=dv_adsorptive_dT, + dv_adsorpt_dT=dv_adsorpt_dT, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + else + // + // Use Clausius Clyperon assumptions: No further propiertes are required + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + end if; + + // + // Calculation of the integrand + // + y := dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the molar adsorption ethalpy +with respect to temperature at constant uptake: +</p> +<pre> + (∂Δh<sub>ads</sub>/∂T)<sub>x</sub> = (∂Δh<sub>ads</sub>/∂T)<sub>p</sub> - (∂Δh<sub>ads</sub>/∂p)<sub>T</sub> * (∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub>; +</pre> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads</sub></i> is defined as difference +of the specific enthalpy of the gas/vapor phase <i>h<sub>adsorptive</sub></i> and the +adsorpt phase <i>h<sub>adsorpt</sub></i>: +</p> +<pre> + Δh<sub>ads</sub> = h<sub>adsorptive</sub> - h<sub>adsorpt</sub> = T * M<sub>adsorptive</sub> * (v<sub>adsorptive</sub> - v<sub>adsorpt</sub>) (dp/dT) ≈ T * M<sub>adsorptive</sub> * (v<sub>adsorptive</sub> - v<sub>adsorpt</sub>) * (-(∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub>); +</pre> +<p> +Herein, <i>M<sub>adsorptive</sub></i> is the molar mass of the adsorptive, <i>T</i> +is the temperature, <i>v<sub>adsorptive</sub></i> ist the specific volume of the +adsorptive, <i>v<sub>adsorpt</sub></i> ist the specific volume of the adsorpt, +<i>dx/dp</i> is the partial derivative of the uptake with respect to the pressure +at constant temperature, and <i>dx/dT</i> is the partial derivative of the uptake +with respect to the temperature at constant pressure. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Inert sorbent. + </li> + <li> + Neglecting the termn <i>(∂p/∂x)<sub>T</sub> * (dx/dp)</i> of term + <i>dp/dT = -(∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub> + + (∂p/∂x)<sub>T</sub> * + (dx/dp)</i>. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Chakraborty, A. and Saha, B.B. and Ng, K.C. and Koyama (2006). On the thermodynamic modeling of the isosteric heat of adsorption and comparison with experiments, Applied Physics Letters, 89:171901. DOI: http://doi.org/10.1063/1.2360925. + </li> + <li> + Chakraborty, A. and Saha, B.B. and Ng, K.C. and Koyama, S. and Srinivasan, K. (2009). Theoretical Insight of Physical Adsorption for a Single-Component Adsorbent + Adsorbate System: I. Thermodynamic Property Surfaces, Langmuir, 25:2204-221. DOI: http://doi.org/10.1021/la803289p. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_ads_dT_x; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_ads_dT_x_CC.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_ads_dT_x_CC.mo new file mode 100644 index 0000000000000000000000000000000000000000..4510cfc14e9b8d0849ced2825f1b99cafc879d2f --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_ads_dT_x_CC.mo @@ -0,0 +1,140 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands; +function dh_ads_dT_x_CC + "Partial derivative of the molar adsorption enthalpy w.r.t. temperature at constant uptake according to Clausius Clapeyron" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrand; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := func_p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := func_dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := func_dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp := func_ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT := func_ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT := func_ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Calculation of partial derivatives of molar sorption enthalpy + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + // + // Calculation of the integrand + // + y := dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the molar adsorption ethalpy +with respect to temperature at constant uptake. The molar adsorption enthalpy is +calculated using Clausius Clapeyron assumptions: +</p> +<pre> + (∂Δh<sub>ads</sub>/∂T)<sub>x</sub> = (∂Δh<sub>ads</sub>/∂T)<sub>p</sub> - (∂Δh<sub>ads</sub>/∂p)<sub>T</sub> * (∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub>; +</pre> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads</sub></i> is defined as difference +of the specific enthalpy of the gas/vapor phase <i>h<sub>adsorptive</sub></i> and the +adsorpt phase <i>h<sub>adsorpt</sub></i>: +</p> +<pre> + Δh<sub>ads</sub> = h<sub>adsorptive</sub> - h<sub>adsorpt</sub> = R * T<sup>2</sup> / p * (∂p/∂T)<sub>x</sub> = R * T<sup>2</sup> / p * (-(∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub>); +</pre> +<p> +Herein, <i>R</i> is the ideal gas constant, <i>p</i> is the pressure, <i>T</i> is +the temperature, <i>(∂x/∂p)<sub>T</sub></i> is the partial derivative of +the uptake with respect to the pressure at constant temperature, and +<i>(∂x/∂T)<sub>p</sub></i> is the partial derivative of the uptake with +respect to the temperature at constant pressure. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The specific volume of the adsorpt phase can be neglected compared to the specific + volume of the adsorptive phase. + </li> + <li> + The adsorptive can be treated as an ideal gas (i.e., p * V = n * R * T). + </li> + <li> + Inert sorbent. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_ads_dT_x_CC; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_ads_dT_x_Dubinin.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_ads_dT_x_Dubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..cef25a33d50cdd887ae1cb60f3d2a6d3862accdb --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_ads_dT_x_Dubinin.mo @@ -0,0 +1,410 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands; +function dh_ads_dT_x_Dubinin + "Partial derivative of the molar adsorption enthalpy w.r.t. temperature at constant uptake according to the model of Dubinin" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrand; + + // + // Definition of inputs + // + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_h_adsorptiveToLiquid_pT + func_h_adsorptiveToLiquid_pT "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_adsorptiveToLiquid_dp + func_dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_adsorptiveToLiquid_dT + func_dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorpt_pT "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorpt_dp "Partial derivative of the specific volume of the adsorpt + w.r.t. pressure + at constant temperature" annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorpt_dT + "Partial derivative of the specific volume of the adsorpt w.r.t. temperature + at constant pressure" annotation (Dialog(tab="General", group="Inputs")); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_beta_pT + func_beta_adsorpt_pT + "Isobaric expansion coefficient of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dbeta_dp + func_dbeta_adsorpt_dp + "Partial derivative of the isobaric expansion coefficient of the adsorpt w.r.t. + pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dbeta_dT + func_dbeta_adsorpt_dT + "Partial derivative of the isobaric expansion coefficient of the adsorpt w.r.t. + temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dW_dA func_dW_dA + "Partial derivative of the characteristic curve w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dA func_ddW_dA_dA + "Second-order partial derivative of the characteristic curve w.r.t. molar + adsorption potential at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dT func_ddW_dA_dT + "Second-order partial derivative of the characteristic curve w.r.t. molar + adsorption potential and temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables +protected + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + SorpLib.Units.DerSpecificEnthalpyByPressure dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt"; + SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure"; + + Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Isobaric expansion coefficient of the adsorpt"; + SorpLib.Units.DerIsobaricExpansionCoefficientByPressure dbeta_adsorpt_dp + "Partial derivative of isobaric expansion coefficient of the adsorpt w.r.t. + pressure at constant temperature"; + SorpLib.Units.DerIsobaricExpansionCoefficientByTemperature dbeta_adsorpt_dT + "Partial derivative of isobaric expansion coefficient of the adsorpt w.r.t. + temperature at constant pressure"; + + SorpLib.Units.MolarAdsorptionPotential A + "Molar adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := func_p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := func_dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := func_dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp := func_ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT := func_ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT := func_ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius Clyperon assumptions + // + h_adsorptiveToLiquid := func_h_adsorptiveToLiquid_pT( + p=p_adsorpt, + T=T_adsorpt) + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + dh_adsorptiveToLiquid_dp:=func_dh_adsorptiveToLiquid_dp( + p=p_adsorpt, + T=T_adsorpt, + dp=dp) + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + dh_adsorptiveToLiquid_dT:=func_dh_adsorptiveToLiquid_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + v_adsorpt :=func_v_adsorpt_pT( + p=p_adsorpt, + T=T_adsorpt) + "Specific volume of the adsorpt"; + dv_adsorpt_dp :=func_dv_adsorpt_dp( + p=p_adsorpt, + T=T_adsorpt, + dp=dp) + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature"; + dv_adsorpt_dT :=func_dv_adsorpt_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure"; + + beta_adsorpt:=func_beta_adsorpt_pT( + p=p_adsorpt, + T=T_adsorpt) + "Isobaric expansion coefficient of the adsorpt"; + dbeta_adsorpt_dp:=func_dbeta_adsorpt_dp( + p=p_adsorpt, + T=T_adsorpt, + dp=dp) + "Partial derivative of isobaric expansion coefficient of the adsorpt w.r.t. + pressure at constant temperature"; + dbeta_adsorpt_dT:=func_dbeta_adsorpt_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of isobaric expansion coefficient of the adsorpt w.r.t. + temperature at constant pressure"; + + A := SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + dA_dp:=SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + dA_dT:=SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT[1]) + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + dW_dA:=func_dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dA:=func_ddW_dA_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dT:=func_ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + + // + // Calculation of partial derivatives of molar sorption enthalpy + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=u, + dx_adsorpt_dp=dx_adsorpt_dp, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dp=dh_adsorptiveToLiquid_dp, + v_adsorpt=v_adsorpt, + dv_adsorpt_dp=dv_adsorpt_dp, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dp=dbeta_adsorpt_dp, + dA_dp=dA_dp, + dW_dA=dW_dA, + ddW_dA_dA=ddW_dA_dA) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=u, + dx_adsorpt_dT=dx_adsorpt_dT, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dT=dh_adsorptiveToLiquid_dT, + v_adsorpt=v_adsorpt, + dv_adsorpt_dT=dv_adsorpt_dT, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dT=dbeta_adsorpt_dT, + dA_dT=dA_dT, + dW_dA=dW_dA, + ddW_dA_dT=ddW_dA_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + else + // + // Use Clausius Clyperon assumptions: No further propiertes are required + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + end if; + + // + // Calculation of the integrand + // + y := dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the molar adsorption ethalpy +with respect to temperature at constant uptake. The molar adsorption enthalpy is +calculated according to the model of Dubinin: +</p> +<pre> + (∂Δh<sub>ads</sub>/∂T)<sub>x</sub> = (∂Δh<sub>ads</sub>/∂T)<sub>p</sub> - (∂Δh<sub>ads</sub>/∂p)<sub>T</sub> * (∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub>; +</pre> +</p> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads</sub></i> is defined as difference +of the specific enthalpy of the gas/vapor phase <i>h<sub>adsorptive</sub></i> and the +adsorpt phase <i>h<sub>adsorpt</sub></i>: +</p> +<pre> + Δh<sub>ads</sub> = h<sub>adsorptive</sub> - h<sub>adsorpt</sub> = M<sub>adsorptive</sub> * Δh<sub>adsorptiveToLiquid</sub> + A - β * T * v<sub>adsorpt</sub> * x * 1 / (∂W/∂A)<sub>p,T</sub>; +</pre> +<p> +Herein, <i>M<sub>adsorptive</sub></i> is the molar mass of the adsorptive, <i>T</i> +is the temperature, <i>x</i> is the uptake, <i>v<sub>adsorpt</sub></i> is the specific +volume of the adsorpt, <i>β</i> is the isobaric expansion coefficient of the +adsorpt, <i>Δh<sub>adsorptiveToLiquid</sub></i> is the specific enthalpy difference +between adsorptive phase and saturated liquid phase (i.e., bubble point), <i>A</i> is +the molar adsorption potential, and <i>(∂W/∂A)<sub>p,T</sub></i> is the partial +derivative of the filled pore volume with respect to the molar adsorption potential at +constant pressure and temperature. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Inert sorbent. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Schwamberger, V. (2016). Thermodynamic and numerical investigation of a novel sorption cycle for application in adsorption heat pumps and chillers (in German), PhD thesis, Karlsruhe. +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_ads_dT_x_Dubinin; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_adsorpt_dT_x.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_adsorpt_dT_x.mo new file mode 100644 index 0000000000000000000000000000000000000000..6a854e1c116eb4511aaae34f0a0e448a9c8d43d0 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_adsorpt_dT_x.mo @@ -0,0 +1,318 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands; +function dh_adsorpt_dT_x + "Partial derivative of the adsorpt w.r.t. temperature at constant uptake" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrand; + + // + // Definition of inputs + // + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorptive_pT "Specific volume of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorptive_dp "Partial derivative of the specific volume of the adsorptive w.r.t. pressure + at constant temperature" annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorptive_dT "Partial derivative of the specific volume of the adsorptive w.r.t. temperature + at constant pressure" annotation (Dialog(tab="General", group="Inputs")); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_dT + "Partial deriivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_ig_dT + "Partial deriivative of the specific enthalpy of the adsorptive (ideal gas) + w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorpt_pT "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorpt_dp "Partial derivative of the specific volume of the adsorpt w.r.t. pressure + at constant temperature" annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorpt_dT "Partial derivative of the specific volume of the adsorpt w.r.t. temperature + at constant pressure" annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables +protected + Modelica.Units.SI.SpecificVolume v_adsorptive + "Specific volume of the adsorptive"; + SorpLib.Units.DerSpecificVolumeByPressure dv_adsorptive_dp + "Partial derivative of specific volume of the adsorptive w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorptive_dT + "Partial derivative of specific volume of the adsorptive w.r.t. temperature at + constant pressure"; + + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptive_dT + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt"; + SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := func_p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := func_dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := func_dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp := func_ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT := func_ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT := func_ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius Clyperon assumptions + // + v_adsorptive := func_v_adsorptive_pT( + p=p_adsorpt, + T=T_adsorpt) + "Specific volume of the adsorptive"; + dv_adsorptive_dp :=func_dv_adsorptive_dp( + p=p_adsorpt, + T=T_adsorpt, + dp=dp) + "Partial derivative of specific volume of the adsorptive w.r.t. pressure at + constant temperature"; + dv_adsorptive_dT :=func_dv_adsorptive_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of specific volume of the adsorptive w.r.t. temperature at + constant pressure"; + + dh_adsorptive_dT := func_dh_adsorptive_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + v_adsorpt :=func_v_adsorpt_pT( + p=p_adsorpt, + T=T_adsorpt) + "Specific volume of the adsorpt"; + dv_adsorpt_dp :=func_dv_adsorpt_dp( + p=p_adsorpt, + T=T_adsorpt, + dp=dp) + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature"; + dv_adsorpt_dT :=func_dv_adsorpt_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure"; + + // + // Calculation of partial derivatives of molar sorption enthalpy + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=v_adsorptive, + v_adsorpt=v_adsorpt, + dv_adsorptive_dp=dv_adsorptive_dp, + dv_adsorpt_dp=dv_adsorpt_dp, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=v_adsorptive, + v_adsorpt=v_adsorpt, + dv_adsorptive_dT=dv_adsorptive_dT, + dv_adsorpt_dT=dv_adsorpt_dT, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + else + // + // Use Clausius Clyperon assumptions + // + dh_adsorptive_dT := func_dh_adsorptive_ig_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + end if; + + // + // Calculation of the integrand + // + y := dh_adsorptive_dT - + (dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp) / M_adsorptive + "Integrand: Partial derivative of the specific enthalpy of the adsorpt w.r.t. + temperature at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy of the +adsorpt with respect to temperature at constant uptake: +</p> +<pre> + (∂h<sub>adsorpt</sub>/∂T)<sub>x</sub> = (∂h<sub>adsorptive</sub>/∂T)<sub>x</sub> - (∂Δh<sub>ads</sub>/∂T)<sub>x</sub>; +</pre> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads</sub></i> is defined as difference +of the specific enthalpy of the gas/vapor phase <i>h<sub>adsorptive</sub></i> and the +adsorpt phase <i>h<sub>adsorpt</sub></i>: +</p> +<pre> + Δh<sub>ads</sub> = h<sub>adsorptive</sub> - h<sub>adsorpt</sub> =T * M<sub>adsorptive</sub> * (v<sub>adsorptive</sub> - v<sub>adsorpt</sub>) (dp/dT) ≈ T * M<sub>adsorptive</sub> * (v<sub>adsorptive</sub> - v<sub>adsorpt</sub>) * (-(∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub>); +</pre> +<p> +Herein, <i>M<sub>adsorptive</sub></i> is the molar mass of the adsorptive, <i>T</i> +is the temperature, <i>v<sub>adsorptive</sub></i> ist the specific volume of the +adsorptive, <i>v<sub>adsorpt</sub></i> ist the specific volume of the adsorpt, +<i>dx/dp</i> is the partial derivative of the uptake with respect to the pressure +at constant temperature, and <i>dx/dT</i> is the partial derivative of the uptake +with respect to the temperature at constant pressure. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Inert sorbent. + </li> + <li> + Neglecting the termn <i>(∂p/∂x)<sub>T</sub> * (dx/dp)</i> of term + <i>dp/dT = -(∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub> + + (∂p/∂x)<sub>T</sub> * + (dx/dp)</i>. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> + <li> + Chakraborty, A. and Saha, B.B. and Ng, K.C. and Koyama (2006). On the thermodynamic modeling of the isosteric heat of adsorption and comparison with experiments, Applied Physics Letters, 89:171901. DOI: http://doi.org/10.1063/1.2360925. + </li> + <li> + Chakraborty, A. and Saha, B.B. and Ng, K.C. and Koyama, S. and Srinivasan, K. (2009). Theoretical Insight of Physical Adsorption for a Single-Component Adsorbent + Adsorbate System: I. Thermodynamic Property Surfaces, Langmuir, 25:2204-221. DOI: http://doi.org/10.1021/la803289p. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_adsorpt_dT_x; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_adsorpt_dT_x_CC.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_adsorpt_dT_x_CC.mo new file mode 100644 index 0000000000000000000000000000000000000000..9f09d0478132a38e154e2e4b1fdba59bb9747654 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_adsorpt_dT_x_CC.mo @@ -0,0 +1,198 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands; +function dh_adsorpt_dT_x_CC + "Partial derivative of the adsorpt w.r.t. temperature at constant uptake according to Clausius Clapeyron" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrand; + + // + // Definition of inputs + // + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_dT + "Partial deriivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_ig_dT + "Partial deriivative of the specific enthalpy of the adsorptive (ideal gas) + w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the specific enthalpy of the adsorptive is + calculated as an ideal gas" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables +protected + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptive_dT + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := func_p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := func_dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := func_dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp := func_ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT := func_ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT := func_ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + dh_adsorptive_dT := func_dh_adsorptive_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + else + dh_adsorptive_dT := func_dh_adsorptive_ig_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + end if; + + // + // Calculation of partial derivatives of molar sorption enthalpy + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + // + // Calculation of the integrand + // + y := dh_adsorptive_dT - + (dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp) / M_adsorptive + "Integrand: Partial derivative of the specific enthalpy of the adsorpt w.r.t. + temperature at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy of the +adsorpt with respect to temperature at constant uptake: +</p> +<pre> + (∂h<sub>adsorpt</sub>/∂T)<sub>x</sub> = (∂h<sub>adsorptive</sub>/∂T)<sub>x</sub> - (∂Δh<sub>ads</sub>/∂T)<sub>x</sub>; +</pre> +<p> +The molar adsorption enthalpy is calculated using Clausius Clapeyron assumptions. +</p> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads</sub></i> is defined as difference +of the specific enthalpy of the gas/vapor phase <i>h<sub>adsorptive</sub></i> and the +adsorpt phase <i>h<sub>adsorpt</sub></i>: +</p> +<pre> + Δh<sub>ads</sub> = h<sub>adsorptive</sub> - h<sub>adsorpt</sub> = R * T<sup>2</sup> / p * (∂p/∂T)<sub>x</sub> = R * T<sup>2</sup> / p * (-(∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub>); +</pre> +<p> +Herein, <i>R</i> is the ideal gas constant, <i>p</i> is the pressure, <i>T</i> is +the temperature, <i>(∂x/∂p)<sub>T</sub></i> is the partial derivative of +the uptake with respect to the pressure at constant temperature, and +<i>(∂x/∂T)<sub>p</sub></i> is the partial derivative of the uptake with +respect to the temperature at constant pressure. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + The specific volume of the adsorpt phase can be neglected compared to the specific + volume of the adsorptive phase. + </li> + <li> + The adsorptive can be treated as an ideal gas (i.e., p * V = n * R * T). + </li> + <li> + Inert sorbent. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Bathen, D. and Breitbach, M. (2001). Adsorptionstechnik (in German), 1st Edition, ISBN 3-540-41908-X, Springer-Verlag Berlin Heidelberg New York. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_adsorpt_dT_x_CC; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_adsorpt_dT_x_Dubinin.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_adsorpt_dT_x_Dubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..1d9659d2f4e7d26aa48d01e9ce034e7227929168 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/dh_adsorpt_dT_x_Dubinin.mo @@ -0,0 +1,446 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands; +function dh_adsorpt_dT_x_Dubinin + "Partial derivative of the adsorpt w.r.t. temperature at constant uptake according to the model of Dubinin" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrand; + + // + // Definition of inputs + // + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_dT + "Partial deriivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_ig_dT + "Partial deriivative of the specific enthalpy of the adsorptive (ideal gas) + w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_h_adsorptiveToLiquid_pT + func_h_adsorptiveToLiquid_pT "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_adsorptiveToLiquid_dp + func_dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_adsorptiveToLiquid_dT + func_dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorpt_pT "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorpt_dp "Partial derivative of the specific volume of the adsorpt + w.r.t. pressure + at constant temperature" annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorpt_dT + "Partial derivative of the specific volume of the adsorpt w.r.t. temperature + at constant pressure" annotation (Dialog(tab="General", group="Inputs")); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_beta_pT + func_beta_adsorpt_pT + "Isobaric expansion coefficient of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dbeta_dp + func_dbeta_adsorpt_dp + "Partial derivative of the isobaric expansion coefficient of the adsorpt w.r.t. + pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dbeta_dT + func_dbeta_adsorpt_dT + "Partial derivative of the isobaric expansion coefficient of the adsorpt w.r.t. + temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dW_dA func_dW_dA + "Partial derivative of the characteristic curve w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dA func_ddW_dA_dA + "Second-order partial derivative of the characteristic curve w.r.t. molar + adsorption potential at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dT func_ddW_dA_dT + "Second-order partial derivative of the characteristic curve w.r.t. molar + adsorption potential and temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables +protected + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptive_dT + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + SorpLib.Units.DerSpecificEnthalpyByPressure dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt"; + SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure"; + + Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Isobaric expansion coefficient of the adsorpt"; + SorpLib.Units.DerIsobaricExpansionCoefficientByPressure dbeta_adsorpt_dp + "Partial derivative of isobaric expansion coefficient of the adsorpt w.r.t. + pressure at constant temperature"; + SorpLib.Units.DerIsobaricExpansionCoefficientByTemperature dbeta_adsorpt_dT + "Partial derivative of isobaric expansion coefficient of the adsorpt w.r.t. + temperature at constant pressure"; + + SorpLib.Units.MolarAdsorptionPotential A + "Molar adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := func_p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := func_dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := func_dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp := func_ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT := func_ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT := func_ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius Clyperon assumptions + // + dh_adsorptive_dT := func_dh_adsorptive_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + h_adsorptiveToLiquid := func_h_adsorptiveToLiquid_pT( + p=p_adsorpt, + T=T_adsorpt) + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + dh_adsorptiveToLiquid_dp:=func_dh_adsorptiveToLiquid_dp( + p=p_adsorpt, + T=T_adsorpt, + dp=dp) + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + dh_adsorptiveToLiquid_dT:=func_dh_adsorptiveToLiquid_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + v_adsorpt :=func_v_adsorpt_pT( + p=p_adsorpt, + T=T_adsorpt) + "Specific volume of the adsorpt"; + dv_adsorpt_dp :=func_dv_adsorpt_dp( + p=p_adsorpt, + T=T_adsorpt, + dp=dp) + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature"; + dv_adsorpt_dT :=func_dv_adsorpt_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure"; + + beta_adsorpt:=func_beta_adsorpt_pT( + p=p_adsorpt, + T=T_adsorpt) + "Isobaric expansion coefficient of the adsorpt"; + dbeta_adsorpt_dp:=func_dbeta_adsorpt_dp( + p=p_adsorpt, + T=T_adsorpt, + dp=dp) + "Partial derivative of isobaric expansion coefficient of the adsorpt w.r.t. + pressure at constant temperature"; + dbeta_adsorpt_dT:=func_dbeta_adsorpt_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of isobaric expansion coefficient of the adsorpt w.r.t. + temperature at constant pressure"; + + A := SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + dA_dp:=SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + dA_dT:=SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT[1]) + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + dW_dA:=func_dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dA:=func_ddW_dA_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dT:=func_ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + + // + // Calculation of partial derivatives of molar sorption enthalpy + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=u, + dx_adsorpt_dp=dx_adsorpt_dp, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dp=dh_adsorptiveToLiquid_dp, + v_adsorpt=v_adsorpt, + dv_adsorpt_dp=dv_adsorpt_dp, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dp=dbeta_adsorpt_dp, + dA_dp=dA_dp, + dW_dA=dW_dA, + ddW_dA_dA=ddW_dA_dA) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=u, + dx_adsorpt_dT=dx_adsorpt_dT, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dT=dh_adsorptiveToLiquid_dT, + v_adsorpt=v_adsorpt, + dv_adsorpt_dT=dv_adsorpt_dT, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dT=dbeta_adsorpt_dT, + dA_dT=dA_dT, + dW_dA=dW_dA, + ddW_dA_dT=ddW_dA_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + + else + // + // Use Clausius Clyperon assumptions + // + dh_adsorptive_dT := func_dh_adsorptive_ig_dT( + p=p_adsorpt, + T=T_adsorpt, + dT=dT) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + end if; + + // + // Calculation of the integrand + // + y := dh_adsorptive_dT - + (dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp) / M_adsorptive + "Integrand: Partial derivative of the specific enthalpy of the adsorpt w.r.t. + temperature at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy of the +adsorpt with respect to temperature at constant uptake: +</p> +<pre> + (∂h<sub>adsorpt</sub>/∂T)<sub>x</sub> = (∂h<sub>adsorptive</sub>/∂T)<sub>x</sub> - (∂Δh<sub>ads</sub>/∂T)<sub>x</sub>; +</pre> +<p> +The molar adsorption enthalpy is calculated according to the model of Dubinin. +</p> + +<h4>Main equations</h4> +<p> +The molar adsorption enthalpy <i>Δh<sub>ads</sub></i> is defined as difference +of the specific enthalpy of the gas/vapor phase <i>h<sub>adsorptive</sub></i> and the +adsorpt phase <i>h<sub>adsorpt</sub></i>: +</p> +<pre> + Δh<sub>ads</sub> = h<sub>adsorptive</sub> - h<sub>adsorpt</sub> = M<sub>adsorptive</sub> * Δh<sub>adsorptiveToLiquid</sub> + A - β * T * v<sub>adsorpt</sub> * x * 1 / (∂W/∂A)<sub>p,T</sub>; +</pre> +<p> +Herein, <i>M<sub>adsorptive</sub></i> is the molar mass of the adsorptive, <i>T</i> +is the temperature, <i>x</i> is the uptake, <i>v<sub>adsorpt</sub></i> is the specific +volume of the adsorpt, <i>β</i> is the isobaric expansion coefficient of the +adsorpt, <i>Δh<sub>adsorptiveToLiquid</sub></i> is the specific enthalpy difference +between adsorptive phase and saturated liquid phase (i.e., bubble point), <i>A</i> is +the molar adsorption potential, and <i>(∂W/∂A)<sub>p,T</sub></i> is the partial +derivative of the filled pore volume with respect to the molar adsorption potential at +constant pressure and temperature. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Inert sorbent. + </li> +</ul> + +<h4>References</h4> +<ul> + <li> + Schwamberger, V. (2016). Thermodynamic and numerical investigation of a novel sorption cycle for application in adsorption heat pumps and chillers (in German), PhD thesis, Karlsruhe. +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_adsorpt_dT_x_Dubinin; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/package.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..8293d2f0252cbc7877c7d187fcaf1b79b9b832e7 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/package.mo @@ -0,0 +1,24 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents; +package Integrands "Package containing functions defining integrands for numerical integration" +extends Modelica.Icons.InternalPackage; + +annotation (Documentation(info="<html> +<p> +This package contains functions defining integrands. These integrands are used +while numerical integration, which is sometimes requied depending on the calculation +approach of the specific heat capacity of the adsorpt phase. Numerical integration is +performed using the very efficient function +<a href=\"Modelica://Modelica.Math.Nonlinear.quadratureLobatto\">Modelica.Math.Nonlinear.quadratureLobatto</a>. +<br><br> +The content of this package is only of interest when adding new functions to the +library or when adding new approach for calculating the molar adsorption enthalpy. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Integrands; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/package.order b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/package.order new file mode 100644 index 0000000000000000000000000000000000000000..064e616fd24060fedf3a743ca0aaaaa799946e1e --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Integrands/package.order @@ -0,0 +1,7 @@ +Interfaces +dh_ads_dT_x +dh_ads_dT_x_CC +dh_ads_dT_x_Dubinin +dh_adsorpt_dT_x +dh_adsorpt_dT_x_CC +dh_adsorpt_dT_x_Dubinin diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/MediumSpecificFunctions/package.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/MediumSpecificFunctions/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..7fe37d4e7ae5387c7205a385127309dc258a1aab --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/MediumSpecificFunctions/package.mo @@ -0,0 +1,333 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Testers; +package MediumSpecificFunctions "Package containing medium specific functions that are used as functional arguments in integrand functions" + extends Modelica.Icons.InternalPackage; + + // + // Definition of replaceable medium package: This is required to have access to + // functions that change with the selected medium. These functions are used as + // functional input arguments. + // + replaceable package Medium = Modelica.Media.Water.WaterIF97_ph + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Medium"), + choicesAllMatching = true); + // + // Redeclaration of all replacable partial functions regarding the adsorptive + // + replaceable function v_adsorptive_pT + "Calculates specific volume of adsorptive as function pressure and temperature" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT; + + algorithm + v :=1/Medium.density_pT(p=p, T=T) + "Specific volume of the adsorptive"; + end v_adsorptive_pT; + + replaceable function dv_adsorptive_dp + "Calculates the partial derivative of the specific volume of the adsotpive w.r.t. pressure at constant temperature" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp; + + algorithm + dv_dp := + (1/Medium.density_pT(p=p+dp, T=T) - 1/Medium.density_pT(p=p-dp, T=T)) / + (2*dp) + "Partial derivative of the specific volume of the adsorptive w.r.t. + pressure at constant temperature"; + end dv_adsorptive_dp; + + replaceable function dv_adsorptive_dT + "Calculates the partial derivative of the specific volume of the adsotpive w.r.t. temperature at constant pressure" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT; + + algorithm + dv_dT := + (1/Medium.density_pT(p=p, T=T+dT) - 1/Medium.density_pT(p=p, T=T-dT)) / + (2*dT) + "Partial derivative of the specific volume of the adsorptive w.r.t. + temperature at constant pressure"; + end dv_adsorptive_dT; + + replaceable function dh_adsorptive_dT + "Calculates specific enthalpy of adsorptive as function pressure and temperature" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT; + + algorithm + dh_dT := (Medium.specificEnthalpy_pT(p=p, T=T+dT) - + Medium.specificEnthalpy_pT(p=p, T=T-dT)) / (2 * dT) + "Partial derivative of the specific enthalpy w.r.t. temperature at constant + pressure"; + end dh_adsorptive_dT; + + replaceable function dh_adsorptive_ig_dT + "Calculates specific volume of the adsorptive (ideal gas) as function temperature" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT; + + algorithm + dh_dT := 1860 + "Partial derivative of the specific enthalpy w.r.t. temperature at constant + pressure"; + end dh_adsorptive_ig_dT; + + replaceable function h_adsorptiveToLiquid_pT + "Base function for functions calculating specific enthalpy differences between adsorptive state and saturated liquid state (i.e., bubble point)" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_h_adsorptiveToLiquid_pT; + + // + // Definition of variables + // +protected + Medium.ThermodynamicState state_pT + "State properties at p and T"; + Medium.SaturationProperties sat_T + "Saturated state properties at T"; + + algorithm + state_pT := Medium.setState_pT(p=p, T=T) + "State properties at p and T"; + sat_T :=Medium.setSat_T(T=T) + "Saturated state properties at T"; + + h_adsorptiveToLiquid :=Medium.specificEnthalpy(state=state_pT) - + Medium.bubbleEnthalpy(sat=sat_T) + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + end h_adsorptiveToLiquid_pT; + + replaceable function dh_adsorptiveToLiquid_dp + "Base function for functions calculating the partial derivative of specific enthalpy differences between adsorptive state and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant temperature" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_adsorptiveToLiquid_dp; + + // + // Definition of variables + // +protected + Medium.ThermodynamicState state_pT + "State properties at p and T"; + + algorithm + // + // The second summand of the partial derivative is zero because the specific + // enthalpy of vaporization does only depend on the temperature, which determines + // the saturation state but is constant + // + state_pT := Medium.setState_pT(p=p, T=T) + "State properties at p and T"; + + dh_adsorptiveToLiquid_dp := 1/Medium.density(state=state_pT) * (1 - T * + Medium.isobaricExpansionCoefficient(state=state_pT)) - 0 + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + end dh_adsorptiveToLiquid_dp; + + replaceable function dh_adsorptiveToLiquid_dT + "Base function for functions calculating the partial derivative of specific enthalpy differences between adsorptive state and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant pressure" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_adsorptiveToLiquid_dT; + + // + // Definition of variables + // +protected + Medium.SaturationProperties sat_T + "Saturated state properties at T"; + Medium.ThermodynamicState state_pT + "State properties at p and T"; + Medium.ThermodynamicState state_bubble_T + "Bubble state properties at p and T"; + + algorithm + sat_T :=Medium.setSat_T(T=T) + "Saturated state properties at T"; + state_pT := Medium.setState_pT(p=p, T=T) + "State properties at p and T"; + state_bubble_T := Medium.setBubbleState(sat=sat_T) + "Bubble state properties at T"; + + dh_adsorptiveToLiquid_dT := + Medium.specificHeatCapacityCp(state=state_pT) - + Medium.specificHeatCapacityCp(state=state_bubble_T) + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + end dh_adsorptiveToLiquid_dT; + // + // Redeclaration of all replacable partial functions regarding the adsorpt + // + replaceable function v_adsorpt_pT + "Calculates specific volume of the adsorpt as function pressure and temperature" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT; + + algorithm + v := 1 / Medium.bubbleDensity(sat=Medium.setSat_T(T=T)) + "Specific volume of the adsorptive"; + end v_adsorpt_pT; + + replaceable function dv_adsorpt_dp + "Calculates the partial derivative of specific volume of the adsorpt w.r.t. pressure at constant temperature" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp; + + // + // Definition of variables + // +protected + Medium.SaturationProperties sat_T + "Saturated state properties at T"; + + algorithm + // + // The partial derivative is zero because the specific volume of the adsorpt + // does only depend on the temperature, which determines the saturation state + // but is constant + // + sat_T :=Medium.setSat_T(T=T) + "Saturated state properties at T"; + dv_dp := dv_adsorpt_dT(p=p, T=T, dT=dp*1) + * Medium.saturationTemperature_derp_sat(sat=sat_T) * 0 + "Partial derivative of the specific volume of the adsorptive w.r.t. + pressure at constant temperature"; + end dv_adsorpt_dp; + + replaceable function dv_adsorpt_dT + "Calculates the partial derivative of specific volume of the adsorpt w.r.t. temperature at constant pressure" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT; + + // + // Definition of variables + // +protected + Medium.SaturationProperties sat_T + "Saturated state properties at T"; + + algorithm + sat_T :=Medium.setSat_T(T=T) + "Saturated state properties at T"; + dv_dT := -(1 / Medium.bubbleDensity(sat=sat_T)) ^ 2 * + Medium.dBubbleDensity_dPressure(sat=sat_T) / + Medium.saturationTemperature_derp_sat(sat=sat_T) + "Partial derivative of the specific volume of the adsorptive w.r.t. + temperature at constant pressure"; + end dv_adsorpt_dT; + + replaceable function beta_adsorpt_pT + "Calculates isobaric expansion coefficient of the adsorpt as function pressure and temperature" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_beta_pT; + + // + // Definition of variables + // +protected + Medium.SaturationProperties sat_T + "Saturated state properties at T"; + Medium.ThermodynamicState state_bubble_T + "State properties of ubble point at T"; + + algorithm + sat_T :=Medium.setSat_T(T=T) + "Saturated state properties at T"; + state_bubble_T :=Medium.setBubbleState(sat=sat_T) + "State properties of ubble point at T"; + + beta :=Medium.isobaricExpansionCoefficient(state=state_bubble_T) + "Isobaric expansion coefficient"; + end beta_adsorpt_pT; + + replaceable function dbeta_adsorpt_dp + "Calculates the partial derivative of the isobaric expansion coefficient of the adsorpt w.r.t. pressure at constant temperature" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dbeta_dp; + + // + // Definition of variables + // +protected + Medium.SaturationProperties sat_T + "Saturated state properties at T"; + + algorithm + // + // The partial derivative is zero because the isobaric expansion coefficient of + // the adsorpt does only depend on the temperature, which determines the saturation + // state but is constant + // + sat_T :=Medium.setSat_T(T=T) + "Saturated state properties at T"; + dbeta_dp := dbeta_adsorpt_dT(p=p, T=T, dT=dp*1) + * Medium.saturationTemperature_derp_sat(sat=sat_T) * 0 + "Partial derivative of isobaric expansion coefficients w.r.t. pressure at + constant temperature"; + end dbeta_adsorpt_dp; + + replaceable function dbeta_adsorpt_dT + "Calculates the partial derivative of the isobaric expansion coefficient of the adsorpt w.r.t. temperature at constant pressure" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dbeta_dT; + + // + // Definition of variables + // +protected + Medium.SaturationProperties sat_T_pdT + "Saturated state properties at T + dT"; + Medium.SaturationProperties sat_T_mdT + "Saturated state properties at T - dT"; + + Medium.ThermodynamicState state_bubble_T_pdT + "State properties of ubble point at T + dT"; + Medium.ThermodynamicState state_bubble_T_mdT + "State properties of ubble point at T - dT"; + + algorithm + sat_T_pdT :=Medium.setSat_T(T=T+dT) + "Saturated state properties at T + dT"; + sat_T_mdT :=Medium.setSat_T(T=T-dT) + "Saturated state properties at T - dT"; + + state_bubble_T_pdT :=Medium.setBubbleState(sat=sat_T_pdT) + "State properties of ubble point at T + dT"; + state_bubble_T_mdT :=Medium.setBubbleState(sat=sat_T_mdT) + "State properties of ubble point at T - dT"; + + dbeta_dT := + (Medium.isobaricExpansionCoefficient(state=state_bubble_T_pdT) - + Medium.isobaricExpansionCoefficient(state=state_bubble_T_mdT)) / (2 * dT) + "Partial derivative of isobaric expansion coefficients w.r.t. temperature at + constant pressure"; + end dbeta_adsorpt_dT; + // + // Annoations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This package defines functions that are used as functional arguments in integrante +functions and use media-specific functions. More details on the integand functions +can be found here: +<a href=\"Modelica://SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.Integrands\">SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.Integrands</a>. +<br><br> +Within this package, the media-specific functions are provided via the media library +of the Modelica standard Library. This package demonstrates one possibility to build +genral models that can use different Modelica libraries for media property calculation +by just exchaning this package. This package is only used for the testers and it should +not be used within other simulation models. +</p> +</html>")); +end MediumSpecificFunctions; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/MediumSpecificFunctions/package.order b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/MediumSpecificFunctions/package.order new file mode 100644 index 0000000000000000000000000000000000000000..866500edf47968245733bc06654a83771120881b --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/MediumSpecificFunctions/package.order @@ -0,0 +1,15 @@ +Medium +v_adsorptive_pT +dv_adsorptive_dp +dv_adsorptive_dT +dh_adsorptive_dT +dh_adsorptive_ig_dT +h_adsorptiveToLiquid_pT +dh_adsorptiveToLiquid_dp +dh_adsorptiveToLiquid_dT +v_adsorpt_pT +dv_adsorpt_dp +dv_adsorpt_dT +beta_adsorpt_pT +dbeta_adsorpt_dp +dbeta_adsorpt_dT diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/Test_cp_ChakrabortyEtAl.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/Test_cp_ChakrabortyEtAl.mo new file mode 100644 index 0000000000000000000000000000000000000000..c9e6018e86e6774019b3db6e1943481497cf61c7 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/Test_cp_ChakrabortyEtAl.mo @@ -0,0 +1,493 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Testers; +model Test_cp_ChakrabortyEtAl + "Tester for the function 'cp_ChakrabortyEtAl' and all corresponding functions" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialTestPure; + + // + // Definition of variables + // + Modelica.Units.SI.MolarEnthalpy h_ads + "Molar adsorption enthalpy"; + Modelica.Units.SI.MolarEnthalpy h_ads_CC + "Molar adsorption enthalpy according to Clausius Clapeyron"; + Modelica.Units.SI.MolarEnthalpy h_ads_Dubinin + "Molar adsorption enthalpy according to Dubinin model"; + + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T_CC + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature according to Clausius Clapeyron"; + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T_Dubinin + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature according to Dubinin model"; + + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p_CC + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure according to Clausius Clapeyron"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p_Dubinin + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure according to Dubinin model"; + + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_x + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_x_CC + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake according to Clausius Clapeyron"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_x_Dubinin + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake according to Dubinin model"; + +protected + Medium.ThermodynamicState state_adsorptive_pT_pdp + "State properties of adsorptive at p_adsorpt and T_adsorpt: p + dp"; + Medium.ThermodynamicState state_adsorptive_pT_mdp + "State properties of adsorptive at p_adsorpt and T_adsorpt: p - dp"; + Medium.ThermodynamicState state_adsorptive_pT_pdT + "State properties of adsorptive at p_adsorpt and T_adsorpt: T + dT"; + Medium.ThermodynamicState state_adsorptive_pT_mdT + "State properties of adsorptive at p_adsorpt and T_adsorpt: T - dT"; + + Medium.ThermodynamicState state_bubble_T_pdT + "State properties of bubble point at T_adsorpt: T + dT"; + Medium.ThermodynamicState state_bubble_T_mdT + "State properties of bubble point at T_adsorpt: T - dT"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant prssure"; + + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at contant + temperature"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at contant + pressure"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + SorpLib.Units.DerSpecificEnthalpyByPressure dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Isobaric expansion coefficient of the adsorpt phase"; + SorpLib.Units.DerIsobaricExpansionCoefficientByTemperature dbeta_adsorpt_dT + "Partial derivative of isobaric expansion coefficient of the adsorpt phase + w.r.t. temperature at constant pressure"; + + SorpLib.Units.MolarAdsorptionPotential A + "Molar adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + +equation + // + // Definition of derivatives + // + der(p_adsorpt) = 0.75 * dc_dT[1] + "Predecsriped slope of p_adsorpt"; + der(T_adsorpt) = 90/20 + "Predecsriped slope of T_adsorpt"; + + // + // Calculate coefficients of the isotherm model + // + c[1] = state_bubble_T.p; + c[2] = state_bubble_T.d; + c[3] = 5.072313e-1 / 1000; + c[4] = 1.305531e2 * 1000 * 0.018; + c[5] = -8.492403e1 * 1000 * 0.018; + c[6] = 4.128962e-3 / 1000; + + c_pdT[1] = sat_T_pdT.psat; + c_pdT[2] = Medium.bubbleDensity(sat=sat_T_pdT); + c_pdT[3] = 5.072313e-1 / 1000; + c_pdT[4] = 1.305531e2 * 1000 * 0.018; + c_pdT[5] = -8.492403e1 * 1000 * 0.018; + c_pdT[6] = 4.128962e-3 / 1000; + + c_mdT[1] = sat_T_mdT.psat; + c_mdT[2] = Medium.bubbleDensity(sat=sat_T_mdT); + c_mdT[3] = 5.072313e-1 / 1000; + c_mdT[4] = 1.305531e2 * 1000 * 0.018; + c_mdT[5] = -8.492403e1 * 1000 * 0.018; + c_mdT[6] = 4.128962e-3 / 1000; + + // + // Calculate partial derivatives of coefficients of the isotherm model w.r.t. + // temperature + // + dc_dT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T); + dc_dT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T) * dc_dT[1]; + dc_dT[3] = 0; + dc_dT[4] = 0; + dc_dT[5] = 0; + dc_dT[6] = 0; + + dc_dT_pdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_pdT); + dc_dT_pdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_pdT) * dc_dT_pdT[1]; + dc_dT_pdT[3] = 0; + dc_dT_pdT[4] = 0; + dc_dT_pdT[5] = 0; + dc_dT_pdT[6] = 0; + + dc_dT_mdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_mdT); + dc_dT_mdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_mdT) * dc_dT_mdT[1]; + dc_dT_mdT[3] = 0; + dc_dT_mdT[4] = 0; + dc_dT_mdT[5] = 0; + dc_dT_mdT[6] = 0; + + // + // Calculate second-order partial derivatives of coefficients of the isotherm + // model w.r.t. temperature + // + ddc_dT_dT[1] = (dc_dT_pdT[1] - dc_dT_mdT[1]) / (2*dT); + ddc_dT_dT[2] = (dc_dT_pdT[2] - dc_dT_mdT[2]) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = 0; + ddc_dT_dT[6] = 0; + + // + // Calculation of state properties + // + state_adsorptive_pT_pdp = Medium.setState_pTX( + p=p_adsorpt+dp, + T=T_adsorpt) + "State properties of adsorptive at p_adsorpt and T_adsorpt: p + dp"; + state_adsorptive_pT_mdp = Medium.setState_pTX( + p=p_adsorpt-dp, + T=T_adsorpt) + "State properties of adsorptive at p_adsorpt and T_adsorpt: p - dp"; + + state_adsorptive_pT_pdT = Medium.setState_pTX( + p=p_adsorpt, + T=T_adsorpt+dT) + "State properties of adsorptive at p_adsorpt and T_adsorpt: T + dT"; + state_adsorptive_pT_mdT = Medium.setState_pTX( + p=p_adsorpt, + T=T_adsorpt-dT) + "State properties of adsorptive at p_adsorpt and T_adsorpt: T - dT"; + + state_bubble_T_pdT = Medium.setBubbleState(sat=sat_T_pdT) + "State properties of bubble point at T_adsorpt: T + dT"; + state_bubble_T_mdT = Medium.setBubbleState(sat=sat_T_mdT) + "State properties of bubble point at T_adsorpt: T - dT"; + + // + // Calculate properties + // + x_adsorpt = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Uptake"; + + dx_adsorpt_dp = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_dT) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + h_adsorptiveToLiquid = state_adsorptive_pT.h - state_bubble_T.h + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + dh_adsorptiveToLiquid_dp = 1/state_adsorptive_pT.d * (1 - T_adsorpt * + Medium.isobaricExpansionCoefficient(state=state_adsorptive_pT)) - 0 + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + dh_adsorptiveToLiquid_dT = + Medium.specificHeatCapacityCp(state=state_adsorptive_pT) - + Medium.specificHeatCapacityCp(state=state_bubble_T) + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + beta_adsorpt = Medium.isobaricExpansionCoefficient(state=state_bubble_T) + "Isobaric expansion coefficient of the adsorpt phase"; + dbeta_adsorpt_dT = + (Medium.isobaricExpansionCoefficient(state=state_bubble_T_pdT) - + Medium.isobaricExpansionCoefficient(state=state_bubble_T_mdT)) /(2*dT) + "Partial derivative of the ssobaric expansion coefficient of the adsorpt phase + w.r.t. temperature at constant pressure"; + + A =SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + dA_dp =SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + dA_dT =SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT[1]) + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + dW_dA = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dA = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddW_dA_dA( + A=A, + c=c) + "Second-order prtial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dT = SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + and temperature at constant pressure"; + + // + // Calculate molar adsorption enthalpies and their derivatives + // + h_ads = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=1/state_adsorptive_pT.d, + v_adsorpt=1/state_bubble_T.d, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar adsorption enthalpy"; + h_ads_CC = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar adsorption enthalpy according to Clausius Clapeyron"; + h_ads_Dubinin = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + v_adsorpt=1/state_bubble_T.d, + beta_adsorpt=beta_adsorpt, + A=A, + dW_dA=dW_dA) + "Molar adsorption enthalpy according to Dubinin model"; + + dh_ads_dp_T = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=1/state_adsorptive_pT.d, + v_adsorpt=1/state_bubble_T.d, + dv_adsorptive_dp=(1/state_adsorptive_pT_pdp.d - 1/state_adsorptive_pT_mdp.d) / + (2*dp), + dv_adsorpt_dp=0, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dp_T_CC = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature according to Clausius Clapeyron"; + dh_ads_dp_T_Dubinin = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dp=dh_adsorptiveToLiquid_dp, + v_adsorpt=1/state_bubble_T.d, + dv_adsorpt_dp=0, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dp=0, + dA_dp=dA_dp, + dW_dA=dW_dA, + ddW_dA_dA=ddW_dA_dA) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature according to Dubinin model"; + + dh_ads_dT_p = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=1/state_adsorptive_pT.d, + v_adsorpt=1/state_bubble_T.d, + dv_adsorptive_dT=(1/state_adsorptive_pT_pdT.d - 1/state_adsorptive_pT_mdT.d) / + (2*dT), + dv_adsorpt_dT=-1/state_bubble_T.d^2 * dc_dT[2], + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + dh_ads_dT_p_CC = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure according to Clausius Clapeyron"; + dh_ads_dT_p_Dubinin = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + dx_adsorpt_dT=dx_adsorpt_dT, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dT=dh_adsorptiveToLiquid_dT, + v_adsorpt=1/state_bubble_T.d, + dv_adsorpt_dT=-1/state_bubble_T.d^2 * dc_dT[2], + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dT=dbeta_adsorpt_dT, + dA_dT=dA_dT, + dW_dA=dW_dA, + ddW_dA_dT=ddW_dA_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure according to Dubinin model"; + + dh_ads_dT_x = dh_ads_dT_p - dh_ads_dp_T * + dx_adsorpt_dT / dx_adsorpt_dp + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake"; + dh_ads_dT_x_CC = dh_ads_dT_p_CC - dh_ads_dp_T_CC * + dx_adsorpt_dT / dx_adsorpt_dp + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake according to Clausius Clapeyron"; + dh_ads_dT_x_Dubinin = dh_ads_dT_p_Dubinin - dh_ads_dp_T_Dubinin * + dx_adsorpt_dT / dx_adsorpt_dp + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake according to Dubinin model"; + + // + // Calculate specific heat capacities of adsorpt phase + // + cp_adsorpt = SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.cp_ChakrabortyEtAl( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + cp_adsorptive=cp_adsorptive, + v_adsorptive=1/state_adsorptive_pT.d, + dv_adsorptive_dT=(1/state_adsorptive_pT_pdT.d - 1/state_adsorptive_pT_mdT.d) / + (2*dT), + v_adsorpt=1/state_bubble_T.d, + h_ads=h_ads, + dh_ads_dT_x=dh_ads_dT_x) + "Specific heat capacitiy of adsorpt"; + cp_adsorpt_CC = SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.cp_ChakrabortyEtAl( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + cp_adsorptive=cp_adsorptive, + v_adsorptive=1/state_adsorptive_pT.d, + dv_adsorptive_dT=(1/state_adsorptive_pT_pdT.d - 1/state_adsorptive_pT_mdT.d) / + (2*dT), + v_adsorpt=1/state_bubble_T.d, + h_ads=h_ads_CC, + dh_ads_dT_x=dh_ads_dT_x_CC) + "Specific heat capacitiy of adsorpt calculated using molar adsorption enthalpy + according to Clausius Clapeyron"; + cp_adsorpt_Dubinin = SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.cp_ChakrabortyEtAl( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + cp_adsorptive=cp_adsorptive, + v_adsorptive=1/state_adsorptive_pT.d, + dv_adsorptive_dT=(1/state_adsorptive_pT_pdT.d - 1/state_adsorptive_pT_mdT.d) / + (2*dT), + v_adsorpt=1/state_bubble_T.d, + h_ads=h_ads_Dubinin, + dh_ads_dT_x=dh_ads_dT_x_Dubinin) + "Specific heat capacitiy of adsorptive using molar adsorption enthalpy + according to Dubinin model"; + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'cp_ChakrabortyEtAl' function. +<br/><br/> +To see the function behavior, plot the variables <i>cp_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_cp_ChakrabortyEtAl; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/Test_cp_SchwambergerSchmidt.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/Test_cp_SchwambergerSchmidt.mo new file mode 100644 index 0000000000000000000000000000000000000000..bdbb51e80671f5ec108d22f3cba58cb152aeab11 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/Test_cp_SchwambergerSchmidt.mo @@ -0,0 +1,291 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Testers; +model Test_cp_SchwambergerSchmidt + "Tester for the function 'cp_SchwambergerSchmidt' and all corresponding functions" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialTestPure; + + // + // Load functions package and select correct medium + // + package MediumSpecificFunctionsForIntegrands = + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Testers.MediumSpecificFunctions + (redeclare final package Medium = Medium) + "Library containing medium-specific functions that are used as functional + arguments" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + + // + // Definition of parameters + // + replaceable function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT + "Classical form of isotherm model: Calculates uptake as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_p_xT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT + "Inverse form of General: Calculates pressure as function of uptake + and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_dx_dp = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature as + function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_dx_dT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure as + function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_ddx_dp_dp = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dp + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature + as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_ddx_dT_dT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dT_dT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure + as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_ddx_dp_dT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature + as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_dW_dA = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_ddW_dA_dA = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddW_dA_dA + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dA + "Second-order prtial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_ddW_dA_dT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddW_dA_dT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dT + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + and temperature at constant pressure" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + +equation + // + // Definition of derivatives + // + der(p_adsorpt) = 0.75 * dc_dT[1] + "Predecsriped slope of p_adsorpt"; + der(T_adsorpt) = 90/20 + "Predecsriped slope of T_adsorpt"; + + // + // Calculate coefficients of the isotherm model + // + c[1] = state_bubble_T.p; + c[2] = state_bubble_T.d; + c[3] = 5.072313e-1 / 1000; + c[4] = 1.305531e2 * 1000 * 0.018; + c[5] = -8.492403e1 * 1000 * 0.018; + c[6] = 4.128962e-3 / 1000; + + c_pdT[1] = sat_T_pdT.psat; + c_pdT[2] = Medium.bubbleDensity(sat=sat_T_pdT); + c_pdT[3] = 5.072313e-1 / 1000; + c_pdT[4] = 1.305531e2 * 1000 * 0.018; + c_pdT[5] = -8.492403e1 * 1000 * 0.018; + c_pdT[6] = 4.128962e-3 / 1000; + + c_mdT[1] = sat_T_mdT.psat; + c_mdT[2] = Medium.bubbleDensity(sat=sat_T_mdT); + c_mdT[3] = 5.072313e-1 / 1000; + c_mdT[4] = 1.305531e2 * 1000 * 0.018; + c_mdT[5] = -8.492403e1 * 1000 * 0.018; + c_mdT[6] = 4.128962e-3 / 1000; + + // + // Calculate partial derivatives of coefficients of the isotherm model w.r.t. + // temperature + // + dc_dT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T); + dc_dT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T) * dc_dT[1]; + dc_dT[3] = 0; + dc_dT[4] = 0; + dc_dT[5] = 0; + dc_dT[6] = 0; + + dc_dT_pdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_pdT); + dc_dT_pdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_pdT) * dc_dT_pdT[1]; + dc_dT_pdT[3] = 0; + dc_dT_pdT[4] = 0; + dc_dT_pdT[5] = 0; + dc_dT_pdT[6] = 0; + + dc_dT_mdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_mdT); + dc_dT_mdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_mdT) * dc_dT_mdT[1]; + dc_dT_mdT[3] = 0; + dc_dT_mdT[4] = 0; + dc_dT_mdT[5] = 0; + dc_dT_mdT[6] = 0; + + // + // Calculate second-order partial derivatives of coefficients of the isotherm + // model w.r.t. temperature + // + ddc_dT_dT[1] = (dc_dT_pdT[1] - dc_dT_mdT[1]) / (2*dT); + ddc_dT_dT[2] = (dc_dT_pdT[2] - dc_dT_mdT[2]) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = 0; + ddc_dT_dT[6] = 0; + + // + // Calculate properties + // + x_adsorpt = func_x_pT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Uptake"; + + // + // Calculate specific heat capacities of adsorpt phase + // + cp_adsorpt = SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.cp_SchwambergerSchmidt( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + func_dh_adsorptive_dT=function MediumSpecificFunctionsForIntegrands.dh_adsorptive_dT(), + func_dh_adsorptive_ig_dT=function MediumSpecificFunctionsForIntegrands.dh_adsorptive_ig_dT(), + func_v_adsorptive_pT=function MediumSpecificFunctionsForIntegrands.v_adsorptive_pT(), + func_dv_adsorptive_dp=function MediumSpecificFunctionsForIntegrands.dv_adsorptive_dp(), + func_dv_adsorptive_dT=function MediumSpecificFunctionsForIntegrands.dv_adsorptive_dT(), + func_v_adsorpt_pT=function MediumSpecificFunctionsForIntegrands.v_adsorpt_pT(), + func_dv_adsorpt_dp=function MediumSpecificFunctionsForIntegrands.dv_adsorpt_dp(), + func_dv_adsorpt_dT=function MediumSpecificFunctionsForIntegrands.dv_adsorpt_dT(), + p_clausiusClyperon=615, + x_adsorpt_lb=0.006, + tolerance=1e-2, + dp=dp, + dT=dT) + "Specific heat capacitiy of adsorpt"; + + cp_adsorpt_CC = SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.cp_SchwambergerSchmidt_clausiusClapeyron( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + func_dh_adsorptive_dT=function MediumSpecificFunctionsForIntegrands.dh_adsorptive_dT(), + func_dh_adsorptive_ig_dT=function MediumSpecificFunctionsForIntegrands.dh_adsorptive_ig_dT(), + p_clausiusClyperon=615, + x_adsorpt_lb=0.006, + tolerance=1e-2, + dT=dT) + "Specific heat capacitiy of adsorpt calculated using molar adsorption enthalpy + according to Clausius Clapeyron"; + + cp_adsorpt_Dubinin = SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.cp_SchwambergerSchmidt_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + func_dh_adsorptive_dT=function MediumSpecificFunctionsForIntegrands.dh_adsorptive_dT(), + func_dh_adsorptive_ig_dT=function MediumSpecificFunctionsForIntegrands.dh_adsorptive_ig_dT(), + func_h_adsorptiveToLiquid_pT=function MediumSpecificFunctions.h_adsorptiveToLiquid_pT(), + func_dh_adsorptiveToLiquid_dp=function MediumSpecificFunctionsForIntegrands.dh_adsorptiveToLiquid_dp(), + func_dh_adsorptiveToLiquid_dT=function MediumSpecificFunctionsForIntegrands.dh_adsorptiveToLiquid_dT(), + func_v_adsorpt_pT=function MediumSpecificFunctionsForIntegrands.v_adsorpt_pT(), + func_dv_adsorpt_dp=function MediumSpecificFunctionsForIntegrands.dv_adsorpt_dp(), + func_dv_adsorpt_dT=function MediumSpecificFunctionsForIntegrands.dv_adsorpt_dT(), + func_beta_adsorpt_pT=function MediumSpecificFunctionsForIntegrands.beta_adsorpt_pT(), + func_dbeta_adsorpt_dp=function MediumSpecificFunctionsForIntegrands.dbeta_adsorpt_dp(), + func_dbeta_adsorpt_dT=function MediumSpecificFunctionsForIntegrands.dbeta_adsorpt_dT(), + func_dW_dA=function func_dW_dA(), + func_ddW_dA_dA=function func_ddW_dA_dA(), + func_ddW_dA_dT=function func_ddW_dA_dT(), + p_clausiusClyperon=615, + x_adsorpt_lb=0.006, + tolerance=1e-2, + dp=dp, + dT=dT) + "Specific heat capacitiy of adsorptive using molar adsorption enthalpy + according to Dubinin model"; + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'cp_WaltonLeVan' function. +<br/><br/> +To see the function behavior, plot the variables <i>cp_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_cp_SchwambergerSchmidt; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/Test_cp_WaltonLeVan.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/Test_cp_WaltonLeVan.mo new file mode 100644 index 0000000000000000000000000000000000000000..0ded5d42e01c4ed870fe139db1c9f77cf57bdf99 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/Test_cp_WaltonLeVan.mo @@ -0,0 +1,287 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Testers; +model Test_cp_WaltonLeVan + "Tester for the function 'cp_WaltonLeVan' and all corresponding functions" + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialTestPure; + + // + // Load functions package and select correct medium + // + package MediumSpecificFunctionsForIntegrands = + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Testers.MediumSpecificFunctions + (redeclare final package Medium = Medium) + "Library containing medium-specific functions that are used as functional + arguments" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + + // + // Definition of parameters + // + replaceable function func_x_pT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.x_pT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_x_pT + "Classical form of isotherm model: Calculates uptake as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_p_xT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.p_xT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_p_xT + "Inverse form of General: Calculates pressure as function of uptake + and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_dx_dp = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dp + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature as + function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_dx_dT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dx_dT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dx_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure as + function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_ddx_dp_dp = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dp + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature + as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_ddx_dT_dT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dT_dT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure + as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_ddx_dp_dT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddx_dp_dT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddx_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature + as function of pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_dW_dA = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.dW_dA + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_ddW_dA_dA = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddW_dA_dA + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dA + "Second-order prtial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + replaceable function func_ddW_dA_dT = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative.ddW_dA_dT + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dT + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + and temperature at constant pressure" + annotation (Dialog(tab="General", group="Functions"), + choicesAllMatching=true); + +equation + // + // Definition of derivatives + // + der(p_adsorpt) = 0.75 * dc_dT[1] + "Predecsriped slope of p_adsorpt"; + der(T_adsorpt) = 90/20 + "Predecsriped slope of T_adsorpt"; + + // + // Calculate coefficients of the isotherm model + // + c[1] = state_bubble_T.p; + c[2] = state_bubble_T.d; + c[3] = 5.072313e-1 / 1000; + c[4] = 1.305531e2 * 1000 * 0.018; + c[5] = -8.492403e1 * 1000 * 0.018; + c[6] = 4.128962e-3 / 1000; + + c_pdT[1] = sat_T_pdT.psat; + c_pdT[2] = Medium.bubbleDensity(sat=sat_T_pdT); + c_pdT[3] = 5.072313e-1 / 1000; + c_pdT[4] = 1.305531e2 * 1000 * 0.018; + c_pdT[5] = -8.492403e1 * 1000 * 0.018; + c_pdT[6] = 4.128962e-3 / 1000; + + c_mdT[1] = sat_T_mdT.psat; + c_mdT[2] = Medium.bubbleDensity(sat=sat_T_mdT); + c_mdT[3] = 5.072313e-1 / 1000; + c_mdT[4] = 1.305531e2 * 1000 * 0.018; + c_mdT[5] = -8.492403e1 * 1000 * 0.018; + c_mdT[6] = 4.128962e-3 / 1000; + + // + // Calculate partial derivatives of coefficients of the isotherm model w.r.t. + // temperature + // + dc_dT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T); + dc_dT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T) * dc_dT[1]; + dc_dT[3] = 0; + dc_dT[4] = 0; + dc_dT[5] = 0; + dc_dT[6] = 0; + + dc_dT_pdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_pdT); + dc_dT_pdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_pdT) * dc_dT_pdT[1]; + dc_dT_pdT[3] = 0; + dc_dT_pdT[4] = 0; + dc_dT_pdT[5] = 0; + dc_dT_pdT[6] = 0; + + dc_dT_mdT[1] = 1/Medium.saturationTemperature_derp_sat(sat=sat_T_mdT); + dc_dT_mdT[2] = Medium.dBubbleDensity_dPressure(sat=sat_T_mdT) * dc_dT_mdT[1]; + dc_dT_mdT[3] = 0; + dc_dT_mdT[4] = 0; + dc_dT_mdT[5] = 0; + dc_dT_mdT[6] = 0; + + // + // Calculate second-order partial derivatives of coefficients of the isotherm + // model w.r.t. temperature + // + ddc_dT_dT[1] = (dc_dT_pdT[1] - dc_dT_mdT[1]) / (2*dT); + ddc_dT_dT[2] = (dc_dT_pdT[2] - dc_dT_mdT[2]) / (2*dT); + ddc_dT_dT[3] = 0; + ddc_dT_dT[4] = 0; + ddc_dT_dT[5] = 0; + ddc_dT_dT[6] = 0; + + // + // Calculate properties + // + x_adsorpt = func_x_pT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Uptake"; + + // + // Calculate specific heat capacities of adsorpt phase + // + cp_adsorpt = SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.cp_WaltonLeVan( + cp_adsorptive=cp_adsorptive, + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + func_v_adsorptive_pT=function MediumSpecificFunctionsForIntegrands.v_adsorptive_pT(), + func_dv_adsorptive_dp=function MediumSpecificFunctionsForIntegrands.dv_adsorptive_dp(), + func_dv_adsorptive_dT=function MediumSpecificFunctionsForIntegrands.dv_adsorptive_dT(), + func_v_adsorpt_pT=function MediumSpecificFunctionsForIntegrands.v_adsorpt_pT(), + func_dv_adsorpt_dp=function MediumSpecificFunctionsForIntegrands.dv_adsorpt_dp(), + func_dv_adsorpt_dT=function MediumSpecificFunctionsForIntegrands.dv_adsorpt_dT(), + p_clausiusClyperon=615, + x_adsorpt_lb=0.006, + tolerance=1e-2, + dp=dp, + dT=dT) + "Specific heat capacitiy of adsorpt"; + + cp_adsorpt_CC = SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.cp_WaltonLeVan_clausiusClapeyron( + cp_adsorptive=cp_adsorptive, + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + x_adsorpt_lb=0.006, + tolerance=1e-2) + "Specific heat capacitiy of adsorpt calculated using molar adsorption enthalpy + according to Clausius Clapeyron"; + + cp_adsorpt_Dubinin = + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.cp_WaltonLeVan_Dubinin( + cp_adsorptive=cp_adsorptive, + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + func_h_adsorptiveToLiquid_pT=function MediumSpecificFunctions.h_adsorptiveToLiquid_pT(), + func_dh_adsorptiveToLiquid_dp=function MediumSpecificFunctionsForIntegrands.dh_adsorptiveToLiquid_dp(), + func_dh_adsorptiveToLiquid_dT=function MediumSpecificFunctionsForIntegrands.dh_adsorptiveToLiquid_dT(), + func_v_adsorpt_pT=function MediumSpecificFunctionsForIntegrands.v_adsorpt_pT(), + func_dv_adsorpt_dp=function MediumSpecificFunctionsForIntegrands.dv_adsorpt_dp(), + func_dv_adsorpt_dT=function MediumSpecificFunctionsForIntegrands.dv_adsorpt_dT(), + func_beta_adsorpt_pT=function MediumSpecificFunctionsForIntegrands.beta_adsorpt_pT(), + func_dbeta_adsorpt_dp=function MediumSpecificFunctionsForIntegrands.dbeta_adsorpt_dp(), + func_dbeta_adsorpt_dT=function MediumSpecificFunctionsForIntegrands.dbeta_adsorpt_dT(), + func_dW_dA=function func_dW_dA(), + func_ddW_dA_dA=function func_ddW_dA_dA(), + func_ddW_dA_dT=function func_ddW_dA_dT(), + p_clausiusClyperon=615, + x_adsorpt_lb=0.006, + tolerance=1e-2, + dp=dp, + dT=dT) + "Specific heat capacitiy of adsorptive using molar adsorption enthalpy + according to Dubinin model"; + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'cp_WaltonLeVan' function. +<br/><br/> +To see the function behavior, plot the variables <i>cp_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_cp_WaltonLeVan; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/package.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..199eb359d4f9d5367e0783e67497df34d268719f --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents; +package Testers "Models to test and varify functions for specific heat capacities of adsorpt phases for pure components" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions and models of the +'PureComponents' package. The test models check the implementation of the functions +and models and enable verification of their behavior. In addition, the test models +demonstrate the functions' and models' general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/package.order b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..dafb2965168e121674ea19053cf5d4b2276efba1 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/Testers/package.order @@ -0,0 +1,4 @@ +MediumSpecificFunctions +Test_cp_ChakrabortyEtAl +Test_cp_WaltonLeVan +Test_cp_SchwambergerSchmidt diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_ChakrabortyEtAl.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_ChakrabortyEtAl.mo new file mode 100644 index 0000000000000000000000000000000000000000..ab54d1881fe017c57d3a98687a603f0cced69edc --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_ChakrabortyEtAl.mo @@ -0,0 +1,106 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents; +function cp_ChakrabortyEtAl + "Specific heat capacity of adsorpt phase according to Chakraborty et al. (2007)" + + // + // Definition of inputs + // + input Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPure_cp; + + input Modelica.Units.SI.SpecificHeatCapacity cp_adsorptive + "Specific heat capacity of adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificVolume v_adsorptive + "Specific volume of the adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorptive_dT + "Partial derivative of specific volume of the adsorptive w.r.t. temperature + at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the v_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.MolarEnthalpy h_ads + "Molar adsorption enthalpy" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_x + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + cp_adsorpt := cp_adsorptive + (v_adsorptive - T_adsorpt * dv_adsorptive_dT) * + h_ads / (M_adsorptive * T_adsorpt * (v_adsorptive - v_adsorpt)) - + dh_ads_dT_x / M_adsorptive + "Specific heat capacitiy of adsorpt"; + + // + // Annotations + // + annotation (Inline=true, +Documentation(info="<html> +<p> +This function calculates the specific heat capacity of the adsorpt phase for a +pure component according to Chakraborty et al. (2009). +</p> + +<h4>Main equations</h4> +<p> +The specific heat capacity is defined as follows: +</p> +<pre> + c<sub>x,adsorpt</sub> = (∂h<sub>adsorpt</sub>/∂T<sub>adsorpt</sub>)<sub>p</sub> + (∂h<sub>adsorpt</sub>/∂p<sub>adsorpt</sub>)<sub>T</sub> * (∂p<sub>adsorpt</sub>/∂T<sub>adsorpt</sub>)<sub>x</sub>; +</pre> +<p> +Herein, <i>(∂h<sub>adsorpt</sub>/∂T<sub>adsorpt</sub>)<sub>p</sub></i> +is the partial derivative of the specific enthalpy of the adsorpt w.r.t. temperature +at constant pressure +<i>(∂h<sub>adsorpt</sub>/∂p<sub>adsorpt</sub>)<sub>T</sub></i> +is the partial derivative of the specific enthalpy of the adsorpt w.r.t. pressure +at constant temperature, and +<i>(∂p<sub>adsorpt</sub>/∂T<sub>adsorpt</sub>)<sub>x</sub></i> +is the partial derivative of the pressure w.r.t. temperature at constant uptake. Now, +Chakraborty et al. assume that the adsorpt properties can be substituted by adsorptive +properties (i.e., gas/vapor phase) and they substitute the Clapeyron equation. Thus, the +specific heat capacity can be expressed as: +</p> +<pre> + c<sub>x,adsorpt</sub> = c<sub>p,adsorptive</sub> + (v<sub>adsorptive</sub> - T<sub>adsorpt</sub> * (∂v<sub>adsorptive</sub>/∂T)<sub>p</sub>) * h<sub>ads</sub> / (M<sub>adsorptive</sub> * T<sub>adsoropt</sub> * (v<sub>adsorptive</sub> - v<sub>adsorpt</sub>)) - (∂h<sub>ads</sub>/∂T)<sub>x</sub> +</pre> +<p> +Herein, <i>T<sub>adsorpt</sub></i> is the equilibrium temperature, <i>c<sub>p,adsorptive</sub></i> +is the specific heat capacity of the adsorptive, <i>v<sub>adsorptive</sub></i> is +the specific volume of the adsorptive,<i><i>v<sub>adsorpt</sub></i></i> is the +specific volume of the adsorpt, <i>(∂v<sub>adsorptive</sub>/∂T)<sub>p</sub></i> +is the partial derivative of the specic volume of the adsorptive w.r.t. temperature +at constant pressure, <i>h<sub>ads</sub></i> is the molar adsorption enthalpy, +<i>(∂h<sub>ads</sub>/∂T)<sub>x</sub></i> is the partial derivative of the +molar enthalpy w.r.t. temperature at constant uptake, and <i>M<sub>adsorptive</sub></i> +is the molar mass of the adsorptive. +</p> + +<h4>References</h4> +<ul> + <li> + Chakraborty, A. and Saha, B.B. and Ng, K.C. and Koyama, S. and Srinivasan, K. (2009). Theoretical Insight of Physical Adsorption for a Single-Component Adsorbent + Adsorbate System: I. Thermodynamic Property Surfaces, Langmuir, 25:2204-221. DOI: http://doi.org/10.1021/la803289p. + </li> + <li> + Schwamberger, V. and Schmidt, F.P. (2013). Estimating the Heat Capacity of the Adsorbate−Adsorbent System from Adsorption Equilibria Regarding Thermodynamic Consistency, Industrial & Engineering Chemostry Research, 52:16958−16965. DOI: https://doi.org/10.1021/ie4011832. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end cp_ChakrabortyEtAl; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_SchwambergerSchmidt.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_SchwambergerSchmidt.mo new file mode 100644 index 0000000000000000000000000000000000000000..d6251e9832c328f3e26ae99ea370e66352a7e39b --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_SchwambergerSchmidt.mo @@ -0,0 +1,162 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents; +function cp_SchwambergerSchmidt + "Specific heat capacity of adsorpt phase according to Schwamberger and Schmidt (2013)" + + // + // Definition of inputs + // + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrad_cp; + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorptive_pT "Specific volume of the adsorptive" annotation (Dialog( + tab="General", group="Inputs - Functions"), choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorptive_dp "Partial derivative of the specific volume of the adsorptive w.r.t. pressure + at constant temperature" annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorptive_dT "Partial derivative of the specific volume of the adsorptive w.r.t. temperature + at constant pressure" annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_dT + "Partial deriivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_ig_dT + "Partial deriivative of the specific enthalpy of the adsorptive (ideal gas) + w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorpt_pT "Specific volume of the adsorpt" annotation (Dialog(tab="General", + group="Inputs - Functions"), choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorpt_dp "Partial derivative of the specific volume of the adsorpt w.r.t. pressure + at constant temperature" annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorpt_dT "Partial derivative of the specific volume of the adsorpt w.r.t. temperature + at constant pressure" annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input Modelica.Units.SI.Pressure p_clausiusClyperon = 615 + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Units.Uptake x_adsorpt_lb = 0 + "Lower limit for integral (i.e., should be zero)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for solution of integral calculated numerically" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + + // + // Definition of variables + // +protected + SorpLib.Units.IntegralSpecificHeatCapacityByUptake int_dh_adsorpt_dT_x + "Partial derivative of specific enthalpy of adsorpt w.r.t. temperature at constant + uptake integrated from x_adsorpt_lb to x_adsorpt"; + +algorithm + // + // Calculate integral + // + int_dh_adsorpt_dT_x :=Modelica.Math.Nonlinear.quadratureLobatto( + f=function + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_adsorpt_dT_x( + T_adsorpt=T_adsorpt, + M_adsorptive=M_adsorptive, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + func_v_adsorptive_pT=function func_v_adsorptive_pT(), + func_dv_adsorptive_dp=function func_dv_adsorptive_dp(), + func_dv_adsorptive_dT=function func_dv_adsorptive_dT(), + func_dh_adsorptive_dT=function func_dh_adsorptive_dT(), + func_dh_adsorptive_ig_dT=function func_dh_adsorptive_ig_dT(), + func_v_adsorpt_pT=function func_v_adsorpt_pT(), + func_dv_adsorpt_dp=function func_dv_adsorpt_dp(), + func_dv_adsorpt_dT=function func_dv_adsorpt_dT(), + p_clausiusClyperon=p_clausiusClyperon, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance) + "Partial derivative of the specific enthalpy of the adsorpt w.r.t. temperature + at constant uptake integrated from x_adsorpt_lb to x_adsorpt"; + + // + // Calculate final result + // + cp_adsorpt := 1 / (x_adsorpt-x_adsorpt_lb) * int_dh_adsorpt_dT_x + "Specific heat capacitiy of adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific heat capacity of the adsorpt phase for a +pure component according to Schwamberger and Schmidt (2013). +</p> + +<h4>Main equations</h4> +<p> +The specific heat capacity is defined as follows: +</p> +<pre> + c<sub>x,adsorpt</sub> = 1 / (x<sub>adsorpt</sub> - x<sub>adsorpt,lb</sub>) * ∫ [(∂h<sub>adsorpt</sub>/∂T)<sub>x</sub>] * dx +</pre> +<p> +Herein, <i>x<sub>adsorpt</sub></i> is the equilibrium uptake, <i>x<sub>adsorpt,lb</sub></i> +is the lower bound of the equilibrium uptake, and <i>(∂h<sub>adsorpt</sub>/∂T)<sub>x</sub></i> +is the partial derivative of the specific enthalpy of the adsorpt w.r.t. temperature +at constant uptake. +</p> + +<h4>References</h4> +<ul> + <li> + Schwamberger, V. and Schmidt, F.P. (2013). Estimating the Heat Capacity of the Adsorbate−Adsorbent System from Adsorption Equilibria Regarding Thermodynamic Consistency, Industrial & Engineering Chemistry Research, 52:16958−16965. DOI: https://doi.org/10.1021/ie4011832. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end cp_SchwambergerSchmidt; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_SchwambergerSchmidt_Dubinin.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_SchwambergerSchmidt_Dubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..0bc39c512748d53c3ca0a5672521a1bcbc852bf9 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_SchwambergerSchmidt_Dubinin.mo @@ -0,0 +1,216 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents; +function cp_SchwambergerSchmidt_Dubinin + "Specific heat capacity of adsorpt phase according to Schwamberger and Schmidt (2013) using the molar adsorption enthalpy accourding to Dubinin" + + // + // Definition of inputs + // + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrad_cp; + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_dT + "Partial deriivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_ig_dT + "Partial deriivative of the specific enthalpy of the adsorptive (ideal gas) + w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_h_adsorptiveToLiquid_pT + func_h_adsorptiveToLiquid_pT "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)" annotation (Dialog(tab="General", group= + "Inputs - Functions"), choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_adsorptiveToLiquid_dp + func_dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", + group="Inputs - Functions"), choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_adsorptiveToLiquid_dT + func_dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", + group="Inputs - Functions"), choicesAllMatching=true); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorpt_pT "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorpt_dp "Partial derivative of the specific volume of the adsorpt w.r.t. pressure + at constant temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorpt_dT "Partial derivative of the specific volume of the adsorpt w.r.t. temperature + at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_beta_pT + func_beta_adsorpt_pT + "Isobaric expansion coefficient of the adsorpt" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dbeta_dp + func_dbeta_adsorpt_dp + "Partial derivative of the isobaric expansion coefficient of the adsorpt w.r.t. + pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dbeta_dT + func_dbeta_adsorpt_dT + "Partial derivative of the isobaric expansion coefficient of the adsorpt w.r.t. + temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dW_dA func_dW_dA + "Partial derivative of the characteristic curve w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dA func_ddW_dA_dA + "Second-order partial derivative of the characteristic curve w.r.t. molar + adsorption potential at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dT func_ddW_dA_dT + "Second-order partial derivative of the characteristic curve w.r.t. molar + adsorption potential and temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input Modelica.Units.SI.Pressure p_clausiusClyperon = 615 + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Units.Uptake x_adsorpt_lb = 0 + "Lower limit for integral (i.e., should be zero)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for solution of integral calculated numerically" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + + // + // Definition of variables + // +protected + SorpLib.Units.IntegralSpecificHeatCapacityByUptake int_dh_adsorpt_dT_x + "Partial derivative of specific enthalpy of adsorpt w.r.t. temperature at constant + uptake integrated from x_adsorpt_lb to x_adsorpt"; + +algorithm + // + // Calculate integral + // + int_dh_adsorpt_dT_x :=Modelica.Math.Nonlinear.quadratureLobatto( + f=function + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_adsorpt_dT_x_Dubinin( + T_adsorpt=T_adsorpt, + M_adsorptive=M_adsorptive, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + func_dh_adsorptive_dT=function func_dh_adsorptive_dT(), + func_dh_adsorptive_ig_dT=function func_dh_adsorptive_ig_dT(), + func_h_adsorptiveToLiquid_pT=function func_h_adsorptiveToLiquid_pT(), + func_dh_adsorptiveToLiquid_dp=function func_dh_adsorptiveToLiquid_dp(), + func_dh_adsorptiveToLiquid_dT=function func_dh_adsorptiveToLiquid_dT(), + func_v_adsorpt_pT=function func_v_adsorpt_pT(), + func_dv_adsorpt_dp=function func_dv_adsorpt_dp(), + func_dv_adsorpt_dT=function func_dv_adsorpt_dT(), + func_beta_adsorpt_pT=function func_beta_adsorpt_pT(), + func_dbeta_adsorpt_dp=function func_dbeta_adsorpt_dp(), + func_dbeta_adsorpt_dT=function func_dbeta_adsorpt_dT(), + func_dW_dA=function func_dW_dA(), + func_ddW_dA_dA=function func_ddW_dA_dA(), + func_ddW_dA_dT=function func_ddW_dA_dT(), + p_clausiusClyperon=p_clausiusClyperon, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance) + "Partial derivative of the specific enthalpy of the adsorpt w.r.t. temperature + at constant uptake integrated from x_adsorpt_lb to x_adsorpt"; + + // + // Calculate final result + // + cp_adsorpt := 1 / (x_adsorpt-x_adsorpt_lb) * int_dh_adsorpt_dT_x + "Specific heat capacitiy of adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific heat capacity of the adsorpt phase for a +pure component according to Schwamberger and Schmidt (2013). The molar sorption enthalpy +is calculated according to the model of Dubinin. +</p> + +<h4>Main equations</h4> +<p> +The specific heat capacity is defined as follows: +</p> +<pre> + c<sub>x,adsorpt</sub> = 1 / (x<sub>adsorpt</sub> - x<sub>adsorpt,lb</sub>) * ∫ [(∂h<sub>adsorpt</sub>/∂T)<sub>x</sub>] * dx +</pre> +<p> +Herein, <i>x<sub>adsorpt</sub></i> is the equilibrium uptake, <i>x<sub>adsorpt,lb</sub></i> +is the lower bound of the equilibrium uptake, and <i>(∂h<sub>adsorpt</sub>/∂T)<sub>x</sub></i> +is the partial derivative of the specific enthalpy of the adsorpt w.r.t. temperature +at constant uptake. +</p> + +<h4>References</h4> +<ul> + <li> + Schwamberger, V. and Schmidt, F.P. (2013). Estimating the Heat Capacity of the Adsorbate−Adsorbent System from Adsorption Equilibria Regarding Thermodynamic Consistency, Industrial & Engineering Chemistry Research, 52:16958−16965. DOI: https://doi.org/10.1021/ie4011832. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end cp_SchwambergerSchmidt_Dubinin; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_SchwambergerSchmidt_clausiusClapeyron.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_SchwambergerSchmidt_clausiusClapeyron.mo new file mode 100644 index 0000000000000000000000000000000000000000..dc7b6ae79b8de0e38bc532ca693aea5baa60644b --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_SchwambergerSchmidt_clausiusClapeyron.mo @@ -0,0 +1,122 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents; +function cp_SchwambergerSchmidt_clausiusClapeyron + "Specific heat capacity of adsorpt phase according to Schwamberger and Schmidt (2013) using the molar adsorption enthalpy accourding to Clausius Clapeyon" + + // + // Definition of inputs + // + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrad_cp; + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_dT + "Partial deriivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_dT + func_dh_adsorptive_ig_dT + "Partial deriivative of the specific enthalpy of the adsorptive (ideal gas) + w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input Modelica.Units.SI.Pressure p_clausiusClyperon = 615 + "Maximum pressure up to which the specific enthalpy of the adsorptive is + calculated as an ideal gas" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Units.Uptake x_adsorpt_lb = 0 + "Lower limit for integral (i.e., should be zero)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for solution of integral calculated numerically" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + + // + // Definition of variables + // +protected + SorpLib.Units.IntegralSpecificHeatCapacityByUptake int_dh_adsorpt_dT_x + "Partial derivative of specific enthalpy of adsorpt w.r.t. temperature at constant + uptake integrated from x_adsorpt_lb to x_adsorpt"; + +algorithm + // + // Calculate integral + // + int_dh_adsorpt_dT_x :=Modelica.Math.Nonlinear.quadratureLobatto( + f=function + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_adsorpt_dT_x_CC( + T_adsorpt=T_adsorpt, + M_adsorptive=M_adsorptive, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + func_dh_adsorptive_dT=function func_dh_adsorptive_dT(), + func_dh_adsorptive_ig_dT=function func_dh_adsorptive_ig_dT(), + p_clausiusClyperon=p_clausiusClyperon, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance) + "Partial derivative of the specific enthalpy of the adsorpt w.r.t. temperature + at constant uptake integrated from x_adsorpt_lb to x_adsorpt"; + + // + // Calculate final result + // + cp_adsorpt := 1 / (x_adsorpt-x_adsorpt_lb) * int_dh_adsorpt_dT_x + "Specific heat capacitiy of adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific heat capacity of the adsorpt phase for a +pure component according to Schwamberger and Schmidt (2013). The molar sorption +enthalpy is calculated according to the Clausius Clapeyron assumptions. +</p> + +<h4>Main equations</h4> +<p> +The specific heat capacity is defined as follows: +</p> +<pre> + c<sub>x,adsorpt</sub> = 1 / (x<sub>adsorpt</sub> - x<sub>adsorpt,lb</sub>) * ∫ [(∂h<sub>adsorpt</sub>/∂T)<sub>x</sub>] * dx +</pre> +<p> +Herein, <i>x<sub>adsorpt</sub></i> is the equilibrium uptake, <i>x<sub>adsorpt,lb</sub></i> +is the lower bound of the equilibrium uptake, and <i>(∂h<sub>adsorpt</sub>/∂T)<sub>x</sub></i> +is the partial derivative of the specific enthalpy of the adsorpt w.r.t. temperature +at constant uptake. +</p> + +<h4>References</h4> +<ul> + <li> + Schwamberger, V. and Schmidt, F.P. (2013). Estimating the Heat Capacity of the Adsorbate−Adsorbent System from Adsorption Equilibria Regarding Thermodynamic Consistency, Industrial & Engineering Chemistry Research, 52:16958−16965. DOI: https://doi.org/10.1021/ie4011832. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end cp_SchwambergerSchmidt_clausiusClapeyron; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_WaltonLeVan.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_WaltonLeVan.mo new file mode 100644 index 0000000000000000000000000000000000000000..634a674555df8cb12f7b7b00c33a59d54ef85979 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_WaltonLeVan.mo @@ -0,0 +1,151 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents; +function cp_WaltonLeVan + "Specific heat capacity of adsorpt phase according to Walton and LeVan (2005)" + + // + // Definition of inputs + // + input Modelica.Units.SI.SpecificHeatCapacity cp_adsorptive + "Specific heat capacity of adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrad_cp; + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorptive_pT "Specific volume of the adsorptive" annotation (Dialog( + tab="General", group="Inputs - Functions"), choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorptive_dp "Partial derivative of the specific volume of the adsorptive w.r.t. pressure + at constant temperature" annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorptive_dT "Partial derivative of the specific volume of the adsorptive w.r.t. temperature + at constant pressure" annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorpt_pT "Specific volume of the adsorpt" annotation (Dialog(tab="General", + group="Inputs - Functions"), choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorpt_dp "Partial derivative of the specific volume of the adsorpt w.r.t. pressure + at constant temperature" annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorpt_dT "Partial derivative of the specific volume of the adsorpt w.r.t. temperature + at constant pressure" annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input Modelica.Units.SI.Pressure p_clausiusClyperon = 615 + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Units.Uptake x_adsorpt_lb = 0 + "Lower limit for integral (i.e., should be zero)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for solution of integral calculated numerically" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + + // + // Definition of variables + // +protected + SorpLib.Units.IntegralMolarHeatCapacityByUptake int_dh_ads_dT_x + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake integrated from x_adsorpt_lb to x_adsorpt"; + +algorithm + // + // Calculate integral + // + int_dh_ads_dT_x :=Modelica.Math.Nonlinear.quadratureLobatto( + f=function + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_ads_dT_x( + T_adsorpt=T_adsorpt, + M_adsorptive=M_adsorptive, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + func_v_adsorptive_pT=function func_v_adsorptive_pT(), + func_dv_adsorptive_dp=function func_dv_adsorptive_dp(), + func_dv_adsorptive_dT=function func_dv_adsorptive_dT(), + func_v_adsorpt_pT=function func_v_adsorpt_pT(), + func_dv_adsorpt_dp=function func_dv_adsorpt_dp(), + func_dv_adsorpt_dT=function func_dv_adsorpt_dT(), + p_clausiusClyperon=p_clausiusClyperon, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake integrated from x_adsorpt_lb to x_adsorpt"; + + // + // Calculate final result + // + cp_adsorpt := cp_adsorptive - 1 / (x_adsorpt-x_adsorpt_lb) * int_dh_ads_dT_x / + M_adsorptive + "Specific heat capacitiy of adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific heat capacity of the adsorpt phase for a +pure component according to Walton and LeVan (2005). +</p> + +<h4>Main equations</h4> +<p> +The specific heat capacity is defined as follows: +</p> +<pre> + c<sub>x,adsorpt</sub> = c<sub>p,adsorptive</sub> - 1 / (M<sub>adsorptive</sub> * (x<sub>adsorpt</sub> - x<sub>adsorpt,lb</sub>)) * ∫ [(∂h<sub>ads</sub>/∂T)<sub>x</sub>] * dx +</pre> +<p> +Herein, <i>x<sub>adsorpt</sub></i> is the equilibrium uptake, <i>x<sub>adsorpt,lb</sub></i> +is the lower bound of the equilibrium uptake, <i>(∂h<sub>ads</sub>/∂T)<sub>x</sub></i> +is the partial derivative of the molar enthalpy w.r.t. temperature at constant uptake, and +<i>M<sub>adsorptive</sub></i> is the molar mass of the adsorptive. +</p> + +<h4>References</h4> +<ul> + <li> + Walton, K.S. and LeVan, M.D. (2005). Adsorbed-Phase Heat Capacities: Thermodynamically Consistent Values Determined from Temperature-Dependent Equilibrium Models, Industrial & Engineering Chemistry Researc, 44(1):178-182. DOI: https://doi.org/10.1021/ie049394j. + </li> + <li> + Schwamberger, V. and Schmidt, F.P. (2013). Estimating the Heat Capacity of the Adsorbate−Adsorbent System from Adsorption Equilibria Regarding Thermodynamic Consistency, Industrial & Engineering Chemistry Research, 52:16958−16965. DOI: https://doi.org/10.1021/ie4011832. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end cp_WaltonLeVan; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_WaltonLeVan_Dubinin.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_WaltonLeVan_Dubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..2d14bc3e9fe780789b2c7234774803a836d3b4fa --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_WaltonLeVan_Dubinin.mo @@ -0,0 +1,206 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents; +function cp_WaltonLeVan_Dubinin + "Specific heat capacity of adsorpt phase according to Walton and LeVan (2005) using the molar adsorption enthalpy accourding to Dubinin" + + // + // Definition of inputs + // + input Modelica.Units.SI.SpecificHeatCapacity cp_adsorptive + "Specific heat capacity of adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrad_cp; + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_h_adsorptiveToLiquid_pT + func_h_adsorptiveToLiquid_pT "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)" annotation (Dialog(tab="General", group= + "Inputs - Functions"), choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_adsorptiveToLiquid_dp + func_dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", + group="Inputs - Functions"), choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dh_adsorptiveToLiquid_dT + func_dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", + group="Inputs - Functions"), choicesAllMatching=true); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_v_pT + func_v_adsorpt_pT "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dp + func_dv_adsorpt_dp "Partial derivative of the specific volume of the adsorpt w.r.t. pressure + at constant temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dv_dT + func_dv_adsorpt_dT "Partial derivative of the specific volume of the adsorpt w.r.t. temperature + at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_beta_pT + func_beta_adsorpt_pT + "Isobaric expansion coefficient of the adsorpt" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dbeta_dp + func_dbeta_adsorpt_dp + "Partial derivative of the isobaric expansion coefficient of the adsorpt w.r.t. + pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.Interfaces.Partial_dbeta_dT + func_dbeta_adsorpt_dT + "Partial derivative of the isobaric expansion coefficient of the adsorpt w.r.t. + temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_dW_dA func_dW_dA + "Partial derivative of the characteristic curve w.r.t. molar adsorption potential + at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dA func_ddW_dA_dA + "Second-order partial derivative of the characteristic curve w.r.t. molar + adsorption potential at constant pressure and temperature" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + input SorpLib.Media.Functions.SorptionEquilibria.BaseClasses.PartialPure_ddW_dA_dT func_ddW_dA_dT + "Second-order partial derivative of the characteristic curve w.r.t. molar + adsorption potential and temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs - Functions"), + choicesAllMatching=true); + + input Modelica.Units.SI.Pressure p_clausiusClyperon = 615 + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs - Functions")); + + input SorpLib.Units.Uptake x_adsorpt_lb = 0 + "Lower limit for integral (i.e., should be zero)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for solution of integral calculated numerically" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + + // + // Definition of variables + // +protected + SorpLib.Units.IntegralMolarHeatCapacityByUptake int_dh_ads_dT_x + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake integrated from x_adsorpt_lb to x_adsorpt"; + +algorithm + // + // Calculate integral + // + int_dh_ads_dT_x :=Modelica.Math.Nonlinear.quadratureLobatto( + f=function + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_ads_dT_x_Dubinin( + T_adsorpt=T_adsorpt, + M_adsorptive=M_adsorptive, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT(), + func_h_adsorptiveToLiquid_pT=function func_h_adsorptiveToLiquid_pT(), + func_dh_adsorptiveToLiquid_dp=function func_dh_adsorptiveToLiquid_dp(), + func_dh_adsorptiveToLiquid_dT=function func_dh_adsorptiveToLiquid_dT(), + func_v_adsorpt_pT=function func_v_adsorpt_pT(), + func_dv_adsorpt_dp=function func_dv_adsorpt_dp(), + func_dv_adsorpt_dT=function func_dv_adsorpt_dT(), + func_beta_adsorpt_pT=function func_beta_adsorpt_pT(), + func_dbeta_adsorpt_dp=function func_dbeta_adsorpt_dp(), + func_dbeta_adsorpt_dT=function func_dbeta_adsorpt_dT(), + func_dW_dA=function func_dW_dA(), + func_ddW_dA_dA=function func_ddW_dA_dA(), + func_ddW_dA_dT=function func_ddW_dA_dT(), + p_clausiusClyperon=p_clausiusClyperon, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake integrated from x_adsorpt_lb to x_adsorpt"; + + // + // Calculate final result + // + cp_adsorpt := cp_adsorptive - 1 / (x_adsorpt-x_adsorpt_lb) * int_dh_ads_dT_x / + M_adsorptive + "Specific heat capacitiy of adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific heat capacity of the adsorpt phase for a +pure component according to Walton and LeVan (2005). The molar sorption enthalpy +is calculated according to the model of Dubinin. +</p> + +<h4>Main equations</h4> +<p> +The specific heat capacity is defined as follows: +</p> +<pre> + c<sub>x,adsorpt</sub> = c<sub>p,adsorptive</sub> - 1 / (M<sub>adsorptive</sub> * (x<sub>adsorpt</sub> - x<sub>adsorpt,lb</sub>)) * ∫ [(∂h<sub>ads</sub>/∂T)<sub>x</sub>] * dx +</pre> +<p> +Herein, <i>x<sub>adsorpt</sub></i> is the equilibrium uptake, <i>x<sub>adsorpt,lb</sub></i> +is the lower bound of the equilibrium uptake, <i>(∂h<sub>ads</sub>/∂T)<sub>x</sub></i> +is the partial derivative of the molar enthalpy w.r.t. temperature at constant uptake, and +<i>M<sub>adsorptive</sub></i> is the molar mass of the adsorptive. +</p> + +<h4>References</h4> +<ul> + <li> + Walton, K.S. and LeVan, M.D. (2005). Adsorbed-Phase Heat Capacities: Thermodynamically Consistent Values Determined from Temperature-Dependent Equilibrium Models, Industrial & Engineering Chemistry Researc, 44(1):178-182. DOI: https://doi.org/10.1021/ie049394j. + </li> + <li> + Schwamberger, V. and Schmidt, F.P. (2013). Estimating the Heat Capacity of the Adsorbate−Adsorbent System from Adsorption Equilibria Regarding Thermodynamic Consistency, Industrial & Engineering Chemistry Research, 52:16958−16965. DOI: https://doi.org/10.1021/ie4011832. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end cp_WaltonLeVan_Dubinin; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_WaltonLeVan_clausiusClapeyron.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_WaltonLeVan_clausiusClapeyron.mo new file mode 100644 index 0000000000000000000000000000000000000000..29e51aedfe9ae6b6fbf979dcb8c56d6745856d51 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/cp_WaltonLeVan_clausiusClapeyron.mo @@ -0,0 +1,101 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents; +function cp_WaltonLeVan_clausiusClapeyron + "Specific heat capacity of adsorpt phase according to Walton and LeVan (2005) using the molar adsorption enthalpy accourding to Clausius Clapeyon" + + // + // Definition of inputs + // + input Modelica.Units.SI.SpecificHeatCapacity cp_adsorptive + "Specific heat capacity of adsorptive" + annotation (Dialog(tab="General", group="Inputs")); + extends + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.BasesClasses.PartialPureIntegrad_cp; + + input SorpLib.Units.Uptake x_adsorpt_lb = 0 + "Lower limit for integral (i.e., should be zero)" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance for solution of integral calculated numerically" + annotation (Dialog(tab="General", group="Inputs - Numerics")); + + // + // Definition of variables + // +protected + SorpLib.Units.IntegralMolarHeatCapacityByUptake int_dh_ads_dT_x + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake integrated from x_adsorpt_lb to x_adsorpt"; + +algorithm + // + // Calculate integral + // + int_dh_ads_dT_x :=Modelica.Math.Nonlinear.quadratureLobatto( + f=function + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_ads_dT_x_CC( + T_adsorpt=T_adsorpt, + M_adsorptive=M_adsorptive, + c=c, + dc_dT=dc_dT, + ddc_dT_dT=ddc_dT_dT, + func_p_xT=function func_p_xT(), + func_dx_dp=function func_dx_dp(), + func_dx_dT=function func_dx_dT(), + func_ddx_dp_dp=function func_ddx_dp_dp(), + func_ddx_dT_dT=function func_ddx_dT_dT(), + func_ddx_dp_dT=function func_ddx_dp_dT()), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + uptake integrated from x_adsorpt_lb to x_adsorpt"; + + // + // Calculate final result + // + cp_adsorpt := cp_adsorptive - 1 / (x_adsorpt-x_adsorpt_lb) * int_dh_ads_dT_x / + M_adsorptive + "Specific heat capacitiy of adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific heat capacity of the adsorpt phase for a +pure component according to Walton and LeVan (2005). The molar sorption enthalpy +is calculated according to the Clausius Clapeyron assumptions. +</p> + +<h4>Main equations</h4> +<p> +The specific heat capacity is defined as follows: +</p> +<pre> + c<sub>x,adsorpt</sub> = c<sub>p,adsorptive</sub> - 1 / (M<sub>adsorptive</sub> * (x<sub>adsorpt</sub> - x<sub>adsorpt,lb</sub>)) * ∫ [(∂h<sub>ads</sub>/∂T)<sub>x</sub>] * dx +</pre> +<p> +Herein, <i>x<sub>adsorpt</sub></i> is the equilibrium uptake, <i>x<sub>adsorpt,lb</sub></i> +is the lower bound of the equilibrium uptake, <i>(∂h<sub>ads</sub>/∂T)<sub>x</sub></i> +is the partial derivative of the molar enthalpy w.r.t. temperature at constant uptake, and +<i>M<sub>adsorptive</sub></i> is the molar mass of the adsorptive. +</p> + +<h4>References</h4> +<ul> + <li> + Walton, K.S. and LeVan, M.D. (2005). Adsorbed-Phase Heat Capacities: Thermodynamically Consistent Values Determined from Temperature-Dependent Equilibrium Models, Industrial & Engineering Chemistry Researc, 44(1):178-182. DOI: https://doi.org/10.1021/ie049394j. + </li> + <li> + Schwamberger, V. and Schmidt, F.P. (2013). Estimating the Heat Capacity of the Adsorbate−Adsorbent System from Adsorption Equilibria Regarding Thermodynamic Consistency, Industrial & Engineering Chemistry Research, 52:16958−16965. DOI: https://doi.org/10.1021/ie4011832. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 20, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end cp_WaltonLeVan_clausiusClapeyron; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/package.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..40a6233e6ab16e2b2cc696198647d23cd491ef3a --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/package.mo @@ -0,0 +1,28 @@ +within SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt; +package PureComponents "Functions required to calculate specific heat capacities of adsorpt phases for pure components" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains models to calculate specific heat capacities of adsorpt +phases for pure component adsorption. +</p> + +<h4>Implemented functions for each specific heat capacity model</h4> +<p> +The following functions are provided for each specific heat capacity model: +</p> +<ul> + <li> + Specific heat capacity. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PureComponents; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/package.order b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..0bf2ab5a9ddb2b0637baa73464e8f307536fe635 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/PureComponents/package.order @@ -0,0 +1,9 @@ +Integrands +cp_ChakrabortyEtAl +cp_WaltonLeVan +cp_WaltonLeVan_clausiusClapeyron +cp_WaltonLeVan_Dubinin +cp_SchwambergerSchmidt +cp_SchwambergerSchmidt_clausiusClapeyron +cp_SchwambergerSchmidt_Dubinin +Testers diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/package.mo b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..16dec94024a33a7269959a45a6aadf916eaf7da0 --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.Functions; +package SpecificHeatCapacitiesAdsorpt "Functions required to calculate specific heat capacities of adsorpt phases" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains models to calculate specific heat capacities of adsorpt +phases for pure component and multi-component adsorption. Please check the +documentation of the individual packages for more details on the implemented +specific heat capacity models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SpecificHeatCapacitiesAdsorpt; diff --git a/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/package.order b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/package.order new file mode 100644 index 0000000000000000000000000000000000000000..29935860fc93201cf571df611f9552fa51c92b0d --- /dev/null +++ b/SorpLib/Media/Functions/SpecificHeatCapacitiesAdsorpt/package.order @@ -0,0 +1,2 @@ +BasesClasses +PureComponents diff --git a/SorpLib/Media/Functions/Testers/TestCharCurve1Arctan.mo b/SorpLib/Media/Functions/Testers/TestCharCurve1Arctan.mo deleted file mode 100644 index d86b3c6ea5acc9738b8cc6cf09236180863892af..0000000000000000000000000000000000000000 --- a/SorpLib/Media/Functions/Testers/TestCharCurve1Arctan.mo +++ /dev/null @@ -1,19 +0,0 @@ -within SorpLib.Media.Functions.Testers; -model TestCharCurve1Arctan - - Modelica.SIunits.SpecificVolume W(start=7.9e-5) - "Specific volume of adsorbate"; - Real dWdA(unit="m3/J") - "Derivative of specific volume of adsorbate with respect to the adsorption potential"; - Modelica.SIunits.SpecificEnergy A(start=3e5) "Adsorption Potential"; - final parameter Real[4] c={5.072313e-4,1.305531e5,-8.492403e4,4.128962e-6} - "Coefficients for characteristic curve"; - -equation - W = SorpLib.Media.Functions.CharCurve1Arctan(A, c); - dWdA = SorpLib.Media.Functions.CharCurve1Arctan_dWdA(A, c); - A = 1e2 + time*1e4; - //W = 7.9e-5+time*1e-5; - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false))); -end TestCharCurve1Arctan; diff --git a/SorpLib/Media/Functions/Testers/TestCharCurve2Polynomial.mo b/SorpLib/Media/Functions/Testers/TestCharCurve2Polynomial.mo deleted file mode 100644 index 917226a539a1e5b36b57bd7e1e73036ba7c770e9..0000000000000000000000000000000000000000 --- a/SorpLib/Media/Functions/Testers/TestCharCurve2Polynomial.mo +++ /dev/null @@ -1,28 +0,0 @@ -within SorpLib.Media.Functions.Testers; -model TestCharCurve2Polynomial - - Modelica.SIunits.SpecificVolume W(start=7.9e-5) - "Specific volume of adsorbate"; - Real dWdA(unit="m3/J") - "Derivative of specific volume of adsorbate with respect to the adsorption potential"; - Modelica.SIunits.SpecificEnergy A(start=3e5) "Adsorption Potential"; - final parameter Real[3] cNom={5,2,1} - "Coefficients for nominator of characteristic curve"; - final parameter Real[2] cDenom={2,1} - "Coefficients for denominator of characteristic curve"; - -equation - W = SorpLib.Media.Functions.CharCurve2Polynomial( - A, - cNom, - cDenom); - dWdA = - SorpLib.Media.Functions.CharCurve2Polynomial_dWdA( - A, - cNom, - cDenom); - A = 1e2 + time*1e4; - //W = 7.9e-5+time*1e-5; - annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( - coordinateSystem(preserveAspectRatio=false))); -end TestCharCurve2Polynomial; diff --git a/SorpLib/Media/Functions/Testers/package.mo b/SorpLib/Media/Functions/Testers/package.mo deleted file mode 100644 index 83942fd48464959200177822e533cc3820ef4cdf..0000000000000000000000000000000000000000 --- a/SorpLib/Media/Functions/Testers/package.mo +++ /dev/null @@ -1,6 +0,0 @@ -within SorpLib.Media.Functions; -package Testers -extends SorpLib.Internals.ClassTypes.ApplicationPackage; - - -end Testers; diff --git a/SorpLib/Media/Functions/Testers/package.order b/SorpLib/Media/Functions/Testers/package.order deleted file mode 100644 index 5fdf775b80f3ad28319547057cb8b44e1049c837..0000000000000000000000000000000000000000 --- a/SorpLib/Media/Functions/Testers/package.order +++ /dev/null @@ -1,2 +0,0 @@ -TestCharCurve1Arctan -TestCharCurve2Polynomial diff --git a/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_ddz_dT_dT.mo b/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_ddz_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..c036f0d84bbcefbc0e2020f8e7947c33ce976532 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_ddz_dT_dT.mo @@ -0,0 +1,44 @@ +within SorpLib.Media.Functions.Utilities.BasesClasses; +partial function Partial_ddz_dT_dT + "Base function for utility functions calculating the second-order partial derivative of properties w.r.t. temperature as a function of temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real ddz_dT_dT + "Second-order partial derivative of fluid property data w.r.t. temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for utility functions that calculate +the second-order partial derivative of an arbitrary property with respect to +temperature as a function of temperature. +<br/><br/> +This partial function defines the temperature <i>T</i> as input and the second- +order partial derivative of the arbitrary property with respect to temperature +<i>dz_dT</i> as output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +further inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_ddz_dT_dT; diff --git a/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_dz_dT.mo b/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_dz_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..b4107da35853fd30457d5dc55cf8bb4dabde2c49 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_dz_dT.mo @@ -0,0 +1,44 @@ +within SorpLib.Media.Functions.Utilities.BasesClasses; +partial function Partial_dz_dT + "Base function for utility functions calculating the partial derivative of properties w.r.t. temperature as a function of temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real dz_dT + "Partial derivative of fluid property data w.r.t. temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for utility functions that calculate +the partial derivative of an arbitrary property with respect to temperature +as a function of temperature. +<br/><br/> +This partial function defines the temperature <i>T</i> as input and the partial +derivative of the arbitrary property with respect to temperature <i>dz_dT</i> as +output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +further inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_dz_dT; diff --git a/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_int_z_dT.mo b/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_int_z_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..c64e8fb0c2d072195c3065808fa28d53fe3c58eb --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_int_z_dT.mo @@ -0,0 +1,45 @@ +within SorpLib.Media.Functions.Utilities.BasesClasses; +partial function Partial_int_z_dT + "Base function for utility functions calculating the indefinite integral of properties w.r.t. temperature as a function of temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real int_z_dT + "Indefinite integral of fluid property data w.r.t. temperature without integration + constant" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for utility functions that calculate +the indefinite integral of an arbitrary property with respect to temperature +as a function of temperature. +<br/><br/> +This partial function defines the temperature <i>T</i> as input and the indefinite +integral of the arbitrary property with respect to temperature <i>int_z_dT</i> as +output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +further inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_int_z_dT; diff --git a/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_z_T.mo b/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_z_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..409828271c81c2797f3dc2356301a904dcf415f4 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/BasesClasses/Partial_z_T.mo @@ -0,0 +1,45 @@ +within SorpLib.Media.Functions.Utilities.BasesClasses; +partial function Partial_z_T + "Base function for utility functions calculating properties as a function of temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real z + "Fluid property data" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for utility functions that calculate +an arbitrary property as a function of temperature. +<br/><br/> +This partial function defines the temperature <i>T</i> as input and the arbitrary +property <i>z</i> as output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +further inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_z_T; diff --git a/SorpLib/Media/Functions/Utilities/BasesClasses/package.mo b/SorpLib/Media/Functions/Utilities/BasesClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..ff7b4ebf7d83c806b69fc98b4de3ed1cc48eba52 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/BasesClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.Functions.Utilities; +package BasesClasses "Base classes used to build new utility functions" + extends Modelica.Icons.BasesPackage; + +annotation (Documentation(revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This package contains partial basic functions and models. These partial functions +and models contain fundamental definitions of utility functions. The content of this +package is only of interest when adding new utility functions to the library. +</p> +</html>")); +end BasesClasses; diff --git a/SorpLib/Media/Functions/Utilities/BasesClasses/package.order b/SorpLib/Media/Functions/Utilities/BasesClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..920946ba107c58397e43b189ef1508aa1614d667 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/BasesClasses/package.order @@ -0,0 +1,4 @@ +Partial_z_T +Partial_dz_dT +Partial_ddz_dT_dT +Partial_int_z_dT diff --git a/SorpLib/Media/Functions/Utilities/Testers/Test_cubicSplineInterpolation_T.mo b/SorpLib/Media/Functions/Utilities/Testers/Test_cubicSplineInterpolation_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..8c7eab3184bfa856f25bcb08d981074cba0a8c0c --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/Testers/Test_cubicSplineInterpolation_T.mo @@ -0,0 +1,177 @@ +within SorpLib.Media.Functions.Utilities.Testers; +model Test_cubicSplineInterpolation_T + "Tester for the function 'cubicSplineInterpolation_T' and all corresponding functions" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real[21] abscissa = { + 0.01, 5, 10, 15, 20, 25, 30, 35, 40, 45, + 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100} .+ 273.15 + "Abscissa values"; + parameter Real[21] ordinate = { + 206.14, 147.12, 106.38, 77.93, 57.79, 43.36, 32.89, 25.22, 19.52, 15.26, + 12.03, 9.586, 7.671, 6.197, 5.042, 4.131, 3.407, 2.828, 2.361, 1.982, 1.6729} + "Abscissa values"; + + final parameter Real[21,4] coefficients= + SorpLib.Media.Functions.Utilities.calcCubicSplineCoefficients( + abscissa=abscissa, + ordinate=ordinate) + "Coefficient a to d for cubic polynomials"; + + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculated partial derivatives numerically"; + + // + // Definition of variables + // + Modelica.Units.SI.Temperature T(start=263.15, fixed=true) + "Temperature"; + + Real z + "Cubic spline interpolation"; + Real z_num + "Linear interpolation calculated numerically"; + + Real dz_dT + "Partial derivative of cubic spline interpolation w.r.t. temperature"; + Real dz_dT_num + "Partial derivative of cubic spline interpolation w.r.t. temperature calculated + numerically"; + + Real ddz_dT_dT + "Second-order partial derivative of linear interpolation w.r.t. temperature"; + Real ddz_dT_dT_num + "Second-order partial derivative of linear interpolation w.r.t. temperature + calculated numerically"; + + Real int_z_dT + "Indefinite integral of linear interpolation w.r.t. temperature"; + +equation + // + // Definition of derivatives + // + der(T) = 120/20 + "Predecsriped slope of T"; + + // + // Calculate properties + // + z=SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T( + T=T, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients) + "Cubic spline interpolation"; + + dz_dT= + SorpLib.Media.Functions.Utilities.dcubicSplineInterpolation_dT( + T=T, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients) + "Partial derivative of cubic spline interpolation w.r.t. temperature"; + dz_dT_num= + (SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T( + T=T+dT, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients) - + SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T( + T=T-dT, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients)) / + (2*dT) + "Partial derivative of cubic spline interpolation w.r.t. temperature calculated + numerically"; + + ddz_dT_dT= + SorpLib.Media.Functions.Utilities.ddcubicSplineInterpolation_dT_dT( + T=T, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients) + "Second-order partial derivative of linear interpolation w.r.t. temperature"; + ddz_dT_dT_num= + (SorpLib.Media.Functions.Utilities.dcubicSplineInterpolation_dT( + T=T+dT, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients) - + SorpLib.Media.Functions.Utilities.dcubicSplineInterpolation_dT( + T=T-dT, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients)) / + (2*dT) + "Second-order partial derivative of linear interpolation w.r.t. temperature + calculated numerically"; + + int_z_dT = SorpLib.Media.Functions.Utilities.intCubicSplineInterpolation_dT( + T=T, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients) + "Indefinite integral of linear interpolation w.r.t. temperature"; + z_num = ( + SorpLib.Media.Functions.Utilities.intCubicSplineInterpolation_dT( + T=T+dT, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients) - + SorpLib.Media.Functions.Utilities.intCubicSplineInterpolation_dT( + T=T-dT, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients)) / (2 * dT) + "Linear interpolation calculated numerically"; + + // + // Definition of assertions: Check numerical implementations + // + assert(abs(dz_dT-dz_dT_num) < 1e-6, + "Partial derivative of z is not valied: Deviation (|" + + String(abs(dz_dT-dz_dT_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + assert(abs(ddz_dT_dT-ddz_dT_dT_num) < 1e-6, + "Second-order partial derivative of z is not valied: Deviation (|" + + String(abs(ddz_dT_dT-ddz_dT_dT_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + assert(abs(z-z_num) < 1e-6, + "Indefinite integral of of z is not valied: Deviation (|" + + String(abs(z-z_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'cubicSplineInterpolation_T' function, its +partial derivative with respect to temperature, and its indefinite integral with +respect to temperature. +<br/><br/> +To see the function behavior, plot the variables <i>z_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_cubicSplineInterpolation_T; diff --git a/SorpLib/Media/Functions/Utilities/Testers/Test_generalizedFunction_T.mo b/SorpLib/Media/Functions/Utilities/Testers/Test_generalizedFunction_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..345d6262e7ab0db53680387eef7d4f839ac714f4 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/Testers/Test_generalizedFunction_T.mo @@ -0,0 +1,617 @@ +within SorpLib.Media.Functions.Utilities.Testers; +model Test_generalizedFunction_T + "Tester for the function 'generalizedFunction_T' and all corresponding functions" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculated partial derivatives numerically"; + + // + // Definition of variables + // + Modelica.Units.SI.Temperature T(start=273.15, fixed=true) + "Temperature"; + + // + // Generalized function + // + Real z_polynomialTemperature + "Polynomial function using temperature for calculation"; + Real z_polynomialReducedTemperature + "Polynomial function using reduced temperature for calculation"; + Real z_exponentialTemperature + "Exponential function using temperature for calculation"; + Real z_exponentialReducedTemperature + "Exponential function using reduced temperature for calculation"; + + Real z_polynomialTemperatureNum + "Polynomial function using temperature for calculation calculated numerically + from integral"; + Real z_polynomialReducedTemperatureNum + "Polynomial function using reduced temperature for calculation calculated + numerically from integral"; + Real z_exponentialTemperatureNum + "Exponential function using temperature for calculation calculated numerically + from integral"; + Real z_exponentialReducedTemperatureNum + "Exponential function using reduced temperature for calculation calculated + numerically from integral"; + + // + // Partial derivative of generalized function w.r.t. temperature + // + Real dz_dT_polynomialTemperature + "Partial derivative of polynomial function using temperature for calculation + w.r.t. temperature"; + Real dz_dT_polynomialReducedTemperature + "Partial derivative of polynomial function using reduced temperature for + calculation w.r.t. temperature"; + Real dz_dT_exponentialTemperature + "Partial derivative of exponential function using temperature for calculation + w.r.t. temperature"; + Real dz_dT_exponentialReducedTemperature + "Partial derivative of exponential function using reduced temperature for + calculation w.r.t. temperature"; + + Real dz_dT_polynomialTemperatureNum + "Partial derivative of polynomial function using temperature for calculation + w.r.t. temperature calculated numerically"; + Real dz_dT_polynomialReducedTemperatureNum + "Partial derivative of polynomial function using reduced temperature for + calculation w.r.t. temperature calculated numerically"; + Real dz_dT_exponentialTemperatureNum + "Partial derivative of exponential function using temperature for calculation + w.r.t. temperature calculated numerically"; + Real dz_dT_exponentialReducedTemperatureNum + "Partial derivative of exponential function using reduced temperature for + calculation w.r.t. temperature calculated numerically"; + + // + // Second-order partial derivative of generalized function w.r.t. temperature + // + Real ddz_dT_dT_polynomialTemperature + "Second-order partial derivative of polynomial function using temperature for + calculation w.r.t. temperature"; + Real ddz_dT_dT_polynomialReducedTemperature + "Second-order partial derivative of polynomial function using reduced + temperature for calculation w.r.t. temperature"; + Real ddz_dT_dT_exponentialTemperature + "Second-order partial derivative of exponential function using temperature + for calculation w.r.t. temperature"; + Real ddz_dT_dT_exponentialReducedTemperature + "Second-order partial derivative of exponential function using reduced + temperature for calculation w.r.t. temperature"; + + Real ddz_dT_dT_polynomialTemperatureNum + "Second-order partial derivative of polynomial function using temperature for + calculation w.r.t. temperature calculated numerically"; + Real ddz_dT_dT_polynomialReducedTemperatureNum + "Second-order partial derivative of polynomial function using reduced + temperature for calculation w.r.t. temperature calculated numerically"; + Real ddz_dT_dT_exponentialTemperatureNum + "Second-order partial derivative of exponential function using temperature + for calculation w.r.t. temperature calculated numerically"; + Real ddz_dT_dT_exponentialReducedTemperatureNum + "Second-order partial derivative of exponential function using reduced + temperature for calculation w.r.t. temperature calculated numerically"; + + // + // Idefinite integral of generalized function w.r.t. temperature + // + Real int_z_dT_polynomialTemperature + "Indefinite integral of polynomial function using temperature for calculation + w.r.t. temperature"; + Real int_z_dT_polynomialReducedTemperature + "Indefinite integral of polynomial function using reduced temperature for + calculation w.r.t. temperature"; + Real int_z_dT_exponentialTemperature + "Indefinite integral of exponential function using temperature for calculation + w.r.t. temperature"; + Real int_z_dT_exponentialReducedTemperature + "Indefinite integral of exponential function using reduced temperature for + calculation w.r.t. temperature"; + +equation + // + // Definition of derivatives + // + der(T) = 100/20 + "Predecsriped slope of T"; + + // + // Generalized function + // + z_polynomialTemperature= + SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.1,0.2,0.3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Polynomial function using temperature for calculation"; + z_polynomialReducedTemperature= + SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T, + T_ref=647.096, + z_ref=322, + coefficients={1,1.99274064,1.09965342,-0.510839303,-1.75493479,-45.5170352, + -6.74694450e5}, + exponents={0,1/3,2/3,5/3,16/3,43/3,110/3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature) + "Polynomial function using reduced temperature for calculation"; + z_exponentialTemperature= + SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.01,0.02,0.03}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature) + "Exponential function using temperature for calculation"; + z_exponentialReducedTemperature= + SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T, + T_ref=647.096, + z_ref=322, + coefficients={-2.03150240,-2.68302940,-5.38626492,-17.2991605,-44.7586581,-63.9201063}, + exponents={2/6,4/6,8/6,18/6,37/6,71/6}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature) + "Exponential function using reduced temperature for calculation"; + + // + // Partial derivative of generalized function w.r.t. temperature + // + dz_dT_polynomialTemperature= + SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.1,0.2,0.3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Partial derivative of polynomial function using temperature for calculation + w.r.t. temperature"; + dz_dT_polynomialReducedTemperature= + SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T, + T_ref=647.096, + z_ref=322, + coefficients={1,1.99274064,1.09965342,-0.510839303,-1.75493479,-45.5170352, + -6.74694450e5}, + exponents={0,1/3,2/3,5/3,16/3,43/3,110/3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature) + "Partial derivative of polynomial function using reduced temperature for + calculation w.r.t. temperature"; + dz_dT_exponentialTemperature= + SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.01,0.02,0.03}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature) + "Partial derivative of exponential function using temperature for calculation + w.r.t. temperature"; + dz_dT_exponentialReducedTemperature= + SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T, + T_ref=647.096, + z_ref=322, + coefficients={-2.03150240,-2.68302940,-5.38626492,-17.2991605,-44.7586581,-63.9201063}, + exponents={2/6,4/6,8/6,18/6,37/6,71/6}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature) + "Partial derivative of exponential function using reduced temperature for + calculation w.r.t. temperature"; + + dz_dT_polynomialTemperatureNum=( + SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T + dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.1,0.2,0.3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + - SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T - dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.1,0.2,0.3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature)) + /(2*dT) + "Partial derivative of polynomial function using temperature for calculation + w.r.t. temperature calculated numerically"; + dz_dT_polynomialReducedTemperatureNum=( + SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T + dT, + T_ref=647.096, + z_ref=322, + coefficients={1,1.99274064,1.09965342,-0.510839303,-1.75493479,-45.5170352, + -6.74694450e5}, + exponents={0,1/3,2/3,5/3,16/3,43/3,110/3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature) + - SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T - dT, + T_ref=647.096, + z_ref=322, + coefficients={1,1.99274064,1.09965342,-0.510839303,-1.75493479,-45.5170352, + -6.74694450e5}, + exponents={0,1/3,2/3,5/3,16/3,43/3,110/3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature)) + /(2*dT) + "Partial derivative of polynomial function using reduced temperature for + calculation w.r.t. temperature calculated numerically"; + dz_dT_exponentialTemperatureNum=( + SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T + dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.01,0.02,0.03}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature) + - SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T - dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.01,0.02,0.03}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature)) + /(2*dT) + "Partial derivative of exponential function using temperature for calculation + w.r.t. temperature calculated numerically"; + dz_dT_exponentialReducedTemperatureNum=( + SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T + dT, + T_ref=647.096, + z_ref=322, + coefficients={-2.03150240,-2.68302940,-5.38626492,-17.2991605,-44.7586581,-63.9201063}, + exponents={2/6,4/6,8/6,18/6,37/6,71/6}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature) + - SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T - dT, + T_ref=647.096, + z_ref=322, + coefficients={-2.03150240,-2.68302940,-5.38626492,-17.2991605,-44.7586581,-63.9201063}, + exponents={2/6,4/6,8/6,18/6,37/6,71/6}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature)) + /(2*dT) + "Partial derivative of exponential function using reduced temperature for + calculation w.r.t. temperature calculated numerically"; + + // + // Second-order partial derivative of generalized function w.r.t. temperature + // + ddz_dT_dT_polynomialTemperature= + SorpLib.Media.Functions.Utilities.ddgeneralizedFunction_dT_dT( + T=T, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.1,0.2,0.3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Second-order partial derivative of polynomial function using temperature for + calculation w.r.t. temperature"; + ddz_dT_dT_polynomialReducedTemperature= + SorpLib.Media.Functions.Utilities.ddgeneralizedFunction_dT_dT( + T=T, + T_ref=647.096, + z_ref=322, + coefficients={1,1.99274064,1.09965342,-0.510839303,-1.75493479,-45.5170352, + -6.74694450e5}, + exponents={0,1/3,2/3,5/3,16/3,43/3,110/3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature) + "Second-order partial derivative of polynomial function using reduced + temperature for calculation w.r.t. temperature"; + ddz_dT_dT_exponentialTemperature= + SorpLib.Media.Functions.Utilities.ddgeneralizedFunction_dT_dT( + T=T, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.01,0.02,0.03}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature) + "Second-order partial derivative of exponential function using temperature + for calculation w.r.t. temperature"; + ddz_dT_dT_exponentialReducedTemperature= + SorpLib.Media.Functions.Utilities.ddgeneralizedFunction_dT_dT( + T=T, + T_ref=647.096, + z_ref=322, + coefficients={-2.03150240,-2.68302940,-5.38626492,-17.2991605,-44.7586581,-63.9201063}, + exponents={2/6,4/6,8/6,18/6,37/6,71/6}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature) + "Second-order partial derivative of exponential function using reduced + temperature for calculation w.r.t. temperature"; + + ddz_dT_dT_polynomialTemperatureNum=( + SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T + dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.1,0.2,0.3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + - SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T - dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.1,0.2,0.3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature)) + /(2*dT) + "Second-order partial derivative of polynomial function using temperature for + calculation w.r.t. temperature calculated numerically"; + ddz_dT_dT_polynomialReducedTemperatureNum=( + SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T + dT, + T_ref=647.096, + z_ref=322, + coefficients={1,1.99274064,1.09965342,-0.510839303,-1.75493479,-45.5170352, + -6.74694450e5}, + exponents={0,1/3,2/3,5/3,16/3,43/3,110/3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature) + - SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T - dT, + T_ref=647.096, + z_ref=322, + coefficients={1,1.99274064,1.09965342,-0.510839303,-1.75493479,-45.5170352, + -6.74694450e5}, + exponents={0,1/3,2/3,5/3,16/3,43/3,110/3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature)) + /(2*dT) + "Second-order partial derivative of polynomial function using reduced + temperature for calculation w.r.t. temperature calculated numerically"; + ddz_dT_dT_exponentialTemperatureNum=( + SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T + dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.01,0.02,0.03}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature) + - SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T - dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.01,0.02,0.03}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature)) + /(2*dT) + "Second-order partial derivative of exponential function using temperature + for calculation w.r.t. temperature calculated numerically"; + ddz_dT_dT_exponentialReducedTemperatureNum=( + SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T + dT, + T_ref=647.096, + z_ref=322, + coefficients={-2.03150240,-2.68302940,-5.38626492,-17.2991605,-44.7586581,-63.9201063}, + exponents={2/6,4/6,8/6,18/6,37/6,71/6}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature) + - SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T - dT, + T_ref=647.096, + z_ref=322, + coefficients={-2.03150240,-2.68302940,-5.38626492,-17.2991605,-44.7586581,-63.9201063}, + exponents={2/6,4/6,8/6,18/6,37/6,71/6}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature)) + /(2*dT) + "Second-order partial derivative of exponential function using reduced + temperature for calculation w.r.t. temperature calculated numerically"; + + // + // Idefinite integral of generalized function w.r.t. temperature + // + int_z_dT_polynomialTemperature = + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.1,0.2,0.3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Indefinite integral of polynomial function using temperature for calculation + w.r.t. temperature"; + int_z_dT_polynomialReducedTemperature = + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T, + T_ref=647.096, + z_ref=322, + coefficients={1,1.99274064,1.09965342,-0.510839303,-1.75493479,-45.5170352, + -6.74694450e5}, + exponents={0,1/3,2/3,5/3,16/3,43/3,110/3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature) + "Indefinite integral of polynomial function using reduced temperature for + calculation w.r.t. temperature"; + int_z_dT_exponentialTemperature = + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.01,0.02,0.03}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature) + "Indefinite integral of exponential function using temperature for calculation + w.r.t. temperature"; + int_z_dT_exponentialReducedTemperature = + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T, + T_ref=647.096, + z_ref=322, + coefficients={-2.03150240,-2.68302940,-5.38626492,-17.2991605,-44.7586581,-63.9201063}, + exponents={2/6,4/6,8/6,18/6,37/6,71/6}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature) + "Indefinite integral of exponential function using reduced temperature for + calculation w.r.t. temperature"; + + z_polynomialTemperatureNum =( + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T + dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.1,0.2,0.3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + - SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T - dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.1,0.2,0.3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature)) + /(2*dT) + "Polynomial function using temperature for calculation calculated numerically + from integral"; + z_polynomialReducedTemperatureNum =( + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T + dT, + T_ref=647.096, + z_ref=322, + coefficients={1,1.99274064,1.09965342,-0.510839303,-1.75493479,-45.5170352, + -6.74694450e5}, + exponents={0,1/3,2/3,5/3,16/3,43/3,110/3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature) + - SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T - dT, + T_ref=647.096, + z_ref=322, + coefficients={1,1.99274064,1.09965342,-0.510839303,-1.75493479,-45.5170352, + -6.74694450e5}, + exponents={0,1/3,2/3,5/3,16/3,43/3,110/3}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature)) + /(2*dT) + "Polynomial function using reduced temperature for calculation calculated + numerically from integral"; + z_exponentialTemperatureNum =( + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T + dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.01,0.02,0.03}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature) + - SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T - dT, + T_ref=647.096, + z_ref=5, + coefficients={0,1,1,3}, + exponents={0,0.01,0.02,0.03}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature)) + /(2*dT) + "Exponential function using temperature for calculation calculated numerically + from integral"; + z_exponentialReducedTemperatureNum =( + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T + dT, + T_ref=647.096, + z_ref=322, + coefficients={-2.03150240,-2.68302940,-5.38626492,-17.2991605,-44.7586581,-63.9201063}, + exponents={2/6,4/6,8/6,18/6,37/6,71/6}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature) + - SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T - dT, + T_ref=647.096, + z_ref=322, + coefficients={-2.03150240,-2.68302940,-5.38626492,-17.2991605,-44.7586581,-63.9201063}, + exponents={2/6,4/6,8/6,18/6,37/6,71/6}, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature)) + /(2*dT) + "Exponential function using reduced temperature for calculation calculated + numerically from integral"; + + // + // Definition of assertions: Check numerical implementations + // + assert(abs(dz_dT_polynomialTemperature-dz_dT_polynomialTemperatureNum) < 1e-6, + "Partial derivative of dz_dT_polynomialTemperature is not valied: Deviation (|" + + String(abs(dz_dT_polynomialTemperature-dz_dT_polynomialTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(dz_dT_polynomialReducedTemperature-dz_dT_polynomialReducedTemperatureNum) < 1e-6, + "Partial derivative of dz_dT_polynomialTemperature is not valied: Deviation (|" + + String(abs(dz_dT_polynomialReducedTemperature-dz_dT_polynomialReducedTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(dz_dT_exponentialTemperature-dz_dT_exponentialTemperatureNum) < 1e-6, + "Partial derivative of dz_dT_polynomialTemperature is not valied: Deviation (|" + + String(abs(dz_dT_exponentialTemperature-dz_dT_exponentialTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(dz_dT_exponentialReducedTemperature-dz_dT_exponentialReducedTemperatureNum) < 1e-6, + "Partial derivative of dz_dT_polynomialTemperature is not valied: Deviation (|" + + String(abs(dz_dT_exponentialReducedTemperature-dz_dT_exponentialReducedTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + assert(abs(ddz_dT_dT_polynomialTemperature-ddz_dT_dT_polynomialTemperatureNum) < 1e-6, + "Second-order partial derivative of ddz_dT_dT_polynomialTemperature is not " + + "valied: Deviation (|" + + String(abs(ddz_dT_dT_polynomialTemperature-ddz_dT_dT_polynomialTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(ddz_dT_dT_polynomialReducedTemperature-ddz_dT_dT_polynomialReducedTemperatureNum) < 1e-6, + "Second-order partial derivative of ddz_dT_dT_polynomialTemperature is not " + + "valied: Deviation (|" + + String(abs(ddz_dT_dT_polynomialReducedTemperature-ddz_dT_dT_polynomialReducedTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(ddz_dT_dT_exponentialTemperature-ddz_dT_dT_exponentialTemperatureNum) < 1e-6, + "Second-order partial derivative of ddz_dT_dT_polynomialTemperature is not " + + "valied: Deviation (|" + + String(abs(ddz_dT_dT_exponentialTemperature-ddz_dT_dT_exponentialTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(ddz_dT_dT_exponentialReducedTemperature-ddz_dT_dT_exponentialReducedTemperatureNum) < 1e-6, + "Second-order partial derivative of ddz_dT_dT_polynomialTemperature is not " + + "valied: Deviation (|" + + String(abs(ddz_dT_dT_exponentialReducedTemperature-ddz_dT_dT_exponentialReducedTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + assert(abs(z_polynomialTemperature-z_polynomialTemperatureNum) < 1e-6, + "Indefinite integral of z_polynomialTemperature is not valied: Deviation (|" + + String(abs(z_polynomialTemperature-z_polynomialTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(z_polynomialReducedTemperature-z_polynomialReducedTemperatureNum) < 1e-6, + "Indefinite integral of z_polynomialTemperature is not valied: Deviation (|" + + String(abs(z_polynomialReducedTemperature-z_polynomialReducedTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(z_exponentialTemperature-z_exponentialTemperatureNum) < 1e-6, + "Indefinite integral of z_polynomialTemperature is not valied: Deviation (|" + + String(abs(z_exponentialTemperature-z_exponentialTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(z_exponentialReducedTemperature-z_exponentialReducedTemperatureNum) < 1e-6, + "Indefinite integral of z_polynomialTemperature is not valied: Deviation (|" + + String(abs(z_exponentialReducedTemperature-z_exponentialReducedTemperatureNum)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'generalizedFunction_T' function, its partial +derivative with respect to temperature, and its indefinite integral with respect to +temperature. +<br/><br/> +To see the function behavior, plot the variables <i>z_polynomialTemperatureI</i> +over the time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_generalizedFunction_T; diff --git a/SorpLib/Media/Functions/Utilities/Testers/Test_linearInterpolation_T.mo b/SorpLib/Media/Functions/Utilities/Testers/Test_linearInterpolation_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..330eda8779594ef80a9f3fc0ae78bced910a5342 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/Testers/Test_linearInterpolation_T.mo @@ -0,0 +1,161 @@ +within SorpLib.Media.Functions.Utilities.Testers; +model Test_linearInterpolation_T + "Tester for the function 'linearInterpolation_T' and all corresponding functions" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real[21] abscissa = { + 0.01, 5, 10, 15, 20, 25, 30, 35, 40, 45, + 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100} .+ 273.15 + "Abscissa values"; + parameter Real[21] ordinate = { + 206.14, 147.12, 106.38, 77.93, 57.79, 43.36, 32.89, 25.22, 19.52, 15.26, + 12.03, 9.586, 7.671, 6.197, 5.042, 4.131, 3.407, 2.828, 2.361, 1.982, 1.6729} + "Abscissa values"; + + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculated partial derivatives numerically"; + + // + // Definition of variables + // + Modelica.Units.SI.Temperature T(start=263.15, fixed=true) + "Temperature"; + + Real z + "Linear interpolation"; + Real z_num + "Linear interpolation calculated numerically"; + + Real dz_dT + "Partial derivative of linear interpolation w.r.t. temperature"; + Real dz_dT_num + "Partial derivative of linear interpolation w.r.t. temperature calculated + numerically"; + + Real ddz_dT_dT + "Second-order partial derivative of linear interpolation w.r.t. temperature"; + Real ddz_dT_dT_num + "Second-order partial derivative of linear interpolation w.r.t. temperature + calculated numerically"; + + Real int_z_dT + "Indefinite integral of linear interpolation w.r.t. temperature"; + +equation + // + // Definition of derivatives + // + der(T) = 120/20 + "Predecsriped slope of T"; + + // + // Calculate properties + // + z=SorpLib.Media.Functions.Utilities.linearInterpolation_T( + T=T, + abscissa=abscissa, + ordinate=ordinate) + "Linear interpolation"; + + dz_dT= + SorpLib.Media.Functions.Utilities.dlinearInterpolation_dT( + T=T, + abscissa=abscissa, + ordinate=ordinate) + "Partial derivative of linear interpolation w.r.t. temperature"; + dz_dT_num= + (SorpLib.Media.Functions.Utilities.linearInterpolation_T( + T=T+dT, + abscissa=abscissa, + ordinate=ordinate) - + SorpLib.Media.Functions.Utilities.linearInterpolation_T( + T=T-dT, + abscissa=abscissa, + ordinate=ordinate)) / + (2*dT) + "Partial derivative of linear interpolation w.r.t. temperature calculated + numerically"; + + ddz_dT_dT= + SorpLib.Media.Functions.Utilities.ddlinearInterpolation_dT_dT( + T=T, + abscissa=abscissa, + ordinate=ordinate) + "Second-order partial derivative of linear interpolation w.r.t. temperature"; + ddz_dT_dT_num= + (SorpLib.Media.Functions.Utilities.dlinearInterpolation_dT( + T=T+dT, + abscissa=abscissa, + ordinate=ordinate) - + SorpLib.Media.Functions.Utilities.dlinearInterpolation_dT( + T=T-dT, + abscissa=abscissa, + ordinate=ordinate)) / + (2*dT) + "Second-order partial derivative of linear interpolation w.r.t. temperature + calculated numerically"; + + int_z_dT = SorpLib.Media.Functions.Utilities.intLinearInterpolation_dT( + T=T, + abscissa=abscissa, + ordinate=ordinate) + "Indefinite integral of linear interpolation w.r.t. temperature"; + z_num = ( + SorpLib.Media.Functions.Utilities.intLinearInterpolation_dT( + T=T+dT, + abscissa=abscissa, + ordinate=ordinate) - + SorpLib.Media.Functions.Utilities.intLinearInterpolation_dT( + T=T-dT, + abscissa=abscissa, + ordinate=ordinate)) / (2 * dT) + "Linear interpolation calculated numerically"; + + // + // Definition of assertions: Check numerical implementations + // + assert(abs(dz_dT-dz_dT_num) < 1e-6, + "Partial derivative of z is not valied: Deviation (|" + + String(abs(dz_dT-dz_dT_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + assert(abs(ddz_dT_dT-ddz_dT_dT_num) < 1e-6, + "Second-order partial derivative of z is not valied: Deviation (|" + + String(abs(ddz_dT_dT-ddz_dT_dT_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + assert(abs(z-z_num) < 1e-6, + "Indefinite integral of of z is not valied: Deviation (|" + + String(abs(z-z_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'linearInterpolation_T' function, its partial +derivative with respect to temperature, and its indefinite integral with respect to +temperature. +<br/><br/> +To see the function behavior, plot the variables <i>z_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_linearInterpolation_T; diff --git a/SorpLib/Media/Functions/Utilities/Testers/package.mo b/SorpLib/Media/Functions/Utilities/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b7b8530ba9171bdc10d80b4df8278f49e16d841d --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/Testers/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.Functions.Utilities; +package Testers "Models to test and/or varify utility functions or models" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions and models of the +'Utilities' package. The test models check the implementation of the functions and +models and enable verification of their behavior. In addition, the test models +demonstrate the functions' and models' general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/Functions/Utilities/Testers/package.order b/SorpLib/Media/Functions/Utilities/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..901be58322beb6be2ca5a33e5b189b8037bb7747 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/Testers/package.order @@ -0,0 +1,3 @@ +Test_generalizedFunction_T +Test_linearInterpolation_T +Test_cubicSplineInterpolation_T diff --git a/SorpLib/Media/Functions/Utilities/calcCubicSplineCoefficients.mo b/SorpLib/Media/Functions/Utilities/calcCubicSplineCoefficients.mo new file mode 100644 index 0000000000000000000000000000000000000000..a526a3de9bcefa52bfb00d3a911b60a3ab18a059 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/calcCubicSplineCoefficients.mo @@ -0,0 +1,176 @@ +within SorpLib.Media.Functions.Utilities; +function calcCubicSplineCoefficients + "Calculates coefficients a, b, c, and d for cubic spline interpolation as a function of abscissa and ordinate values" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real abscissa[:] + "Known abscissa values" + annotation (Dialog(tab="General", group="Inputs")); + input Real ordinate[size(abscissa,1)] + "Known ordinate values" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real coefficients[size(abscissa,1), 4] + "Coefficient a to d for cubic polynomials" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real h[size(abscissa,1)-1] + "Interval lengths"; + + Real alpha[size(abscissa,1)-1] + "Intermediate values for solving system"; + Real l[size(abscissa,1)] + "Lower diagonal of tridiagonal matrix"; + Real mu[size(abscissa,1)-1] + "Upper diagonal of tridiagonal matrix"; + Real zeta[size(abscissa,1)] + "Solution vector for second derivatives"; + + Real a[size(abscissa,1)] + "Coefficient a for cubic polynomials"; + Real b[size(abscissa,1)] + "Coefficient b for cubic polynomials"; + Real c[size(abscissa,1)] + "Coefficient c for cubic polynomials (i.e., second derivatives at data + points)"; + Real d[size(abscissa,1)] + "Coefficient d for cubic polynomials"; + +algorithm + // + // Initialize values + // + for ind in 1:size(abscissa,1) - 1 loop + h[ind]:= abscissa[ind + 1] - abscissa[ind] + "Interval lengths"; + end for; + + alpha := zeros(size(abscissa,1)-1) + "Intermediate values for solving system"; + l := ones(size(abscissa,1)) + "Lower diagonal of tridiagonal matrix"; + mu := zeros(size(abscissa,1)-1) + "Upper diagonal of tridiagonal matrix"; + zeta := zeros(size(abscissa,1)) + "Solution vector for second derivatives"; + + a := ordinate + "Coefficient a for cubic polynomials"; + b := zeros(size(abscissa,1)) + "Coefficient b for cubic polynomials"; + c := zeros(size(abscissa,1)) + "Coefficient c for cubic polynomials (i.e., second derivatives at data + points)"; + d := zeros(size(abscissa,1)) + "Coefficient d for cubic polynomials"; + + // + // System of equations required to solve for the second derivatives + // + for ind in 2:size(abscissa,1)-1 loop + alpha[ind] := (3/h[ind]) * (ordinate[ind+1] - ordinate[ind]) - + (3/h[ind-1]) * (ordinate[ind] - ordinate[ind-1]) + "Intermediate values for solving system"; + end for; + + // + // Solve the tridiagonal system using the Thomas algorithm + // + for ind in 2:size(abscissa,1)-1 loop + l[ind] := 2 * (abscissa[ind+1] - abscissa[ind-1]) - h[ind-1] * mu[ind-1] + "Lower diagonal of tridiagonal matrix"; + mu[ind] := h[ind] / l[ind] + "Upper diagonal of tridiagonal matrix"; + zeta[ind] := (alpha[ind] - h[ind-1] * zeta[ind-1]) / l[ind] + "Solution vector for second derivatives"; + end for; + + // + // Back substitution to find the c-values + // + for ind in 1:size(abscissa,1)-1 loop + c[size(abscissa,1)-ind] := zeta[size(abscissa,1)-ind] - + mu[size(abscissa,1)-ind] * c[size(abscissa,1)-ind+1] + "Coefficient c for cubic pilynomials (i.e., second derivatives at data + points)"; + end for; + + // + // Calculate the b- and d-values + // + for ind in 1:size(abscissa,1)-1 loop + b[ind] := (ordinate[ind+1] - ordinate[ind]) / h[ind] - + h[ind] * (c[ind+1] + 2 * c[ind]) / 3 + "Coefficient b for cubic polynomials"; + d[ind] := (c[ind+1] - c[ind]) / (3 * h[ind]) + "Coefficient d for cubic polynomials"; + end for; + + // + // Return coefficients + // + coefficients[:, 1] :=a + "Coefficient a for cubic polynomials"; + coefficients[:, 2] :=b + "Coefficient b for cubic polynomials"; + coefficients[:, 3] :=c + "Coefficient c for cubic polynomials"; + coefficients[:, 4] :=d + "Coefficient d for cubic polynomials"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates piecewise cubic spline interpolation coefficients as +function abscissa and ordinate values. +</p> + +<h4>Main equations</h4> +<p> +Cubic spline interpolation involves fitting a third-degree polynomial for each +interval [<i>T<sub>i</sub></i>;<i>T<sub>i+1</sub></i>] between two neighboring +abscissa values: +</p> +<pre> + z<sub>i</sub>(T) = a<sub>i</sub></i> + b<sub>i</sub> * (T - T<sub>i</sub>) + c<sub>i</sub> * (T - T<sub>i</sub>)<sup>2</sup> + d<sub>i</sub> * (T - T<sub>i</sub>)<sup>3</sup>; +</pre> +<p> +Herein, a, b, c , and d describe the coefficients of the polynomial. A system of +equations is created to determine the coefficients. For this purpose, the function +values and the first and second derivatives of the polynomials of two neighboring +intervals are equated at the common abscissa values. Natural cubic splines are +assumed as a further boundary condition, i.e., the second derivatives are zero at +the boundary points of the abscissa values. The resulting system of equations can +be solved efficiently using the tridiagonal matrix algorithm. +</p> + +<h4>References</h4> +<ul> + <li> + Wikipedia - Spline Interpolation: https://en.wikipedia.org/wiki/Spline_interpolation. + </li> + <li> + Wikipedia - Tridiagonal Matrix Algorithm: https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calcCubicSplineCoefficients; diff --git a/SorpLib/Media/Functions/Utilities/cubicSplineInterpolation_T.mo b/SorpLib/Media/Functions/Utilities/cubicSplineInterpolation_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..10ba9ee5f4ff5b31515d2a9b364331a9b802986d --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/cubicSplineInterpolation_T.mo @@ -0,0 +1,102 @@ +within SorpLib.Media.Functions.Utilities; +function cubicSplineInterpolation_T + "Interpolates an arbitrary fluid property z via cubic splines" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_z_T; + + // + // Definition of inputs + // + input Real abscissa[:] + "Known abscissa values" + annotation (Dialog(tab="General", group="Inputs")); + input Real ordinate[size(abscissa,1)] + "Known ordinate values" + annotation (Dialog(tab="General", group="Inputs")); + + input Real coefficients[size(abscissa,1),4] + "Coefficient a to d for cubic polynomials" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Integer ind_gv + "Index of abscissa that is greater than actual temperature"; + +algorithm + if T <= abscissa[1] then + z := ordinate[1] + "Fluid property data"; + + elseif T >= abscissa[end] then + z := ordinate[end] + "Fluid property data"; + + else + ind_gv :=1 + "Index of abscissa that is greater than actual temperature"; + + while T > abscissa[ind_gv+1] loop + ind_gv :=ind_gv + 1 + "Index of abscissa that is greater than actual temperature"; + end while; + + z := coefficients[ind_gv,1] + + coefficients[ind_gv,2] * (T - abscissa[ind_gv]) + + coefficients[ind_gv,3] * (T - abscissa[ind_gv])^2 + + coefficients[ind_gv,4] * (T - abscissa[ind_gv])^3 + "Fluid property data"; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates an arbitrary fluid property z via piecewise cubic spline +interpolation as a function of temperature as well as known abscissa and ordinate +value. Examples of the arbitrary fluid property <i>z</i> are the specific +heat capacity <i>c</i> or the specific volume <i>v</i>. +<br><br> +The coefficients of the cubic splines must be calculated via the function +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.calcCubicSplineCoefficients\">SorpLib.Media.Functions.Utilities.calcCubicSplineCoefficients</a>. +</p> + +<h4>Main equations</h4> +<p> +Cubic spline interpolation involves fitting a third-degree polynomial for each +interval [<i>T<sub>i</sub></i>;<i>T<sub>i+1</sub></i>] between two neighboring +abscissa values: +</p> +<pre> + z<sub>i</sub>(T) = a<sub>i</sub></i> + b<sub>i</sub> * (T - T<sub>i</sub>) + c<sub>i</sub> * (T - T<sub>i</sub>)<sup>2</sup> + d<sub>i</sub> * (T - T<sub>i</sub>)<sup>3</sup>; +</pre> +<p> +Herein, a, b, c , and d describe the coefficients of the polynomial. A system of +equations is created to determine the coefficients. For this purpose, the function +values and the first and second derivatives of the polynomials of two neighboring +intervals are equated at the common abscissa values. Natural cubic splines are +assumed as a further boundary condition, i.e., the second derivatives are zero at +the boundary points of the abscissa values. The resulting system of equations can +be solved efficiently using the tridiagonal matrix algorithm. +</p> + +<h4>References</h4> +<ul> + <li> + Wikipedia - Spline Interpolation: https://en.wikipedia.org/wiki/Spline_interpolation. + </li> + <li> + Wikipedia - Tridiagonal Matrix Algorithm: https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end cubicSplineInterpolation_T; diff --git a/SorpLib/Media/Functions/Utilities/dcubicSplineInterpolation_dT.mo b/SorpLib/Media/Functions/Utilities/dcubicSplineInterpolation_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..cb23dfaebf8f3d26b737a3b2e60c72a74f03ff4a --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/dcubicSplineInterpolation_dT.mo @@ -0,0 +1,69 @@ +within SorpLib.Media.Functions.Utilities; +function dcubicSplineInterpolation_dT + "Partial derivative of arbitrary fluid property z interpolated via cubic splines w.r.t. temperature" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_dz_dT; + + // + // Definition of inputs + // + input Real abscissa[:] + "Known abscissa values" + annotation (Dialog(tab="General", group="Inputs")); + input Real ordinate[size(abscissa,1)] + "Known ordinate values" + annotation (Dialog(tab="General", group="Inputs")); + + input Real coefficients[size(abscissa,1),4] + "Coefficient a to d for cubic polynomials" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Integer ind_gv + "Index of abscissa that is greater than actual temperature"; + +algorithm + if T <= abscissa[1] then + dz_dT := 0 + "Partial derivative of fluid property data w.r.t. temperature"; + + elseif T >= abscissa[end] then + dz_dT := 0 + "Partial derivative of fluid property data w.r.t. temperature"; + + else + ind_gv :=1 + "Index of abscissa that is greater than actual temperature"; + + while T > abscissa[ind_gv+1] loop + ind_gv :=ind_gv + 1 + "Index of abscissa that is greater than actual temperature"; + end while; + + dz_dT := coefficients[ind_gv,2] + + 2 * coefficients[ind_gv,3] * (T - abscissa[ind_gv]) + + 3 * coefficients[ind_gv,4] * (T - abscissa[ind_gv])^2 + "Partial derivative of fluid property data w.r.t. temperature"; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'cubicSplineInterpolation_T' +with respect to the temperature. For full details of the original function +'cubicSplineInterpolation_T,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T\">SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dcubicSplineInterpolation_dT; diff --git a/SorpLib/Media/Functions/Utilities/ddcubicSplineInterpolation_dT_dT.mo b/SorpLib/Media/Functions/Utilities/ddcubicSplineInterpolation_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..e38739ba4f453b4d0ba68e47963c4a6a85a1ada6 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/ddcubicSplineInterpolation_dT_dT.mo @@ -0,0 +1,69 @@ +within SorpLib.Media.Functions.Utilities; +function ddcubicSplineInterpolation_dT_dT + "Second-order partial derivative of arbitrary fluid property z interpolated via cubic splines w.r.t. temperature" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_ddz_dT_dT; + + // + // Definition of inputs + // + input Real abscissa[:] + "Known abscissa values" + annotation (Dialog(tab="General", group="Inputs")); + input Real ordinate[size(abscissa,1)] + "Known ordinate values" + annotation (Dialog(tab="General", group="Inputs")); + + input Real coefficients[size(abscissa,1),4] + "Coefficient a to d for cubic polynomials" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Integer ind_gv + "Index of abscissa that is greater than actual temperature"; + +algorithm + if T <= abscissa[1] then + ddz_dT_dT := 0 + "Second-order partial derivative of fluid property data w.r.t. temperature"; + + elseif T >= abscissa[end] then + ddz_dT_dT := 0 + "Second-order partial derivative of fluid property data w.r.t. temperature"; + + else + ind_gv :=1 + "Index of abscissa that is greater than actual temperature"; + + while T > abscissa[ind_gv+1] loop + ind_gv :=ind_gv + 1 + "Index of abscissa that is greater than actual temperature"; + end while; + + ddz_dT_dT := 2 * coefficients[ind_gv,3] + + 6 * coefficients[ind_gv,4] * (T - abscissa[ind_gv]) + "Second-order partial derivative of fluid property data w.r.t. temperature"; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the second-order partial derivative of the function +'cubicSplineInterpolation_T' with respect to the temperature. For full details of +the original function 'cubicSplineInterpolation_T,' check the documentation of the +function +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T\">SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddcubicSplineInterpolation_dT_dT; diff --git a/SorpLib/Media/Functions/Utilities/ddgeneralizedFunction_dT_dT.mo b/SorpLib/Media/Functions/Utilities/ddgeneralizedFunction_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..15de84e801835c648a9d0802fb578f4d6d8b0b2b --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/ddgeneralizedFunction_dT_dT.mo @@ -0,0 +1,140 @@ +within SorpLib.Media.Functions.Utilities; +function ddgeneralizedFunction_dT_dT + "Calculates second-order partial derivative of an arbitrary media property z via a generalized function w.r.t. temperature" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_ddz_dT_dT; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_ref + "Reference temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real z_ref + "Reference fluid property data" + annotation (Dialog(tab="General", group="Inputs")); + + input Real coefficients[:] + "Coefficients of generalized function" + annotation (Dialog(tab="General", group="Inputs")); + input Real exponents[size(coefficients,1)] + "Exponents of generalized function" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Choices.GeneralizedFunctionApproach approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Function approach" annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Real z + "Fluid property data"; + Real dz_dT + "Partial derivative of fluid property data w.r.t. temperature"; + +algorithm + // + // Check approach + // + z := 0 + "Fluid property data"; + dz_dT := 0 + "Partial derivative of fluid property data w.r.t. temperature"; + ddz_dT_dT := 0 + "Second-order partial derivative of fluid property data w.r.t. temperature"; + + if approach == SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature then + for ind in 1:size(coefficients,1) loop + if not (Modelica.Math.isEqual(s1=exponents[ind], s2=0, eps=100*Modelica.Constants.eps) or + Modelica.Math.isEqual(s1=exponents[ind]-1, s2=0, eps=100*Modelica.Constants.eps)) then + ddz_dT_dT := ddz_dT_dT + (exponents[ind] * (exponents[ind] - 1) * + coefficients[ind] * T ^ (exponents[ind] - 2)) + "Second-order partial derivative of fluid property data w.r.t. + temperature"; + end if; + end for; + + ddz_dT_dT := z_ref * ddz_dT_dT + "Second-order partial derivative of fluid property data w.r.t. temperature"; + + elseif approach == SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature then + for ind in 1:size(coefficients,1) loop + if not (Modelica.Math.isEqual(s1=exponents[ind], s2=0, eps=100*Modelica.Constants.eps) or + Modelica.Math.isEqual(s1=exponents[ind]-1, s2=0, eps=100*Modelica.Constants.eps)) then + ddz_dT_dT := ddz_dT_dT + (exponents[ind] * (exponents[ind] - 1) * + coefficients[ind] * (1 - T / T_ref) ^ (exponents[ind] - 2)) + "Second-order partial derivative of fluid property data w.r.t. + temperature"; + end if; + end for; + + ddz_dT_dT := z_ref * (-1 / T_ref) ^ 2 * ddz_dT_dT + "Second-order partial derivative of fluid property data w.r.t. temperature"; + + elseif approach == SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature then + for ind in 1:size(coefficients,1) loop + z := z + coefficients[ind] * T ^ exponents[ind] + "Fluid property data"; + + if not Modelica.Math.isEqual(s1=exponents[ind], s2=0, eps=100*Modelica.Constants.eps) then + dz_dT := dz_dT + (exponents[ind] * coefficients[ind] * + T ^ (exponents[ind] - 1)) + "Partial derivative of fluid property data w.r.t. temperature"; + end if; + + if not (Modelica.Math.isEqual(s1=exponents[ind], s2=0, eps=100*Modelica.Constants.eps) or + Modelica.Math.isEqual(s1=exponents[ind]-1, s2=0, eps=100*Modelica.Constants.eps)) then + ddz_dT_dT := ddz_dT_dT + (exponents[ind] * (exponents[ind] - 1) * + coefficients[ind] * T ^ (exponents[ind] - 2)) + "Second-order partial derivative of fluid property data w.r.t. + temperature"; + end if; + end for; + + ddz_dT_dT := z_ref * exp(z) * (dz_dT^2 + ddz_dT_dT) + "Second-order partial derivative of fluid property data w.r.t. temperature"; + + else + for ind in 1:size(coefficients,1) loop + z := z + coefficients[ind] * (1 - T/T_ref) ^ exponents[ind] + "Fluid property data"; + + if not Modelica.Math.isEqual(s1=exponents[ind], s2=0, eps=100*Modelica.Constants.eps) then + dz_dT := dz_dT + (exponents[ind] * coefficients[ind] * (1 - T / T_ref) ^ + (exponents[ind] - 1)) + "Partial derivative of fluid property data w.r.t. temperature"; + end if; + + if not (Modelica.Math.isEqual(s1=exponents[ind], s2=0, eps=100*Modelica.Constants.eps) or + Modelica.Math.isEqual(s1=exponents[ind]-1, s2=0, eps=100*Modelica.Constants.eps)) then + ddz_dT_dT := ddz_dT_dT + (exponents[ind] * (exponents[ind] - 1) * + coefficients[ind] * (1 - T / T_ref) ^ (exponents[ind] - 2)) + "Second-order partial derivative of fluid property data w.r.t. + temperature"; + end if; + end for; + + ddz_dT_dT := z_ref * exp(z) * (-1 / T_ref) ^2 * (dz_dT^2 + ddz_dT_dT) + "Second-order partial derivative of fluid property data w.r.t. temperature"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the second-order partial derivative of the function +'generalizedFunction_T' with respect to the temperature. For full details of the +original function 'generalizedFunction_T,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.generalizedFunction_T\">SorpLib.Media.Functions.Utilities.generalizedFunction_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddgeneralizedFunction_dT_dT; diff --git a/SorpLib/Media/Functions/Utilities/ddlinearInterpolation_dT_dT.mo b/SorpLib/Media/Functions/Utilities/ddlinearInterpolation_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..688b01daba8e4ea11eefbceaa8e474dee6ac418a --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/ddlinearInterpolation_dT_dT.mo @@ -0,0 +1,38 @@ +within SorpLib.Media.Functions.Utilities; +function ddlinearInterpolation_dT_dT + "Second-order partial derivative of linearly interpolated arbitrary fluid property z w.r.t. temperature" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_ddz_dT_dT; + + // + // Definition of inputs + // + input Real abscissa[:] + "Known abscissa values" + annotation (Dialog(tab="General", group="Inputs")); + input Real ordinate[size(abscissa,1)] + "Known ordinate values" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + ddz_dT_dT :=0 + "Second-order partial derivative of fluid property data w.r.t. temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the second-order partial derivative of the function +'linearInterpolation_T' with respect to the temperature. For full details of the +original function 'linearInterpolation_T,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.linearInterpolation_T\">SorpLib.Media.Functions.Utilities.linearInterpolation_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddlinearInterpolation_dT_dT; diff --git a/SorpLib/Media/Functions/Utilities/dgeneralizedFunction_dT.mo b/SorpLib/Media/Functions/Utilities/dgeneralizedFunction_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..3f395f14c9a24f08af0f29a80d92484becd1ef7f --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/dgeneralizedFunction_dT.mo @@ -0,0 +1,116 @@ +within SorpLib.Media.Functions.Utilities; +function dgeneralizedFunction_dT + "Calculates partial derivative of an arbitrary media property z via a generalized function w.r.t. temperature" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_dz_dT; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_ref + "Reference temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real z_ref + "Reference fluid property data" + annotation (Dialog(tab="General", group="Inputs")); + + input Real coefficients[:] + "Coefficients of generalized function" + annotation (Dialog(tab="General", group="Inputs")); + input Real exponents[size(coefficients,1)] + "Exponents of generalized function" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Choices.GeneralizedFunctionApproach approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Function approach" annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Real z + "Fluid property data"; + +algorithm + // + // Check approach + // + z := 0 + "Fluid property data"; + dz_dT :=0 + "Partial derivative of fluid property data w.r.t. temperature"; + + if approach == SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature then + for ind in 1:size(coefficients,1) loop + if not Modelica.Math.isEqual(s1=exponents[ind], s2=0, eps=100*Modelica.Constants.eps) then + dz_dT := dz_dT + (exponents[ind] * coefficients[ind] * + T ^ (exponents[ind] - 1)) + "Partial derivative of fluid property data w.r.t. temperature"; + end if; + end for; + + dz_dT := z_ref * dz_dT + "Partial derivative of fluid property data w.r.t. temperature"; + + elseif approach == SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature then + for ind in 1:size(coefficients,1) loop + if not Modelica.Math.isEqual(s1=exponents[ind], s2=0, eps=100*Modelica.Constants.eps) then + dz_dT := dz_dT + (exponents[ind] * coefficients[ind] * (1 - T / T_ref) ^ + (exponents[ind] - 1)) + "Partial derivative of fluid property data w.r.t. temperature"; + end if; + end for; + + dz_dT := z_ref * (-1 / T_ref) * dz_dT + "Partial derivative of fluid property data w.r.t. temperature"; + + elseif approach == SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature then + for ind in 1:size(coefficients,1) loop + z := z + coefficients[ind] * T ^ exponents[ind] + "Fluid property data"; + + if not Modelica.Math.isEqual(s1=exponents[ind], s2=0, eps=100*Modelica.Constants.eps) then + dz_dT := dz_dT + (exponents[ind] * coefficients[ind] * + T ^ (exponents[ind] - 1)) + "Partial derivative of fluid property data w.r.t. temperature"; + end if; + end for; + + dz_dT := z_ref * exp(z) * dz_dT + "Partial derivative of fluid property data w.r.t. temperature"; + + else + for ind in 1:size(coefficients,1) loop + z := z + coefficients[ind] * (1 - T/T_ref) ^ exponents[ind] + "Fluid property data"; + + if not Modelica.Math.isEqual(s1=exponents[ind], s2=0, eps=100*Modelica.Constants.eps) then + dz_dT := dz_dT + (exponents[ind] * coefficients[ind] * (1 - T / T_ref) ^ + (exponents[ind] - 1)) + "Partial derivative of fluid property data w.r.t. temperature"; + end if; + end for; + + dz_dT := z_ref * exp(z) * (-1 / T_ref) * dz_dT + "Partial derivative of fluid property data w.r.t. temperature"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'generalizedFunction_T' +with respect to the temperature. For full details of the original function +'generalizedFunction_T,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.generalizedFunction_T\">SorpLib.Media.Functions.Utilities.generalizedFunction_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dgeneralizedFunction_dT; diff --git a/SorpLib/Media/Functions/Utilities/dlinearInterpolation_dT.mo b/SorpLib/Media/Functions/Utilities/dlinearInterpolation_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..0a4fa7d2678bb31e69a39fab4be5192863da863b --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/dlinearInterpolation_dT.mo @@ -0,0 +1,68 @@ +within SorpLib.Media.Functions.Utilities; +function dlinearInterpolation_dT + "Partial derivative of linearly interpolated arbitrary fluid property z w.r.t. temperature" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_dz_dT; + + // + // Definition of inputs + // + input Real abscissa[:] + "Known abscissa values" + annotation (Dialog(tab="General", group="Inputs")); + input Real ordinate[size(abscissa,1)] + "Known ordinate values" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Integer ind_gv + "Index of abscissa that is greater than actual temperature"; + +algorithm + if T <= abscissa[1] then + dz_dT := 0 + "Partial derivative of fluid property data w.r.t. temperature"; + + elseif T >= abscissa[end] then + dz_dT := 0 + "Partial derivative of fluid property data w.r.t. temperature"; + + else + // + // Finde abscissa that is greater than actual temperature + // + ind_gv :=1 + "Index of abscissa that is greater than actual temperature"; + + while T > abscissa[ind_gv] loop + ind_gv :=ind_gv + 1 + "Index of abscissa that is greater than actual temperature"; + end while; + + dz_dT := (ordinate[ind_gv] - ordinate[ind_gv-1]) / + (abscissa[ind_gv] - abscissa[ind_gv-1]) + "Partial derivative of fluid property data w.r.t. temperature"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the partial derivative of the function 'linearInterpolation_T' +with respect to the temperature. For full details of the original function +'linearInterpolation_T,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.linearInterpolation_T\">SorpLib.Media.Functions.Utilities.linearInterpolation_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dlinearInterpolation_dT; diff --git a/SorpLib/Media/Functions/Utilities/generalizedFunction_T.mo b/SorpLib/Media/Functions/Utilities/generalizedFunction_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..53d1eeb6ab2698620d8671f148ad50509f60c45b --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/generalizedFunction_T.mo @@ -0,0 +1,142 @@ +within SorpLib.Media.Functions.Utilities; +function generalizedFunction_T + "Calculates an arbitrary fluid property z via a generalized function" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_z_T; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_ref + "Reference temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real z_ref + "Reference fluid property data" + annotation (Dialog(tab="General", group="Inputs")); + + input Real coefficients[:] + "Coefficients of generalized function" + annotation (Dialog(tab="General", group="Inputs")); + input Real exponents[size(coefficients,1)] + "Exponents of generalized function" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Choices.GeneralizedFunctionApproach approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Function approach" annotation (Dialog(tab="General", group="Inputs")); + +algorithm + // + // Check approach + // + z := 0 + "Fluid property data"; + + if approach == SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature then + if not Modelica.Math.isEqual(s1=T, s2=0, eps=100*Modelica.Constants.eps) then + for ind in 1:size(coefficients,1) loop + z := z + coefficients[ind] * T ^ exponents[ind] + "Fluid property data"; + end for; + end if; + + z := z_ref * z + "Fluid property data"; + + elseif approach == SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature then + if not Modelica.Math.isEqual(s1=T, s2=T_ref, eps=100*Modelica.Constants.eps) then + for ind in 1:size(coefficients,1) loop + z := z + coefficients[ind] * (1 - T/T_ref) ^ exponents[ind] + "Fluid property data"; + end for; + end if; + + z := z_ref * z + "Fluid property data"; + + + elseif approach == SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionTemperature then + if not Modelica.Math.isEqual(s1=T, s2=0, eps=100*Modelica.Constants.eps) then + for ind in 1:size(coefficients,1) loop + z := z + coefficients[ind] * T ^ exponents[ind] + "Fluid property data"; + end for; + end if; + + z := z_ref * exp(z) + "Fluid property data"; + + else + if not Modelica.Math.isEqual(s1=T, s2=T_ref, eps=100*Modelica.Constants.eps) then + for ind in 1:size(coefficients,1) loop + z := z + coefficients[ind] * (1 - T/T_ref) ^ exponents[ind] + "Fluid property data"; + end for; + end if; + + z := z_ref * exp(z) + "Fluid property data"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates an arbitrary fluid property <i>z</i> via a generalized function +as a function of temperature. Examples of the arbitrary fluid property <i>z</i> are +the specific heat capacity <i>c</i> or the specific volume <i>v</i>. +</p> + +<h4>Main equations</h4> +<p> +The generalized function comprises four function types often used for fluid +property data calculation. The function type depends on the input <i>approach</i>: +</p> +<ol> + <li> + For <i>approach = PolynomialFunction_Temperature</i>: + <br> + <pre>z = z<sub>ref</sub> * ∑<sub>i</sub> a<sub>i</sub> * T ^ (b<sub>i</sub>);</pre> + <br> + </li> + <li> + For <i>approach = PolynomialFunction_ReducedTemperature</i>: + <br> + <pre>z = z<sub>ref</sub> * ∑<sub>i</sub> a<sub>i</sub> * (1 - T / T<sub>ref</sub>) ^ (b<sub>i</sub>);</pre> + <br> + </li> + <li> + For <i>approach = ExponentialFunction_Temperature</i>: + <br> + <pre>z = z<sub>ref</sub> * <strong>exp</strong>(∑<sub>i</sub> a<sub>i</sub> * T ^ (b<sub>i</sub>));</pre> + <br> + </li> + <li> + For <i>approach = ExponentialFunction_ReducedTemperature</i>: + <br> + <pre>z = z<sub>ref</sub> * <strong>exp</strong>(∑<sub>i</sub> a<sub>i</sub> * (1 - T / T<sub>ref</sub>) ^ (b<sub>i</sub>));</pre> + <br> + </li> +</ol> +<p> +Herein, <i>z<sub>ref</sub></i> is either a pre-factor for approaches that use the +temperature or the fluid property at reference temperature <i>T<sub>ref</sub></i> +for approaches that use the reduced temperature. The vectors <i>a</i> and <i>b</i> +contain the coefficients and exponents for each summand of the sum. +</p> + +<h4>References</h4> +<ul> + <li> + Wagner, W. and Pruß, A (2002). The IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, Journal of Physical and Chemical Reference Data, 31:387. DOI: https://doi.org/10.1063/1.1461829. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end generalizedFunction_T; diff --git a/SorpLib/Media/Functions/Utilities/intCubicSplineInterpolation_dT.mo b/SorpLib/Media/Functions/Utilities/intCubicSplineInterpolation_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..1c3693fddce7ed05c095299ede62200662138474 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/intCubicSplineInterpolation_dT.mo @@ -0,0 +1,74 @@ +within SorpLib.Media.Functions.Utilities; +function intCubicSplineInterpolation_dT + "Indefinite integral of arbitrary fluid property z interpolated via cubic splines w.r.t. temperature" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_int_z_dT; + + // + // Definition of inputs + // + input Real abscissa[:] + "Known abscissa values" + annotation (Dialog(tab="General", group="Inputs")); + input Real ordinate[size(abscissa,1)] + "Known ordinate values" + annotation (Dialog(tab="General", group="Inputs")); + + input Real coefficients[size(abscissa,1),4] + "Coefficient a to d for cubic polynomials" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Integer ind_gv + "Index of abscissa that is greater than actual temperature"; + +algorithm + if T <= abscissa[1] then + int_z_dT := ordinate[1] * T + "Indefinite integral of fluid property data w.r.t. temperature without + integration constant"; + + elseif T >= abscissa[end] then + int_z_dT := ordinate[end] * T + "Indefinite integral of fluid property data w.r.t. temperature without + integration constant"; + + else + ind_gv :=1 + "Index of abscissa that is greater than actual temperature"; + + while T > abscissa[ind_gv+1] loop + ind_gv :=ind_gv + 1 + "Index of abscissa that is greater than actual temperature"; + end while; + + int_z_dT := coefficients[ind_gv,1] * T + + coefficients[ind_gv,2] / 2 * (T - abscissa[ind_gv])^2 + + coefficients[ind_gv,3] / 3 * (T - abscissa[ind_gv])^3 + + coefficients[ind_gv,4] / 4 * (T - abscissa[ind_gv])^3 + "Indefinite integral of fluid property data w.r.t. temperature without + integration constant"; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the indefinite integral of the function 'cubicSplineInterpolation_T' +with respect to the temperature. Note that the integration constant is neglected. +For full details of the original function 'cubicSplineInterpolation_T,' check the +documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T\">SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end intCubicSplineInterpolation_dT; diff --git a/SorpLib/Media/Functions/Utilities/intGeneralizedFunction_dT.mo b/SorpLib/Media/Functions/Utilities/intGeneralizedFunction_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..5305fe8940cada5da1e040e866706b1b98a086ac --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/intGeneralizedFunction_dT.mo @@ -0,0 +1,111 @@ +within SorpLib.Media.Functions.Utilities; +function intGeneralizedFunction_dT + "Calculates indefinite integral of an arbitrary media property z via a generalized function w.r.t. temperature" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_int_z_dT; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_ref + "Reference temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real z_ref + "Reference fluid property data" + annotation (Dialog(tab="General", group="Inputs")); + + input Real coefficients[:] + "Coefficients of generalized function" + annotation (Dialog(tab="General", group="Inputs")); + input Real exponents[size(coefficients,1)] + "Exponents of generalized function" + annotation (Dialog(tab="General", group="Inputs")); + + input Real tolerance = 100*Modelica.Constants.eps + "Tolerance if numerical integration is required" + annotation (Dialog(tab="General", group="Inputs")); + + input SorpLib.Choices.GeneralizedFunctionApproach approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Function approach" annotation (Dialog(tab="General", group="Inputs")); + +algorithm + // + // Check approach + // + int_z_dT := 0 + "Indefinite integral of fluid property data w.r.t. temperature without integration + constant"; + + if approach == SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature then + // + // Analytical solution exists + // + for ind in 1:size(coefficients,1) loop + if not Modelica.Math.isEqual(s1=exponents[ind], s2=-1, eps=100*Modelica.Constants.eps) then + int_z_dT := int_z_dT + coefficients[ind] * T ^ (exponents[ind] + 1) / + (exponents[ind] + 1) + "Indefinite integral of fluid property data w.r.t. temperature without integration + constant"; + else + int_z_dT := int_z_dT + coefficients[ind] * log(abs(T)) + "Indefinite integral of fluid property data w.r.t. temperature without integration + constant"; + end if; + end for; + + int_z_dT := z_ref * int_z_dT + "Indefinite integral of fluid property data w.r.t. temperature without integration + constant"; + + elseif approach == SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature then + // + // Analytical solution exists + // + for ind in 1:size(coefficients,1) loop + if not Modelica.Math.isEqual(s1=exponents[ind], s2=-1, eps=100*Modelica.Constants.eps) then + int_z_dT := int_z_dT - coefficients[ind] * T_ref * (1 - T / T_ref) ^ + (exponents[ind] + 1) / (exponents[ind] + 1) + "Indefinite integral of fluid property data w.r.t. temperature without integration + constant"; + else + int_z_dT := int_z_dT - coefficients[ind] * T_ref * log(abs(1 - T / T_ref)) + "Indefinite integral of fluid property data w.r.t. temperature without integration + constant"; + end if; + end for; + + int_z_dT := z_ref * int_z_dT + "Indefinite integral of fluid property data w.r.t. temperature without integration + constant"; + + else + // + // Analytical solution does not exist for 'ExponentialFunction_Temperature' + // and 'ExponentialFunction_ReducedTemperature' + // + assert(false, + "An analytical integral does not exist for the approach: " + String(approach) + ". Only a specific integral can be determined numerically.", + level = AssertionLevel.warning); + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the indefinite integral of the function 'generalizedFunction_T' +with respect to the temperature. The integral can only be solved analytically for +the approaches 'PolynomialFunction_Temperature' and 'PolynomialFunction_ReducedTemperature.' +Note that the integration constant is neglected. For full details of the original +function 'generalizedFunction_T,' check the documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.generalizedFunction_T\">SorpLib.Media.Functions.Utilities.generalizedFunction_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end intGeneralizedFunction_dT; diff --git a/SorpLib/Media/Functions/Utilities/intLinearInterpolation_dT.mo b/SorpLib/Media/Functions/Utilities/intLinearInterpolation_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..34e2b5dd8c8fb63dd86af7b39f9e078fa332ef4d --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/intLinearInterpolation_dT.mo @@ -0,0 +1,74 @@ +within SorpLib.Media.Functions.Utilities; +function intLinearInterpolation_dT + "Indefinite integral of linearly interpolated arbitrary fluid property z w.r.t. temperature" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_int_z_dT; + + // + // Definition of inputs + // + input Real abscissa[:] + "Known abscissa values" + annotation (Dialog(tab="General", group="Inputs")); + input Real ordinate[size(abscissa,1)] + "Known ordinate values" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Integer ind_gv + "Index of abscissa that is greater than actual temperature"; + +algorithm + if T <= abscissa[1] then + int_z_dT := ordinate[1] * T + "Indefinite integral of fluid property data w.r.t. temperature without + integration constant"; + + elseif T >= abscissa[end] then + int_z_dT := ordinate[end] * T + "Indefinite integral of fluid property data w.r.t. temperature without + integration constant"; + + else + // + // Finde abscissa that is greater than actual temperature + // + ind_gv :=1 + "Index of abscissa that is greater than actual temperature"; + + while T > abscissa[ind_gv] loop + ind_gv :=ind_gv + 1 + "Index of abscissa that is greater than actual temperature"; + end while; + + int_z_dT := ordinate[ind_gv-1] * T + + (ordinate[ind_gv] - ordinate[ind_gv-1]) / + (abscissa[ind_gv] - abscissa[ind_gv-1]) * + (T^2 / 2 - abscissa[ind_gv-1] * T) + "Indefinite integral of fluid property data w.r.t. temperature without + integration constant"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the indefinite integral of the function 'linearInterpolation_T' +with respect to the temperature. Note that the integration constant is neglected. +For full details of the original function 'linearInterpolation_T,' check the +documentation of the function +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.linearInterpolation_T\">SorpLib.Media.Functions.Utilities.linearInterpolation_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end intLinearInterpolation_dT; diff --git a/SorpLib/Media/Functions/Utilities/linearInterpolation_T.mo b/SorpLib/Media/Functions/Utilities/linearInterpolation_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..087c0d6e0a50dd7ae755f146acc3533bf6d3b101 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/linearInterpolation_T.mo @@ -0,0 +1,88 @@ +within SorpLib.Media.Functions.Utilities; +function linearInterpolation_T + "Interpolates an arbitrary fluid property z linearly" + extends SorpLib.Media.Functions.Utilities.BasesClasses.Partial_z_T; + + // + // Definition of inputs + // + input Real abscissa[:] + "Known abscissa values" + annotation (Dialog(tab="General", group="Inputs")); + input Real ordinate[size(abscissa,1)] + "Known ordinate values" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Integer ind_gv + "Index of abscissa that is greater than actual temperature"; + +algorithm + if T <= abscissa[1] then + z := ordinate[1] + "Fluid property data"; + + elseif T >= abscissa[end] then + z := ordinate[end] + "Fluid property data"; + + else + // + // Finde abscissa that is greater than actual temperature + // + ind_gv :=1 + "Index of abscissa that is greater than actual temperature"; + + while T > abscissa[ind_gv] loop + ind_gv :=ind_gv + 1 + "Index of abscissa that is greater than actual temperature"; + end while; + + z := ordinate[ind_gv-1] + + (ordinate[ind_gv] - ordinate[ind_gv-1]) / + (abscissa[ind_gv] - abscissa[ind_gv-1]) * + (T - abscissa[ind_gv-1]) + "Fluid property data"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates an arbitrary fluid property <i>z</i> via piecewise linear +interpolation as a function of temperature as well as known abscissa and ordinate +values. Examples for the arbitrary fluid property <i>z</i> are the specific heat +capacity <i>c</i> or the specific volume <i>v</i>. +</p> + +<h4>Main equations</h4> +<p> +For a given temperature <i>T</i>, the arbitrary fluid property <i>z</i> is calculated +using abscissa <i>z<sub>known</sub></i> and its corresponding ordinate <i>T<sub>known</sub></i>, +values that are closest to the given temperature <i>T</i>: +</p> +<pre> + z = z<sub>known,smaller</sub> + (z<sub>known,greater</sub> - z<sub>known,smaller</sub>) / (T<sub>known,greater</sub> - T<sub>known,smaller</sub>) * (T - T<sub>known,smaller</sub>); +</pre> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + For temperatures outside the abscissa values, the ordinate values of the smallest or + largest abscissa value are returned. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 15, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end linearInterpolation_T; diff --git a/SorpLib/Media/Functions/Utilities/package.mo b/SorpLib/Media/Functions/Utilities/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..6f75b4de7cba094e959a60e25a6eeed9f7b47bbc --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Functions; +package Utilities "Package containing utility functions and models for calculating media properties" +extends Modelica.Icons.UtilitiesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains utility functions and models required to calculate fluid +property data. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Utilities; diff --git a/SorpLib/Media/Functions/Utilities/package.order b/SorpLib/Media/Functions/Utilities/package.order new file mode 100644 index 0000000000000000000000000000000000000000..4a5b9d38e39b327d075f247c7ac6e2cc46a4d5a5 --- /dev/null +++ b/SorpLib/Media/Functions/Utilities/package.order @@ -0,0 +1,15 @@ +BasesClasses +generalizedFunction_T +dgeneralizedFunction_dT +ddgeneralizedFunction_dT_dT +intGeneralizedFunction_dT +linearInterpolation_T +dlinearInterpolation_dT +ddlinearInterpolation_dT_dT +intLinearInterpolation_dT +calcCubicSplineCoefficients +cubicSplineInterpolation_T +dcubicSplineInterpolation_dT +ddcubicSplineInterpolation_dT_dT +intCubicSplineInterpolation_dT +Testers diff --git a/SorpLib/Media/Functions/package.mo b/SorpLib/Media/Functions/package.mo index 1a49c2a15bfe9c88b442c314e5c5a38b6312d07c..7b1d12322a2195757660b4fb9fbee2e9a0a375ca 100644 --- a/SorpLib/Media/Functions/package.mo +++ b/SorpLib/Media/Functions/package.mo @@ -1,10 +1,20 @@ within SorpLib.Media; -package Functions -extends SorpLib.Internals.ClassTypes.InternalPackage; - - - - - +package Functions "Functions required to calculate fluid property data" + extends Modelica.Icons.FunctionsPackage; + annotation (Documentation(info="<html> +<p> +This package contains functions used to calculate fluid property data. In particular, +these functions are required for calculating data for pure and multi-component +adsorption. Please check the documentation of the individual packages for more +details on the implemented functions. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); end Functions; diff --git a/SorpLib/Media/Functions/package.order b/SorpLib/Media/Functions/package.order index 5fc88027a3219cd010328f6dc665d6b2633b6646..bb28e34f81549804d93dc0c9e96ec40a5a32100f 100644 --- a/SorpLib/Media/Functions/package.order +++ b/SorpLib/Media/Functions/package.order @@ -1,6 +1,4 @@ -CharCurve1Arctan -CharCurve1Arctan_inverse -CharCurve1Arctan_dWdA -CharCurve2Polynomial -CharCurve2Polynomial_dWdA -Testers +SorptionEquilibria +SorptionEnthalpies +SpecificHeatCapacitiesAdsorpt +Utilities diff --git a/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2/package.mo b/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..ea931503638000379be98db6b993f4382f7fce0c --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2/package.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.IdealGasMixtures; +package DryAir_N2_O2 "SorpLib: Simple dry air consisting of N2 and O2" + extends SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture( + mediumName="DryAir_N2_O2", + data={Modelica.Media.IdealGases.Common.SingleGasesData.N2, + Modelica.Media.IdealGases.Common.SingleGasesData.O2}, + fluidConstants={Modelica.Media.IdealGases.Common.FluidData.N2, + Modelica.Media.IdealGases.Common.FluidData.O2}, + substanceNames={"Nitrogen", + "Oxygen"}, + final reference_X={0.7655,0.2345}); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the fluid property of dry air modeled as ideal +gas mixture of N<sub>2</sub> and O<sub>2</sub>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 24, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DryAir_N2_O2; diff --git a/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2/package.order b/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O/package.mo b/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..30d9ec2fd756aa40046f235a8431776444ea30e1 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O/package.mo @@ -0,0 +1,51 @@ +within SorpLib.Media.IdealGasMixtures; +package DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O "SorpLib: Simple dry air consisting of N2, O2, Ar, CO2, Ne, He, CH4, and H2O" + extends SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture( + mediumName="DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O", + data={Modelica.Media.IdealGases.Common.SingleGasesData.N2, + Modelica.Media.IdealGases.Common.SingleGasesData.O2, + Modelica.Media.IdealGases.Common.SingleGasesData.Ar, + Modelica.Media.IdealGases.Common.SingleGasesData.CO2, + Modelica.Media.IdealGases.Common.SingleGasesData.Ne, + Modelica.Media.IdealGases.Common.SingleGasesData.He, + Modelica.Media.IdealGases.Common.SingleGasesData.CH4, + Modelica.Media.IdealGases.Common.SingleGasesData.H2O}, + fluidConstants={Modelica.Media.IdealGases.Common.FluidData.N2, + Modelica.Media.IdealGases.Common.FluidData.O2, + Modelica.Media.IdealGases.Common.FluidData.Ar, + Modelica.Media.IdealGases.Common.FluidData.CO2, + Modelica.Media.IdealGases.Common.FluidData.Ne, + Modelica.Media.IdealGases.Common.FluidData.He, + Modelica.Media.IdealGases.Common.FluidData.CH4, + Modelica.Media.IdealGases.Common.FluidData.H2O}, + substanceNames={"Nitrogen", + "Oxygen", + "Argon", + "Carbondioxide", + "Neon", + "Helium", + "Methane", + "Water"}, + final reference_X={0.7552/1.00001439,0.2313/1.00001439, + 0.0129/1.00001439,5.90e-4/1.00001439, + 1.27e-05/1.00001439,7.20e-07/1.00001439, + 9.70e-07/1.00001439,1e-5/1.00001439}); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the fluid property of dry air modeled as ideal +gas mixture of N<sub>2</sub>, O<sub>2</sub>, Ar, CO<sub>2</sub>, Ne, He, +CH<sub>4</sub>, and H<sub>2</sub>0. +</p> +</html>", revisions="<html> +<ul> + <li> + November 24, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O; diff --git a/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O/package.order b/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2_CO2_H2O/package.mo b/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2_CO2_H2O/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9179a2d238f6f3f412621117eb5c73b84fbb96a3 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2_CO2_H2O/package.mo @@ -0,0 +1,35 @@ +within SorpLib.Media.IdealGasMixtures; +package DryAir_N2_O2_CO2_H2O "SorpLib: Simple dry air consisting of N2, O2, CO2, and H2O" + extends SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture( + mediumName="DryAir_N2_O2_CO2_H2O", + data={Modelica.Media.IdealGases.Common.SingleGasesData.N2, + Modelica.Media.IdealGases.Common.SingleGasesData.O2, + Modelica.Media.IdealGases.Common.SingleGasesData.CO2, + Modelica.Media.IdealGases.Common.SingleGasesData.H2O}, + fluidConstants={Modelica.Media.IdealGases.Common.FluidData.N2, + Modelica.Media.IdealGases.Common.FluidData.O2, + Modelica.Media.IdealGases.Common.FluidData.CO2, + Modelica.Media.IdealGases.Common.FluidData.H2O}, + substanceNames={"Nitrogen", + "Oxygen", + "Carbondioxide", + "Water"}, + final reference_X={0.7650,0.2344,5.90e-4,1e-5}); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the fluid property of dry air modeled as ideal +gas mixture of N<sub>2</sub>, O<sub>2</sub>, CO<sub>2</sub>, and H<sub>2</sub>0. +</p> +</html>", revisions="<html> +<ul> + <li> + November 24, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DryAir_N2_O2_CO2_H2O; diff --git a/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2_CO2_H2O/package.order b/SorpLib/Media/IdealGasMixtures/DryAir_N2_O2_CO2_H2O/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/ddsaturationPressureH2O_dT_dT.mo b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/ddsaturationPressureH2O_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..3b8939961d7e4796fc6498300a1281035f481254 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/ddsaturationPressureH2O_dT_dT.mo @@ -0,0 +1,187 @@ +within SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture; +function ddsaturationPressureH2O_dT_dT + "Returns second-order partial derivative of saturatation pressure of water w.r.t. temperature as function of temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_sat + "Saturation temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerPressureByTemperatureTemperature ddp_sat_dT_dT + "Second-order partial derivative of saturation pressure w.r.t. temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Modelica.Units.SI.Pressure p_trp = 611.657 + "Triple point pressure"; + constant Modelica.Units.SI.Pressure p_crit = 22.064e6 + "Critical pressure"; + + constant Modelica.Units.SI.Temperature T_trp = 273.16 + "Triple point temperature"; + constant Modelica.Units.SI.Temperature T_crit = 647.096 + "Critical temperature"; + + constant Real[2] coeff_s = {-13.9281690, 34.7078238} + "Coefficients of the gas-solid boundary"; + constant Real[6] coeff_l = {-7.85951783, 1.84408259, -11.7866497, + 22.6807411, -15.9618719, 1.80122502} + "Coefficients of the gas-liquid boundary"; + + constant Real[2] exp_s = {-1.5, -1.25} + "Exponents of the gas-solid boundary"; + constant Real[6] exp_l = {1, 1.5, 3, + 3.5, 4, 7.5} + "Exponents of the gas-liquid boundary"; + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_sat_s + "Saturation pressure of gas-solid boundary"; + Modelica.Media.Common.DerPressureByTemperature dp_sat_s_dT + "First-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + SorpLib.Units.DerPressureByTemperatureTemperature ddp_sat_s_dT_dT + "Second-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + + Modelica.Units.SI.Pressure p_sat_l + "Saturation pressure of gas-liquid boundary"; + Modelica.Media.Common.DerPressureByTemperature dp_sat_l_dT + "First-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + SorpLib.Units.DerPressureByTemperatureTemperature ddp_sat_l_dT_dT + "Second-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + + Real T_red_s = T_sat/T_trp + "Reduced temperature required for gas-solid boundary"; + Real T_red_fl = 1 - T_sat/T_crit + "Reduced temperature required for gas-liquid boundary"; + + Real lambda(unit="1") = SorpLib.Numerics.smoothTransition( + x=T_sat, transitionPoint=T_trp, transitionLength=1, noDiff=3) + "Transiation factor"; + Real dlambda_dT(unit="1/K") = SorpLib.Numerics.smoothTransition_der( + x=T_sat, transitionPoint=T_trp, transitionLength=1, noDiff=3, + x_der=1) + "First-order derivative of transiation factor w.r.t. temperature"; + Real ddlambda_dT_dT(unit="1/(K2)") = SorpLib.Numerics.smoothTransition_der2( + x=T_sat, transitionPoint=T_trp, transitionLength=1, noDiff=3, + x_der=1, x_der2=0) + "Second-order derivative of transiation factor w.r.t. temperature"; + + Real aux_s_1 + "Auxiliary variable 1 of saturation pressure of gas-solid boundary"; + Real aux_s_2 + "Auxiliary variable 2 of saturation pressure of gas-solid boundary"; + + Real aux_l_1 + "Auxiliary variable 1 of saturation pressure of gas-liquid boundary"; + Real aux_l_2 + "Auxiliary variable 2 of saturation pressure of gas-liquid boundary"; + +algorithm + // + // Calculate pressures + // + p_sat_s := p_trp * exp(coeff_s[1] - coeff_s[1] * T_red_s ^ exp_s[1] + + coeff_s[2] - coeff_s[2] * T_red_s ^ exp_s[2]) + "Saturation pressure of gas-solid boundary"; + p_sat_l := p_crit * exp(T_crit/T_sat * + (coeff_l[1] * T_red_fl ^ exp_l[1] + + coeff_l[2] * T_red_fl ^ exp_l[2] + + coeff_l[3] * T_red_fl ^ exp_l[3] + + coeff_l[4] * T_red_fl ^ exp_l[4] + + coeff_l[5] * T_red_fl ^ exp_l[5] + + coeff_l[6] * T_red_fl ^ exp_l[6])) + "Saturation pressure of gas-liquid boundary"; + + // + // Calculate auxiliary variables + // + aux_s_1 := -p_sat_s/T_sat + "Auxiliary variable 1 of saturation pressure of gas-solid boundary"; + aux_s_2 := (coeff_s[1] * exp_s[1] * T_red_s ^ exp_s[1] + + coeff_s[2] * exp_s[2] * T_red_s ^ exp_s[2]) + "Auxiliary variable 2 of saturation pressure of gas-solid boundary"; + + aux_l_1 := -p_sat_l/T_sat + "Auxiliary variable 1 of saturation pressure of gas-liquid boundary"; + aux_l_2 := log(p_sat_l/p_crit) + coeff_l[1] + + coeff_l[2] * exp_l[2] * T_red_fl^(exp_l[2]-1) + + coeff_l[3] * exp_l[3] * T_red_fl^(exp_l[3]-1) + + coeff_l[4] * exp_l[4] * T_red_fl^(exp_l[4]-1) + + coeff_l[5] * exp_l[5] * T_red_fl^(exp_l[5]-1) + + coeff_l[6] * exp_l[6] * T_red_fl^(exp_l[6]-1) + "Auxiliary variable 2 of saturation pressure of gas-liquid boundary"; + + // + // Calculate first-order partial derivatives of pressures w.r.t. temperature + // + dp_sat_s_dT := aux_s_1 * aux_s_2 + "First-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + dp_sat_l_dT := aux_l_1 * aux_l_2 + "First-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + + // + // Calculate second-order partial derivatives of pressures w.r.t. temperature + // + ddp_sat_s_dT_dT := (p_sat_s/T_sat^2 - dp_sat_s_dT/T_sat) * aux_s_2 + + aux_s_1/T_trp * (coeff_s[1] * exp_s[1]^2 * T_red_s ^ (exp_s[1]-1) + + coeff_s[2] * exp_s[2]^2 * T_red_s ^ (exp_s[2]-1)) + "Second-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + ddp_sat_l_dT_dT := (p_sat_l/T_sat^2 - dp_sat_l_dT/T_sat) * aux_l_2 + + aux_l_1 * (1/p_sat_l * dp_sat_l_dT + (-1/T_crit) * + (coeff_l[2] * exp_l[2] * (exp_l[2]-1) * T_red_fl^(exp_l[2]-2) + + coeff_l[3] * exp_l[3] * (exp_l[3]-1) * T_red_fl^(exp_l[3]-2) + + coeff_l[4] * exp_l[4] * (exp_l[4]-1) * T_red_fl^(exp_l[4]-2) + + coeff_l[5] * exp_l[5] * (exp_l[5]-1) * T_red_fl^(exp_l[5]-2) + + coeff_l[6] * exp_l[6] * (exp_l[6]-1) * T_red_fl^(exp_l[6]-2))) + "Second-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + + // + // Check for boundary + // + ddp_sat_dT_dT :=ddlambda_dT_dT*p_sat_s + + 2*dlambda_dT*dp_sat_s_dT + + lambda*ddp_sat_s_dT_dT + + (-ddlambda_dT_dT)*p_sat_l + + 2*(-dlambda_dT)*dp_sat_l_dT + + (1-lambda)*ddp_sat_l_dT_dT + "Second-order partial derivative of saturation pressure w.r.t. temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the second-order partial saturation pressure of water +with respect to temperature depending on the temperature. This functions covers +both, the solid-gas and the gas-liquid boundary. For details, please check the +function +<a href=\"Modelica://SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture.saturationPressureH2O_T\">SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture.saturationPressureH2O_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 24, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddsaturationPressureH2O_dT_dT; diff --git a/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/dsaturationPressureH2O_dT.mo b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/dsaturationPressureH2O_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..0976787838b43e1568223f36ff0ac0425c6ac082 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/dsaturationPressureH2O_dT.mo @@ -0,0 +1,136 @@ +within SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture; +function dsaturationPressureH2O_dT + "Returns partial derivative of saturatation pressure of water w.r.t. temperature as function of temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_sat + "Saturation temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Media.Common.DerPressureByTemperature dp_sat_dT + "First-order partial derivative of saturation pressure w.r.t. temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Modelica.Units.SI.Pressure p_trp = 611.657 + "Triple point pressure"; + constant Modelica.Units.SI.Pressure p_crit = 22.064e6 + "Critical pressure"; + + constant Modelica.Units.SI.Temperature T_trp = 273.16 + "Triple point temperature"; + constant Modelica.Units.SI.Temperature T_crit = 647.096 + "Critical temperature"; + + constant Real[2] coeff_s = {-13.9281690, 34.7078238} + "Coefficients of the gas-solid boundary"; + constant Real[6] coeff_l = {-7.85951783, 1.84408259, -11.7866497, + 22.6807411, -15.9618719, 1.80122502} + "Coefficients of the gas-liquid boundary"; + + constant Real[2] exp_s = {-1.5, -1.25} + "Exponents of the gas-solid boundary"; + constant Real[6] exp_l = {1, 1.5, 3, + 3.5, 4, 7.5} + "Exponents of the gas-liquid boundary"; + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_sat_s + "Saturation pressure of gas-solid boundary"; + Modelica.Media.Common.DerPressureByTemperature dp_sat_s_dT + "First-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + + Modelica.Units.SI.Pressure p_sat_l + "Saturation pressure of gas-liquid boundary"; + Modelica.Media.Common.DerPressureByTemperature dp_sat_l_dT + "First-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + + Real T_red_s = T_sat/T_trp + "Reduced temperature required for gas-solid boundary"; + Real T_red_fl = 1 - T_sat/T_crit + "Reduced temperature required for gas-liquid boundary"; + + Real lambda(unit="1") = SorpLib.Numerics.smoothTransition(x=T_sat, + transitionPoint=T_trp, transitionLength=1, noDiff=3) + "Transiation factor"; + Real dlambda_dT(unit="1/K") = SorpLib.Numerics.smoothTransition_der(x=T_sat, + transitionPoint=T_trp, transitionLength=1, noDiff=3, x_der=1) + "First-order derivative of transiation factor w.r.t. temperature"; + +algorithm + // + // Calculate pressures + // + p_sat_s := p_trp * exp(coeff_s[1] - coeff_s[1] * T_red_s ^ exp_s[1] + + coeff_s[2] - coeff_s[2] * T_red_s ^ exp_s[2]) + "Saturation pressure of gas-solid boundary"; + p_sat_l := p_crit * exp(T_crit/T_sat * + (coeff_l[1] * T_red_fl ^ exp_l[1] + + coeff_l[2] * T_red_fl ^ exp_l[2] + + coeff_l[3] * T_red_fl ^ exp_l[3] + + coeff_l[4] * T_red_fl ^ exp_l[4] + + coeff_l[5] * T_red_fl ^ exp_l[5] + + coeff_l[6] * T_red_fl ^ exp_l[6])) + "Saturation pressure of gas-liquid boundary"; + + // + // Calculate first-order partial derivatives of pressures w.r.t. temperature + // + dp_sat_s_dT := -p_sat_s/T_sat * + (coeff_s[1] * exp_s[1] * T_red_s ^ exp_s[1] + + coeff_s[2] * exp_s[2] * T_red_s ^ exp_s[2]) + "First-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + dp_sat_l_dT := -p_sat_l/T_sat * ( + log(p_sat_l/p_crit) + + coeff_l[1] + + coeff_l[2] * exp_l[2] * T_red_fl^(exp_l[2]-1) + + coeff_l[3] * exp_l[3] * T_red_fl^(exp_l[3]-1) + + coeff_l[4] * exp_l[4] * T_red_fl^(exp_l[4]-1) + + coeff_l[5] * exp_l[5] * T_red_fl^(exp_l[5]-1) + + coeff_l[6] * exp_l[6] * T_red_fl^(exp_l[6]-1)) + "First-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + + // + // Check for boundary + // + dp_sat_dT :=dlambda_dT*p_sat_s + + lambda*dp_sat_s_dT + + (-dlambda_dT)*p_sat_l + + (1-lambda)*dp_sat_l_dT + "First-order partial derivative of saturation pressure w.r.t. temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the first-order partial saturation pressure of water +with respect to temperature depending on the temperature. This functions covers +both, the solid-gas and the gas-liquid boundary. For details, please check the +function +<a href=\"Modelica://SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture.saturationPressureH2O_T\">SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture.saturationPressureH2O_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 24, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dsaturationPressureH2O_dT; diff --git a/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/package.mo b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..73f9a995fc3d119f3b5ca78030d429288fd893bd --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/package.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.IdealGasMixtures.Interfaces; +partial package PartialIdealGasMixture "Medium model of an ideal gas mixture based on NASA source" + extends Modelica.Media.IdealGases.Common.MixtureGasNasa( + final reference_T(min=0) = 0, + final reference_p = 1e5); + + // + // New functions + // + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model extends the medium model of an ideal gas mixture provided +in the Modelica Standard Library by some additional functions required +in SorpLib. For details of the original medium model, check out the +package +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa\">Modelica.Media.IdealGases.Common.MixtureGasNasa</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 24, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialIdealGasMixture; diff --git a/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/package.order b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/package.order new file mode 100644 index 0000000000000000000000000000000000000000..3d7c373cc5cd7d7ad40ec4ec4ecfdaf28d5690b8 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/package.order @@ -0,0 +1,6 @@ +partialPressures +specificEnthalpy_i_T +specificEntropy_i_pTX +saturationPressureH2O_T +dsaturationPressureH2O_dT +ddsaturationPressureH2O_dT_dT diff --git a/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/partialPressures.mo b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/partialPressures.mo new file mode 100644 index 0000000000000000000000000000000000000000..fa9f8ee9cc5580e410fe7881510ae6835467cb74 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/partialPressures.mo @@ -0,0 +1,48 @@ +within SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture; +function partialPressures + "Returns partial pressures" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[nX] p_i + "Partial pressures" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction Y[nX]= + massToMoleFractions(X=state.X, MMX=MMX) + "Mole fractions"; + +algorithm + p_i := Y .* state.p + "Partial pressures"; + + // + // Annotations + // + annotation (Documentation(info="<html> + <p> + This function calculates the partial pressures as function of the state record. + </p> + </html>", + revisions="<html> + <ul> + <li> + November 24, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> + </ul> + </html>")); +end partialPressures; diff --git a/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/saturationPressureH2O_T.mo b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/saturationPressureH2O_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..44db0a4afeef22497055d54314485739a7cb7752 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/saturationPressureH2O_T.mo @@ -0,0 +1,109 @@ +within SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture; +function saturationPressureH2O_T + "Returns saturatation pressure of water as function of temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_sat + "Saturation temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_sat + "Saturation pressure" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Modelica.Units.SI.Pressure p_trp = 611.657 + "Triple point pressure"; + constant Modelica.Units.SI.Pressure p_crit = 22.064e6 + "Critical pressure"; + + constant Modelica.Units.SI.Temperature T_trp = 273.16 + "Triple point temperature"; + constant Modelica.Units.SI.Temperature T_crit = 647.096 + "Critical temperature"; + + constant Real[2] coeff_s = {-13.9281690, 34.7078238} + "Coefficients of the gas-solid boundary"; + constant Real[6] coeff_l = {-7.85951783, 1.84408259, -11.7866497, + 22.6807411, -15.9618719, 1.80122502} + "Coefficients of the gas-liquid boundary"; + + constant Real[2] exp_s = {-1.5, -1.25} + "Exponents of the gas-solid boundary"; + constant Real[6] exp_l = {1, 1.5, 3, + 3.5, 4, 7.5} + "Exponents of the gas-liquid boundary"; + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_sat_s + "Saturation pressure of gas-solid boundary"; + Modelica.Units.SI.Pressure p_sat_l + "Saturation pressure of gas-liquid boundary"; + + Real T_red_s = T_sat/T_trp + "Reduced temperature required for gas-solid boundary"; + Real T_red_fl = 1 - T_sat/T_crit + "Reduced temperature required for gas-liquid boundary"; + + Real lambda(unit="1") = SorpLib.Numerics.smoothTransition(x=T_sat, + transitionPoint=T_trp, transitionLength=1, noDiff=3) + "Transiation factor"; + +algorithm + // + // Calculate pressures + // + p_sat_s := p_trp * exp(coeff_s[1] - coeff_s[1] * T_red_s ^ exp_s[1] + + coeff_s[2] - coeff_s[2] * T_red_s ^ exp_s[2]) + "Saturation pressure of gas-solid boundary"; + p_sat_l := p_crit * exp(T_crit/T_sat * + (coeff_l[1] * T_red_fl ^ exp_l[1] + + coeff_l[2] * T_red_fl ^ exp_l[2] + + coeff_l[3] * T_red_fl ^ exp_l[3] + + coeff_l[4] * T_red_fl ^ exp_l[4] + + coeff_l[5] * T_red_fl ^ exp_l[5] + + coeff_l[6] * T_red_fl ^ exp_l[6])) + "Saturation pressure of gas-liquid boundary"; + + // + // Check for boundary + // + p_sat :=lambda*p_sat_s + (1-lambda)*p_sat_l + "Saturation pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the saturation pressure of water depending on +the temperature. This functions covers both, the solid-gas and the gas- +liquid boundary. +</p> + +<h4>References</h4> +<ul> + <li> + Wagner, W. and Pruß, A (2002). The IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, Journal of Physical and Chemical Reference Data, 31:387. DOI: https://doi.org/10.1063/1.1461829. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 24, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end saturationPressureH2O_T; diff --git a/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/specificEnthalpy_i_T.mo b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/specificEnthalpy_i_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..141a544b56f59af030dca833c91c48aa7eb4a19d --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/specificEnthalpy_i_T.mo @@ -0,0 +1,56 @@ +within SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture; +function specificEnthalpy_i_T + "Returns specific enthalpy of component i" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Integer ind_component + "Component index whose specific enthalpy is to be calculated" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean exclEnthForm=excludeEnthalpyOfFormation + "= true, enthalpy of formation Hf is not included in specific enthalpy h" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Media.Interfaces.Choices.ReferenceEnthalpy refChoice= + referenceChoice + "Choice of reference enthalpy" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.SpecificEnthalpy h_off = h_offset + "User definedreference enthalpy, if referenceChoice = UserDefined" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy of component ind_component" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + h := Modelica.Media.IdealGases.Common.Functions.h_T( + data[ind_component], T, exclEnthForm, refChoice, h_off) + "Specific enthalpy of component ind_component"; + + // + // Annotations + // + annotation(Inline=false,smoothOrder=2, + Documentation(info="<html> +<p> +This function calculates the specific enthalpy of component i. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 24, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end specificEnthalpy_i_T; diff --git a/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/specificEntropy_i_pTX.mo b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/specificEntropy_i_pTX.mo new file mode 100644 index 0000000000000000000000000000000000000000..bbdb1241351576732bfcdf5ff890b9d834e19a8b --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Interfaces/PartialIdealGasMixture/specificEntropy_i_pTX.mo @@ -0,0 +1,71 @@ +within SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture; +function specificEntropy_i_pTX + "Returns specific entropy of component i" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Integer ind_component + "Component index whose specific entropy is to be calculated" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions of mixture (full vector)" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean exclEnthForm=excludeEnthalpyOfFormation + "= true, enthalpy of formation Hf is not included in specific enthalpy h" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Media.Interfaces.Choices.ReferenceEnthalpy refChoice= + referenceChoice + "Choice of reference enthalpy" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.SpecificEnthalpy h_off = h_offset + "User definedreference enthalpy, if referenceChoice = UserDefined" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEntropy s + "Specific entropy of component ind_component" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[nX] Y = massToMoleFractions(X, data.MM) + "Molar fractions"; + +algorithm + s := Modelica.Media.IdealGases.Common.Functions.s0_T(data[ind_component], + T) - Modelica.Constants.R/MMX[ind_component] * (if X[ind_component] < + Modelica.Constants.eps then Y[ind_component] else + Modelica.Math.log(Y[ind_component]*p / reference_p)) + "Specific entropy of component ind_component"; + + // + // Annotations + // + annotation(Inline=false,smoothOrder=2, + Documentation(info="<html> +<p> +This function calculates the specific entropy of component i. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 24, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end specificEntropy_i_pTX; diff --git a/SorpLib/Media/IdealGasMixtures/Interfaces/package.mo b/SorpLib/Media/IdealGasMixtures/Interfaces/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..47e950993db64052592ecb0deb04a2c9dfce66d7 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Interfaces/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.IdealGasMixtures; +package Interfaces "Interfaces for models of ideal gas mixtures" +extends Modelica.Icons.InterfacesPackage; + +annotation (Documentation(info="<html> +<p> +This package provides definitions of basic interfaces for models +of ideal gas mixtures. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Interfaces; diff --git a/SorpLib/Media/IdealGasMixtures/Interfaces/package.order b/SorpLib/Media/IdealGasMixtures/Interfaces/package.order new file mode 100644 index 0000000000000000000000000000000000000000..a38ca7df1026bbac7e96c24b1d98f7040d3609e2 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Interfaces/package.order @@ -0,0 +1 @@ +PartialIdealGasMixture diff --git a/SorpLib/Media/IdealGasMixtures/Tester/Test_DryAir_N2_O2.mo b/SorpLib/Media/IdealGasMixtures/Tester/Test_DryAir_N2_O2.mo new file mode 100644 index 0000000000000000000000000000000000000000..37247cf80ab8bb912ca1196d6ba08ca59619ce3d --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Tester/Test_DryAir_N2_O2.mo @@ -0,0 +1,211 @@ +within SorpLib.Media.IdealGasMixtures.Tester; +model Test_DryAir_N2_O2 "Tester for dry air consisting of N2 and O2" + extends Modelica.Icons.Example; + + // + // Definition of paramters + // + replaceable package Medium = SorpLib.Media.IdealGasMixtures.DryAir_N2_O2 + constrainedby Modelica.Media.IdealGases.Common.MixtureGasNasa + "Medium" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true); + package MediumReference = Modelica.Media.Air.ReferenceAir.Air_pT + "Reference medium: Detailed dry air" + annotation (Dialog(tab="General",group="Models and Media")); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p(start=100, fixed=true) + "Pressure"; + Modelica.Units.SI.Temperature T(start=253.15, fixed=true) + "Temperature"; + Modelica.Units.SI.MassFraction[Medium.nX] X = Medium.reference_X + "Mass fractions"; + + Medium.BaseProperties medium_pTX + "Base properties calculated with pressure, temperature, and mass fractions"; + MediumReference.BaseProperties mediumReference_pTX + "Base properties calculated with pressure, temperature, and mass fractions"; + + Modelica.Units.SI.Pressure[Medium.nX] p_i + "Partial pressures"; + + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + Modelica.Units.SI.SpecificVolume vReference + "Specific volume"; + + Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy"; + Modelica.Units.SI.SpecificEnthalpy h_1 + "Specific enthalpy of component 1"; + Modelica.Units.SI.SpecificEnthalpy h_2 + "Specific enthalpy of component 2"; + Modelica.Units.SI.SpecificEnthalpy hReference + "Specific enthalpy"; + + Modelica.Units.SI.SpecificInternalEnergy u + "Specific internal energy"; + Modelica.Units.SI.SpecificInternalEnergy uReference + "Specific internal energy"; + + Modelica.Units.SI.SpecificEntropy s + "Specific entropy"; + Modelica.Units.SI.SpecificEntropy s_1 + "Specific entropy of component 1"; + Modelica.Units.SI.SpecificEntropy s_2 + "Specific entropy of component 2"; + Modelica.Units.SI.SpecificEntropy sReference + "Specific entropy"; + + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity"; + Modelica.Units.SI.SpecificHeatCapacity cpReference + "Specific heat capacity"; + + Modelica.Units.SI.RelativePressureCoefficient beta + "Isobaric expansion coefficient"; + Modelica.Units.SI.RelativePressureCoefficient betaReference + "Isobaric expansion coefficient"; + + Modelica.Units.SI.IsothermalCompressibility kappa + "Isothermal compressibility"; + Modelica.Units.SI.IsothermalCompressibility kappaReference + "Isothermal compressibility"; + + Modelica.Units.SI.Pressure p_sat_water + "Saturation pressure of water"; + Modelica.Media.Common.DerPressureByTemperature dp_sat_water_dT + "First-order partial derivative of saturation pressure of water w.r.t. + temperature"; + SorpLib.Units.DerPressureByTemperatureTemperature ddp_sat_water_dT_dT + "Second-order partial derivative of saturation pressure of water w.r.t. + temperature"; + + // + // Protected parameters + // +protected + final parameter Modelica.Units.SI.SpecificEnthalpy dh_ref= + Medium.specificEnthalpy_pTX(p=1e5, T=273.15, X=Medium.reference_X) - + MediumReference.specificEnthalpy_pTX(p=1e5, T=273.15, X=MediumReference.reference_X) + "Difference of enthalpies to get offset of reference enthalpies"; + + final parameter Modelica.Units.SI.SpecificInternalEnergy du_ref= + (Medium.specificEnthalpy_pTX(p=1e5, T=273.15, X=Medium.reference_X) + + 1e5 * Medium.density_pTX(p=1e5, T=273.15, X=Medium.reference_X)) - + (MediumReference.specificEnthalpy_pTX(p=1e5, T=273.15, X=MediumReference.reference_X) + + 1e5 * MediumReference.density_pTX(p=1e5, T=273.15, X=MediumReference.reference_X)) + "Difference of specific internal energies to get offset of reference internal + energies"; + + final parameter Modelica.Units.SI.SpecificEntropy ds_ref= + Medium.specificEntropy_pTX(p=1e5, T=273.15, X=Medium.reference_X) - + MediumReference.specificEntropy_pTX(p=1e5, T=273.15, X=MediumReference.reference_X) + "Difference of entropies to get offset of reference entropies"; + +equation + // + // Change independent state variables + // + der(p) = (20e5 - 100) / 20 + "Predescribed slope of pressure"; + der(T) = (573.15 - 253.15) / 20 + "Predescribed slope of temperature"; + + // + // Calculate state variables + // + medium_pTX.p = p + "Base properties calculated with pressure and temperature"; + medium_pTX.T = T + "Base properties calculated with pressure and temperature"; + medium_pTX.X = X + "Base properties calculated with pressure and temperature"; + + mediumReference_pTX.p = p + "Base properties calculated with pressure, temperature, and mass fractions"; + mediumReference_pTX.T = T + "Base properties calculated with pressure, temperature, and mass fractions"; + + // + // Calculate further variables + // + p_i = Medium.partialPressures(state=medium_pTX.state) + "Partial pressures"; + + v = 1/medium_pTX.d + "Specific volume"; + vReference = 1/mediumReference_pTX.d + "Specific volume"; + + h = medium_pTX.h + "Specific enthalpy"; + h_1 = Medium.specificEnthalpy_i_T(ind_component=1, T=T) + "Specific enthalpy of component 1"; + h_2 = Medium.specificEnthalpy_i_T(ind_component=2, T=T) + "Specific enthalpy of component 2"; + hReference = mediumReference_pTX.h + dh_ref + "Specific enthalpy"; + + u = medium_pTX.u + "Specific internal energy"; + uReference = mediumReference_pTX.u + du_ref + "Specific internal energy"; + + s = Medium.specificEntropy(state=medium_pTX.state) + "Specific entropy"; + s_1 = Medium.specificEntropy_i_pTX(ind_component=1, p=p, T=T, X=X) + "Specific entropy of component 1"; + s_2 = Medium.specificEntropy_i_pTX(ind_component=1, p=p, T=T, X=X) + "Specific entropy of component 2"; + sReference = MediumReference.specificEntropy(state=mediumReference_pTX.state) + + ds_ref + "Specific entropy"; + + cp = Medium.specificHeatCapacityCp(state=medium_pTX.state) + "Specific heat capacity"; + cpReference = MediumReference.specificHeatCapacityCp(state=mediumReference_pTX.state) + "Specific heat capacity"; + + beta = Medium.beta(state=medium_pTX.state) + "Isobaric expansion coefficient"; + betaReference = MediumReference.beta(state=mediumReference_pTX.state) + "Isobaric expansion coefficient"; + + kappa = Medium.kappa(state=medium_pTX.state) + "Isothermal compressibility"; + kappaReference = MediumReference.kappa(state=mediumReference_pTX.state) + "Isothermal compressibility"; + + p_sat_water=Medium.saturationPressureH2O_T(T_sat=T) + "Saturation pressure of water"; + dp_sat_water_dT=Medium.dsaturationPressureH2O_dT(T_sat=T) + "First-order partial derivative of saturation pressure of water w.r.t. + temperature"; + ddp_sat_water_dT_dT=Medium.ddsaturationPressureH2O_dT_dT(T_sat=T) + "Second-order partial derivative of saturation pressure of water w.r.t. + temperature"; + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal gas mixture of +N<sub>2</sub> and O<sub>2</sub>. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_DryAir_N2_O2; diff --git a/SorpLib/Media/IdealGasMixtures/Tester/Test_DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O.mo b/SorpLib/Media/IdealGasMixtures/Tester/Test_DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O.mo new file mode 100644 index 0000000000000000000000000000000000000000..562ac2af047d08b4c21732a95a87237674958f28 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Tester/Test_DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.IdealGasMixtures.Tester; +model Test_DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O + "Tester for dry air consisting of N2, O2, Ar, CO2, Ne, He, CH4, and H2O" + extends SorpLib.Media.IdealGasMixtures.Tester.Test_DryAir_N2_O2( + redeclare package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O); + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal gas mixture of +N<sub>2</sub>, O<sub>2</sub>, Ar, CO<sub>2</sub>, Ne, He, CH<sub>4</sub>, and +H<sub>2</sub>0. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O; diff --git a/SorpLib/Media/IdealGasMixtures/Tester/Test_DryAir_N2_O2_CO2_H2O.mo b/SorpLib/Media/IdealGasMixtures/Tester/Test_DryAir_N2_O2_CO2_H2O.mo new file mode 100644 index 0000000000000000000000000000000000000000..487886608272702a9100f3fe12b69b8b62ad2577 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Tester/Test_DryAir_N2_O2_CO2_H2O.mo @@ -0,0 +1,28 @@ +within SorpLib.Media.IdealGasMixtures.Tester; +model Test_DryAir_N2_O2_CO2_H2O + "Tester for dry air consisting of N2, O2, CO2, and H2O" + extends SorpLib.Media.IdealGasMixtures.Tester.Test_DryAir_N2_O2( + redeclare package Medium = + SorpLib.Media.IdealGasMixtures.DryAir_N2_O2_CO2_H2O); + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal gas mixture of +N<sub>2</sub>, O<sub>2</sub>, CO<sub>2</sub>, and H<sub>2</sub>O. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_DryAir_N2_O2_CO2_H2O; diff --git a/SorpLib/Media/IdealGasMixtures/Tester/package.mo b/SorpLib/Media/IdealGasMixtures/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f6f09e42aff2b70d2fbd9a67bde61f8bf91f3c3c --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.IdealGasMixtures; +package Tester "Package containing testers to test and varify models calculating fluid property data of ideal gas mixtures" + extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented fluid +property models of ideal gas mixtures. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Media/IdealGasMixtures/Tester/package.order b/SorpLib/Media/IdealGasMixtures/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..47a949b5219ac6da4c69b74022b099be9df67674 --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/Tester/package.order @@ -0,0 +1,3 @@ +Test_DryAir_N2_O2 +Test_DryAir_N2_O2_CO2_H2O +Test_DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O diff --git a/SorpLib/Media/IdealGasMixtures/package.mo b/SorpLib/Media/IdealGasMixtures/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..77c4363e29b973fbaf1641c3f94a1b7c87d0c74f --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/package.mo @@ -0,0 +1,23 @@ +within SorpLib.Media; +package IdealGasMixtures "Package containing medium models of ideal gas mixtures" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains models of ideal gas mixtures. These models are based +on the Modelica Standard Library but extended by new functions required in +SorpLib. Note that the reference temperature must be 0 K and the reference +enthalpy and entropy must be 0 J/kg and 0 J/(Kg.K). Otherwise, absolute values +caloric and entropic properties may not be correctly calculated. For details +of the mixture models, check the documentation of the package +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa\">Modelica.Media.IdealGases.Common.MixtureGasNasa</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end IdealGasMixtures; diff --git a/SorpLib/Media/IdealGasMixtures/package.order b/SorpLib/Media/IdealGasMixtures/package.order new file mode 100644 index 0000000000000000000000000000000000000000..9641cd9316ab76d7a7e4b06121b8e13a54b85aff --- /dev/null +++ b/SorpLib/Media/IdealGasMixtures/package.order @@ -0,0 +1,5 @@ +Interfaces +DryAir_N2_O2 +DryAir_N2_O2_CO2_H2O +DryAir_N2_O2_Ar_CO2_Ne_He_CH4_H2O +Tester diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryAirMassFractions_dX.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryAirMassFractions_dX.mo new file mode 100644 index 0000000000000000000000000000000000000000..86285653f7bdf72b0734ab501821373e01acba41 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryAirMassFractions_dX.mo @@ -0,0 +1,58 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function ddryAirMassFractions_dX + "Partial derivatives of 'dry air'-based mass fractions w.r.t. 'moist air'-based mass fractions" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions based on moist air mass" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real[nX, nX] dx_dX(each unit="kg.kg/(kg.kg)") + "Partial derivatives of mass fractions given per dry air mass w.r.t. mass + fractions given per moist air mass: Rows are dry air mass and columns are + moist air mass" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + dx_dX :=zeros(nX, nX) + "Partial derivatives of mass fractions given per dry air mass w.r.t. mass + fractions given per moist air mass: Most elements are zero."; + + dx_dX[nX, nX] := 1 / (X[nX] - 1)^2 + "Partial derivatives of mass fractions given per dry air mass w.r.t. mass + fractions given per moist air mass: Water w.r.t. water."; + + for ind in 1:nX-1 loop + dx_dX[ind, ind] := (1 + X[nX] / (1 - X[nX])) + "Partial derivatives of mass fractions given per dry air mass w.r.t. mass + fractions given per moist air mass: Diagonal."; + dx_dX[ind, nX] := X[ind] / (X[nX] - 1)^2 + "Partial derivatives of mass fractions given per dry air mass w.r.t. mass + fractions given per moist air mass: W.r.t. water."; + + end for; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivatives of mass fractions given per dry +air mass with respect to mass fractions given per moist air mass. +</p> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddryAirMassFractions_dX; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryMassFractionSaturation_dT_pX.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryMassFractionSaturation_dT_pX.mo new file mode 100644 index 0000000000000000000000000000000000000000..4d02e2398078fcacadc20f1660e51b70fc61003c --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryMassFractionSaturation_dT_pX.mo @@ -0,0 +1,70 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function ddryMassFractionSaturation_dT_pX + "Returns partial derivative of saturated wasser mass fraction per dry air mass w.r.t. temperature at constant pressure and mass fractions" + extends Modelica.Icons.Function; + + // + // Deifnition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Deifnition of outputs + // + output Real dx_sat_dT_pX(unit="kg/(kg.K)") + "Partial derivative of saturated wasser mass fraction per dry air mass + w.r.t. temperature at constant pressure and mass fractions" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_sat= + saturationPressureH2O_T(T_sat = state.T) + "Saturation pressure"; + Modelica.Media.Common.DerPressureByTemperature dp_sat_dT= + dsaturationPressureH2O_dT(T_sat = state.T) + "Partial derivative of saturation pressure w.r.t. temperature"; + +algorithm + dx_sat_dT_pX := MMX[nX] / (state.Y[1:nX-1]./sum(state.Y[1:nX-1]) * MMX[1:nX-1]) * + (p_sat / max((state.p - p_sat)^2, Modelica.Constants.small) + + 1 / max((state.p - p_sat), Modelica.Constants.small)) * dp_sat_dT + "Partial derivative of saturated wasser mass fraction per dry air mass + w.r.t. temperature at constant pressure and mass fractions"; + + // + // Assertations + // + if print_warnings then + assert(p_sat <= state.p, + "Saturation pressure (" + String(p_sat) + " Pa) is greater than total " + + "pressure (" + String(state.p) + " Pa). Thus, the calculation of the " + + "saturation mass fraction is not sound!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the saturation mass fraction +of the condensing component (i.e., water) per dry air with respect to temperature +at constant pressure and mass fractions as function of the state record. Note +that the saturation mass fraction can only be calculated if the partial pressure +of the condensing component is less than the pressure of the ideal gas-vapor +mixture. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddryMassFractionSaturation_dT_pX; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryMassFractionSaturation_dX_pT.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryMassFractionSaturation_dX_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..5e94b7da788509e54a39d105a949f3694bb3a5a4 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryMassFractionSaturation_dX_pT.mo @@ -0,0 +1,89 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function ddryMassFractionSaturation_dX_pT + "Returns partial derivatives of saturated wasser mass fraction per dry air mass w.r.t. mass fractions at constant pressure and temperature" + extends Modelica.Icons.Function; + + // + // Deifnition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Deifnition of outputs + // + output Real[nX] dx_sat_dX_pT(each unit="kg.kg/(kg.kg)") + "Partial derivatives of saturated wasser mass fraction per dry air mass + w.r.t. mass fractions given per moist air mass at constant pressure and + temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MolarMass Y_dryAir= + sum(state.Y[1:nX-1]) + "Sum of molar fractions of dry air components"; + Modelica.Units.SI.MolarMass MM_dryAir= + state.Y[1:nX-1] ./ Y_dryAir * MMX[1:nX-1] + "Molar mass of dry air components"; + Modelica.Units.SI.Pressure p_sat= + saturationPressureH2O_T(T_sat = state.T) + "Saturation pressure"; + + Real[nX-1] dMM_dryAir_dY= + MMX[1:nX-1] ./ Y_dryAir .- sum(MMX[1:nX-1] .* state.Y[1:nX-1] ./ Y_dryAir^2) + "Partial derivatives of molar mass of dry air components w.r.t. molar + fractions of dry air components"; + Real[nX, nX] dY_dX(each unit="mol.kg/(mol.kg)")= + dmassToMoleFractions_dX(X=state.X) + "Partial derivatives of mole fractions given per moist air w.r.t mass + fractions given per moist air mass: Rows are mole fractions and colums + are mass fractions"; + Real[nX] dMM_dryAir_dX= + {sum(dMM_dryAir_dY .* dY_dX[1:nX-1, ind]) for ind in 1:nX} + "Partial derivatives of molar mass of dry air components w.r.t. mass + fractions given per moist air mass"; + +algorithm + dx_sat_dX_pT := (-MMX[nX] / MM_dryAir^2 * + p_sat / max((state.p - p_sat), Modelica.Constants.small)) .* + dMM_dryAir_dX + "Partial derivatives of saturated wasser mass fraction per dry air mass + w.r.t. mass fractions given per moist air mass at constant pressure and + temperature"; + + // + // Assertations + // + if print_warnings then + assert(p_sat <= state.p, + "Saturation pressure (" + String(p_sat) + " Pa) is greater than total " + + "pressure (" + String(state.p) + " Pa). Thus, the calculation of the " + + "saturation mass fraction is not sound!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivatives of the saturation mass fraction +of the condensing component (i.e., water) per dry air with respect to mass fractions +given per moist air mass at constant pressure and temperature as function of the +state record. Note that the saturation mass fraction can only be calculated if +the partial pressure of the condensing component is less than the pressure of the +ideal gas-vapor mixture. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddryMassFractionSaturation_dX_pT; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryMassFractionSaturation_dp_TX.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryMassFractionSaturation_dp_TX.mo new file mode 100644 index 0000000000000000000000000000000000000000..9ff37a3a41fb9c1d042eeb9bc4393ee0e685256d --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddryMassFractionSaturation_dp_TX.mo @@ -0,0 +1,66 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function ddryMassFractionSaturation_dp_TX + "Returns partial derivative of saturated wasser mass fraction per dry air mass w.r.t. pressure at constant temperature and mass fractions" + extends Modelica.Icons.Function; + + // + // Deifnition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Deifnition of outputs + // + output Real dx_sat_dp_TX(unit="kg/(kg.Pa)") + "Partial derivative of saturated wasser mass fraction per dry air mass + w.r.t. pressure at constant temperature and mass fractions" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_sat= + saturationPressureH2O_T(T_sat = state.T) + "Saturation pressure"; + +algorithm + dx_sat_dp_TX := -MMX[nX] / (state.Y[1:nX-1]./sum(state.Y[1:nX-1]) * MMX[1:nX-1]) * + p_sat / max((state.p - p_sat)^2, Modelica.Constants.small) + "Partial derivative of saturated wasser mass fraction per dry air mass + w.r.t. pressure at constant temperature and mass fractions"; + + // + // Assertations + // + if print_warnings then + assert(p_sat <= state.p, + "Saturation pressure (" + String(p_sat) + " Pa) is greater than total " + + "pressure (" + String(state.p) + " Pa). Thus, the calculation of the " + + "saturation mass fraction is not sound!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the saturation mass fraction +of the condensing component (i.e., water) per dry air with respect to pressure +at constant temperature and mass fractions as function of the state record. Note +that the saturation mass fraction can only be calculated if the partial pressure +of the condensing component is less than the pressure of the ideal gas-vapor +mixture. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddryMassFractionSaturation_dp_TX; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddsaturationPressureH2O_dT_dT.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddsaturationPressureH2O_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..20b0fe075f961b7b0766b255440be57068de70df --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/ddsaturationPressureH2O_dT_dT.mo @@ -0,0 +1,177 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function ddsaturationPressureH2O_dT_dT + "Returns second-order partial derivative of saturatation pressure of water w.r.t. temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_sat + "Saturation temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerPressureByTemperatureTemperature ddp_sat_dT_dT + "Second-order partial derivative of saturation pressure w.r.t. temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real[2] coeff_s = {-13.9281690, 34.7078238} + "Coefficients of the gas-solid boundary"; + constant Real[6] coeff_l = {-7.85951783, 1.84408259, -11.7866497, + 22.6807411, -15.9618719, 1.80122502} + "Coefficients of the gas-liquid boundary"; + + constant Real[2] exp_s = {-1.5, -1.25} + "Exponents of the gas-solid boundary"; + constant Real[6] exp_l = {1, 1.5, 3, + 3.5, 4, 7.5} + "Exponents of the gas-liquid boundary"; + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_sat_s + "Saturation pressure of gas-solid boundary"; + Modelica.Media.Common.DerPressureByTemperature dp_sat_s_dT + "First-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + SorpLib.Units.DerPressureByTemperatureTemperature ddp_sat_s_dT_dT + "Second-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + + Modelica.Units.SI.Pressure p_sat_l + "Saturation pressure of gas-liquid boundary"; + Modelica.Media.Common.DerPressureByTemperature dp_sat_l_dT + "First-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + SorpLib.Units.DerPressureByTemperatureTemperature ddp_sat_l_dT_dT + "Second-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + + Real T_red_s = T_sat/T_water_trp + "Reduced temperature required for gas-solid boundary"; + Real T_red_fl = 1 - T_sat/T_water_crit + "Reduced temperature required for gas-liquid boundary"; + + Real lambda(unit="1") = SorpLib.Numerics.smoothTransition( + x=T_sat, transitionPoint=T_water_trp, transitionLength=1, noDiff=3) + "Transiation factor"; + Real dlambda_dT(unit="1/K") = SorpLib.Numerics.smoothTransition_der( + x=T_sat, transitionPoint=T_water_trp, transitionLength=1, noDiff=3, + x_der=1) + "First-order derivative of transiation factor w.r.t. temperature"; + Real ddlambda_dT_dT(unit="1/(K2)") = SorpLib.Numerics.smoothTransition_der2( + x=T_sat, transitionPoint=T_water_trp, transitionLength=1, noDiff=3, + x_der=1, x_der2=0) + "Second-order derivative of transiation factor w.r.t. temperature"; + + Real aux_s_1 + "Auxiliary variable 1 of saturation pressure of gas-solid boundary"; + Real aux_s_2 + "Auxiliary variable 2 of saturation pressure of gas-solid boundary"; + + Real aux_l_1 + "Auxiliary variable 1 of saturation pressure of gas-liquid boundary"; + Real aux_l_2 + "Auxiliary variable 2 of saturation pressure of gas-liquid boundary"; + +algorithm + // + // Calculate pressures + // + p_sat_s := p_water_trp * exp(coeff_s[1] - coeff_s[1] * T_red_s ^ exp_s[1] + + coeff_s[2] - coeff_s[2] * T_red_s ^ exp_s[2]) + "Saturation pressure of gas-solid boundary"; + p_sat_l := p_water_crit * exp(T_water_crit/T_sat * + (coeff_l[1] * T_red_fl ^ exp_l[1] + + coeff_l[2] * T_red_fl ^ exp_l[2] + + coeff_l[3] * T_red_fl ^ exp_l[3] + + coeff_l[4] * T_red_fl ^ exp_l[4] + + coeff_l[5] * T_red_fl ^ exp_l[5] + + coeff_l[6] * T_red_fl ^ exp_l[6])) + "Saturation pressure of gas-liquid boundary"; + + // + // Calculate auxiliary variables + // + aux_s_1 := -p_sat_s/T_sat + "Auxiliary variable 1 of saturation pressure of gas-solid boundary"; + aux_s_2 := (coeff_s[1] * exp_s[1] * T_red_s ^ exp_s[1] + + coeff_s[2] * exp_s[2] * T_red_s ^ exp_s[2]) + "Auxiliary variable 2 of saturation pressure of gas-solid boundary"; + + aux_l_1 := -p_sat_l/T_sat + "Auxiliary variable 1 of saturation pressure of gas-liquid boundary"; + aux_l_2 := log(p_sat_l/p_water_crit) + coeff_l[1] + + coeff_l[2] * exp_l[2] * T_red_fl^(exp_l[2]-1) + + coeff_l[3] * exp_l[3] * T_red_fl^(exp_l[3]-1) + + coeff_l[4] * exp_l[4] * T_red_fl^(exp_l[4]-1) + + coeff_l[5] * exp_l[5] * T_red_fl^(exp_l[5]-1) + + coeff_l[6] * exp_l[6] * T_red_fl^(exp_l[6]-1) + "Auxiliary variable 2 of saturation pressure of gas-liquid boundary"; + + // + // Calculate first-order partial derivatives of pressures w.r.t. temperature + // + dp_sat_s_dT := aux_s_1 * aux_s_2 + "First-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + dp_sat_l_dT := aux_l_1 * aux_l_2 + "First-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + + // + // Calculate second-order partial derivatives of pressures w.r.t. temperature + // + ddp_sat_s_dT_dT := (p_sat_s/T_sat^2 - dp_sat_s_dT/T_sat) * aux_s_2 + + aux_s_1/T_water_trp * (coeff_s[1] * exp_s[1]^2 * T_red_s ^ (exp_s[1]-1) + + coeff_s[2] * exp_s[2]^2 * T_red_s ^ (exp_s[2]-1)) + "Second-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + ddp_sat_l_dT_dT := (p_sat_l/T_sat^2 - dp_sat_l_dT/T_sat) * aux_l_2 + + aux_l_1 * (1/p_sat_l * dp_sat_l_dT + (-1/T_water_crit) * + (coeff_l[2] * exp_l[2] * (exp_l[2]-1) * T_red_fl^(exp_l[2]-2) + + coeff_l[3] * exp_l[3] * (exp_l[3]-1) * T_red_fl^(exp_l[3]-2) + + coeff_l[4] * exp_l[4] * (exp_l[4]-1) * T_red_fl^(exp_l[4]-2) + + coeff_l[5] * exp_l[5] * (exp_l[5]-1) * T_red_fl^(exp_l[5]-2) + + coeff_l[6] * exp_l[6] * (exp_l[6]-1) * T_red_fl^(exp_l[6]-2))) + "Second-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + + // + // Check for boundary + // + ddp_sat_dT_dT :=ddlambda_dT_dT*p_sat_s + + 2*dlambda_dT*dp_sat_s_dT + + lambda*ddp_sat_s_dT_dT + + (-ddlambda_dT_dT)*p_sat_l + + 2*(-dlambda_dT)*dp_sat_l_dT + + (1-lambda)*ddp_sat_l_dT_dT + "Second-order partial derivative of saturation pressure w.r.t. temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the second-order partial saturation pressure of water +with respect to temperature depending on the temperature. This functions covers +both, the solid-gas and the gas-liquid boundary. For details, please check the +function +<a href=\"Modelica://SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture.saturationPressureH2O_T\">SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture.saturationPressureH2O_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddsaturationPressureH2O_dT_dT; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dh_dT_pX.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dh_dT_pX.mo new file mode 100644 index 0000000000000000000000000000000000000000..daaf1378f2b445481589759c2aee6f8050e1ceac --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dh_dT_pX.mo @@ -0,0 +1,107 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dh_dT_pX + "Returns partial derivative of specific enthalpy w.r.t. temperature at constant pressure and mass fractions" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificHeatCapacity dh_dT_pX + "Partial derivative of specific enthalpy w.r.t. temperature at constant + pressure and mass fractions" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + + Real dx_sat_dT_pX(unit="kg/(kg.K)")= + ddryMassFractionSaturation_dT_pX(state=state) + "Partial derivative of saturated wasser mass fraction per dry air mass + w.r.t. temperature at constant pressure and mass fractions"; + +algorithm + // + // Calculate partial derivative per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + dh_dT_pX := x[1:nX-1] / sum(x[1:nX-1]) * + {Modelica.Media.IdealGases.Common.Functions.cp_T( + data=data[i], + T=state.T) for i in 1:nX-1} + "Partial derivative equals partial derivative of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + + elseif x[nX] <= x_sat then + dh_dT_pX := x[1:nX-1] / sum(x[1:nX-1]) * + {Modelica.Media.IdealGases.Common.Functions.cp_T( + data=data[i], + T=state.T) for i in 1:nX-1} + + x[nX] * specificHeatCapacityVapor(state=state) + "Partial derivative equals partial derivative of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + + elseif state.T > T_water_trp then + dh_dT_pX := x[1:nX-1] / sum(x[1:nX-1]) * + {Modelica.Media.IdealGases.Common.Functions.cp_T( + data=data[i], + T=state.T) for i in 1:nX-1} + + enthalpyOfCondensingGas(T=state.T) * dx_sat_dT_pX + + x_sat * specificHeatCapacityVapor(state=state) + + (-1) * enthalpyOfLiquid(p=state.p, T=state.T) * dx_sat_dT_pX + + (x[nX]-x_sat) * specificHeatCapacityLiquid(state=state) + "Partial derivative equals partial derivative of saturated dry air, water + vapor, liquid water: Calculated applying the law of ideal gas mixtures."; + + else + dh_dT_pX := x[1:nX-1] / sum(x[1:nX-1]) * + {Modelica.Media.IdealGases.Common.Functions.cp_T( + data=data[i], + T=state.T) for i in 1:nX-1} + + enthalpyOfCondensingGas(T=state.T) * dx_sat_dT_pX + + x_sat * specificHeatCapacityVapor(state=state) + + (-1) * enthalpyOfSolid(p=state.p, T=state.T) * dx_sat_dT_pX + + (x[nX]-x_sat) * specificHeatCapacitySolid(state=state) + "Partial derivative equals partial derivative of saturated dry air, water + vapor, solid water: Calculated applying the law of ideal gas mixtures."; + + end if; + + // + // Convert result + // + dh_dT_pX := dh_dT_pX / (1 + x[nX]) + "Partial derivative per moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy with +respect to temperature at constant pressure and mass fractions as function of +the state record. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_dT_pX; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dh_dX_pT.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dh_dX_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..221242d576519f3826a16984daab100d07f51a11 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dh_dX_pT.mo @@ -0,0 +1,154 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dh_dX_pT + "Returns partial derivative of specific enthalpy w.r.t. mass fractions at constant pressure and temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Real[nX] dh_dX_pT(each unit="J.kg/(kg2)") + "Partial derivative of specific enthalpy w.r.t. mass fractions at constant + pressure and temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + + Real[nX, nX] dx_dX(each unit="kg.kg/(kg.kg)")= + ddryAirMassFractions_dX(X=state.X) + "Partial derivatives of mass fractions given per dry air mass w.r.t. mass + fractions given per moist air mass: Rows are dry air mass and columns are + moist air mass"; + Real[nX] dx_sat_dX_pT(each unit="kg.kg/(kg.kg)")= + ddryMassFractionSaturation_dX_pT(state=state) + "Partial derivatives of saturated wasser mass fraction per dry air mass + w.r.t. mass fractions given per moist air mass at constant pressure and + temperature"; + Real[nX-1,nX-1] dx_dry_dx(each unit="kg.kg/(kg.kg)") + "Partial derivatives of mass fractions of dry air per dry air w.r.t. mass + fractions of dry air per dry air"; + + Modelica.Units.SI.SpecificEnthalpy[nX-1] h_dryAir + "Specific enthalpies of dry air components"; + Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy per dry air mass"; + +algorithm + // + // Calculate specific enthalpy and partial derivatives per dry air mass + // + for ind_x in 1:nX-1 loop + for ind_der in 1:nX-1 loop + if ind_x == ind_der then + dx_dry_dx[ind_x,ind_der] := 1/sum(x[1:nX-1]) - x[ind_x]/sum(x[1:nX-1])^2 + "Partial derivatives of mass fractions of dry air per dry air w.r.t. + mass fractions of dry air per dry air: Diagonal."; + + else + dx_dry_dx[ind_x,ind_der] :=-x[ind_x]/sum(x[1:nX-1])^2 + "Partial derivatives of mass fractions of dry air per dry air w.r.t. + mass fractions of dry air per dry air: Other elements than diagonal."; + + end if; + end for; + end for; + + h_dryAir :={Modelica.Media.IdealGases.Common.Functions.h_T( + data=data[i], + T=state.T, + exclEnthForm=true, + refChoice=Modelica.Media.Interfaces.Choices.ReferenceEnthalpy.UserDefined, + h_off=h_dryAir_off) for i in 1:nX-1} + "Specific enthalpies of dry air components"; + + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + h := enthalpyOfNonCondensingGas(T=state.T, X=x) + "Specific enthalpy equals specific enthalpy of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + dh_dX_pT := + {sum({sum(dx_dry_dx[1:nX-1,ind_x] .* h_dryAir) for ind_x in 1:nX-1} .* + dx_dX[1:nX-1,ind_X]) for ind_X in 1:nX} + "Partial derivative equals partial derivative of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + + elseif x[nX] <= x_sat then + h := enthalpyOfNonCondensingGas(T=state.T, X=x) + + x[nX] * enthalpyOfCondensingGas(T=state.T) + "Specific enthalpy equals specific enthalpy of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + dh_dX_pT := + {sum({sum(dx_dry_dx[1:nX-1,ind_x] .* h_dryAir) for ind_x in 1:nX-1} .* + dx_dX[1:nX-1,ind_X]) for ind_X in 1:nX} .+ + 1 .* enthalpyOfCondensingGas(T=state.T) .* dx_dX[nX,1:nX] + "Partial derivative equals partial derivative of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + + elseif state.T > T_water_trp then + h := enthalpyOfNonCondensingGas(T=state.T, X=x) + + x_sat * enthalpyOfCondensingGas(T=state.T) + + (x[nX]-x_sat) * enthalpyOfLiquid(p=state.p, T=state.T) + "Specific enthalpy equals specific enthalpy of saturated dry air, water + vapor, liquid water: Calculated applying the law of ideal gas mixtures."; + dh_dX_pT := + {sum({sum(dx_dry_dx[1:nX-1,ind_x] .* h_dryAir) for ind_x in 1:nX-1} .* + dx_dX[1:nX-1,ind_X]) for ind_X in 1:nX} .+ + 1 .* enthalpyOfCondensingGas(T=state.T) .* dx_sat_dX_pT .+ + (dx_dX[nX,1:nX] .- dx_sat_dX_pT) .* enthalpyOfLiquid(p=state.p, T=state.T) + "Partial derivative equals partial derivative of saturated dry air, water + vapor, liquid water: Calculated applying the law of ideal gas mixtures."; + + else + h := enthalpyOfNonCondensingGas(T=state.T, X=x) + + x_sat * enthalpyOfCondensingGas(T=state.T) + + (x[nX]-x_sat) * enthalpyOfSolid(p=state.p, T=state.T) + "Specific enthalpy equals specific enthalpy of saturated dry air, water + vapor, solid water: Calculated applying the law of ideal gas mixtures."; + dh_dX_pT := + {sum({sum(dx_dry_dx[1:nX-1,ind_x] .* h_dryAir) for ind_x in 1:nX-1} .* + dx_dX[1:nX-1,ind_X]) for ind_X in 1:nX} .+ + 1 .* enthalpyOfCondensingGas(T=state.T) .* dx_sat_dX_pT .+ + (dx_dX[nX,1:nX] .- dx_sat_dX_pT) .* enthalpyOfSolid(p=state.p, T=state.T) + "Partial derivative equals partial derivative of saturated dry air, water + vapor, solid water: Calculated applying the law of ideal gas mixtures."; + + end if; + + // + // Convert result + // + dh_dX_pT := dh_dX_pT ./ (1 + x[nX]) .- h ./ (x[nX] + 1) ^2 .* dx_dX[nX,1:nX] + "Partial derivatives per moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy with +respect to mass fractions at constant pressure and temperature as function of +the state record. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_dX_pT; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dh_dp_TX.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dh_dp_TX.mo new file mode 100644 index 0000000000000000000000000000000000000000..26e92f029e46db2627683a65a682b611d436ca2d --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dh_dp_TX.mo @@ -0,0 +1,90 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dh_dp_TX + "Returns partial derivative of specific enthalpy w.r.t. pressure at constant temperature and mass fractions" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerSpecificEnthalpyByPressure dh_dp_TX + "Partial derivative of specific enthalpy w.r.t. pressure at constant + temperature and mass fractions" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + + Real dx_sat_dp_TX(unit="kg/(kg.Pa)")= + ddryMassFractionSaturation_dp_TX(state=state) + "Partial derivative of saturated wasser mass fraction per dry air mass + w.r.t. pressure at constant temperature and mass fractions"; + +algorithm + // + // Calculate partial derivative per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + dh_dp_TX := 0 + "Partial derivative equals partial derivative of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + + elseif x[nX] <= x_sat then + dh_dp_TX := 0 + "Partial derivative equals partial derivative of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + + elseif state.T > T_water_trp then + dh_dp_TX := enthalpyOfCondensingGas(T=state.T) * dx_sat_dp_TX + + (-1) * enthalpyOfLiquid(p=state.p, T=state.T) * dx_sat_dp_TX + + (x[nX]-x_sat) * v_water_liq + "Partial derivative equals partial derivative of saturated dry air, water + vapor, liquid water: Calculated applying the law of ideal gas mixtures."; + + else + dh_dp_TX := enthalpyOfCondensingGas(T=state.T) * dx_sat_dp_TX + + (-1) * enthalpyOfSolid(p=state.p, T=state.T) * dx_sat_dp_TX + + (x[nX]-x_sat) * v_water_solid + "Partial derivative equals partial derivative of saturated dry air, water + vapor, solid water: Calculated applying the law of ideal gas mixtures."; + + end if; + + // + // Convert result + // + dh_dp_TX := dh_dp_TX / (1 + x[nX]) + "Partial derivative per moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy with +respect to pressure at constant temperature and mass fractions as function of +the state record. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dh_dp_TX; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dmassToMoleFractions_dX.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dmassToMoleFractions_dX.mo new file mode 100644 index 0000000000000000000000000000000000000000..63a2a93210eccc3cdf14e22b5f798b7fed37f69b --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dmassToMoleFractions_dX.mo @@ -0,0 +1,62 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dmassToMoleFractions_dX + "Returns partial derivatives of mole fractions w.r.t mass fractions" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Real[nX, nX] dY_dX(each unit="mol.kg/(mol.kg)") + "Partial derivatives of mole fractions w.r.t mass fractions: Rows are mole + fractions and colums are mass fractions" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MolarMass MM_mix = 1 / sum(X ./ MMX) + "Molar mass of mixture"; + +algorithm + for ind_row in 1:nX loop + for ind_col in 1:nX loop + if ind_row == ind_col then + dY_dX[ind_row, ind_col] := + MM_mix / MMX[ind_row] - X[ind_row] * MM_mix^2 / MMX[ind_row]^2 + "Partial derivatives of mole fraction i w.r.t mass fraction i"; + + else + dY_dX[ind_row, ind_col] := + -X[ind_row] * MM_mix^2 / (MMX[ind_row] * MMX[ind_col]) + "Partial derivatives of mole fraction i w.r.t mass fraction j"; + + end if; + end for; + end for; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivatives of mole fractions with respect +to mass fractions (i.e., rows = mole fractions; colums = mass fractions) as +function of mass fractions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dmassToMoleFractions_dX; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/drho_dX_ph.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/drho_dX_ph.mo new file mode 100644 index 0000000000000000000000000000000000000000..1e23953db1a2e2fffbb901c88cf81d6e2c2ebb70 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/drho_dX_ph.mo @@ -0,0 +1,44 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function drho_dX_ph + "Returns partial derivative of density w.r.t. mass fractions at constant pressure and specific enthalpy" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Real[nX] drho_dX_ph(each unit="kg.kg/(m3.kg)") + "Partial derivative of specific enthalpy w.r.t. mass fractions at constant + pressure and temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + +algorithm + drho_dX_ph := density_derX(state=state) .- density_derT_p(state=state) .* + dh_dX_pT(state=state) ./ dh_dT_pX(state=state) + "Partial derivative of specific enthalpy w.r.t. mass fractions at constant + pressure and temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the density with resepct to +mass fractions at constant pressure and specific enthalpy as function of the state +record. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end drho_dX_ph; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dryAirToMoistAirMassBasedProperties.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dryAirToMoistAirMassBasedProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..eb6e78b9ab20398f7b576e71391a286de7a18aa4 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dryAirToMoistAirMassBasedProperties.mo @@ -0,0 +1,44 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dryAirToMoistAirMassBasedProperties + "Converts 'dry air'-specific property to 'moist air'-specific property" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real z_dryAir + "Abitrary property given per dry air mass" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MassFraction x_water + "Mass fraction of water based on dry air mass" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real z_moistAir + "Abitrary property given per moist air mass" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + z_moistAir := z_dryAir / (1 + x_water) + "Abitrary property given per moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function converts an abitrary property given per dry air mass so that it is +given per moist air mass. +</p> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dryAirToMoistAirMassBasedProperties; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dryAirToMoistAirMassFractions.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dryAirToMoistAirMassFractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..2f0ba5434803dbb65a41f9bd68e9fac05b18bca5 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dryAirToMoistAirMassFractions.mo @@ -0,0 +1,44 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dryAirToMoistAirMassFractions + "Convert mass fractions from 'dry air'-based to 'moist air'-based" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MassFraction[nX] x + "Mass fractions based on dry air mass" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.MassFraction[nX] X + "Mass fractions based on moist air mass" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + X :=cat( + 1, + x[1:nX-1] ./ (1 + x[nX]), + {x[nX] / (1 + x[nX])}) + "Mass fractions based on moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function converts mass fractions given per dry air mass to mass fractions +given per moist air mass. +</p> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dryAirToMoistAirMassFractions; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dryMassFractionSaturation.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dryMassFractionSaturation.mo new file mode 100644 index 0000000000000000000000000000000000000000..c09ae65aaf0fedfd88f58a6f907dabdd266ee121 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dryMassFractionSaturation.mo @@ -0,0 +1,62 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dryMassFractionSaturation + "Returns saturation mass fraction of condensing component (i.e., water) (per dry air mass)" + extends Modelica.Icons.Function; + + // + // Deifnition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Deifnition of outputs + // + output Modelica.Units.SI.MassFraction x_sat + "Saturation mass fraction per dry air" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_sat= + saturationPressureH2O_T(T_sat = state.T) + "Saturation pressure"; + +algorithm + x_sat := MMX[nX] / (state.Y[1:nX-1]./sum(state.Y[1:nX-1]) * MMX[1:nX-1]) * + p_sat / max((state.p - p_sat), Modelica.Constants.small) + "Saturation mass fraction per dry air"; + + // + // Assertations + // + if print_warnings then + assert(p_sat <= state.p, + "Saturation pressure (" + String(p_sat) + " Pa) is greater than total " + + "pressure (" + String(state.p) + " Pa). Thus, the calculation of the " + + "saturation mass fraction is not sound!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the saturation mass fraction of the condensing component +(i.e., water) per dry air as function of the state record. Note that the saturation +mass fraction can only be calculated if the partial pressure of the condensing +component is less than the pressure of the ideal gas-vapor mixture. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dryMassFractionSaturation; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dsaturationPressureH2O_dT.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dsaturationPressureH2O_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..1f16381bdf5939ae6bbe94465d9c35e0339595bd --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dsaturationPressureH2O_dT.mo @@ -0,0 +1,127 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dsaturationPressureH2O_dT + "Returns partial derivative of saturatation pressure of water w.r.t. temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_sat + "Saturation temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Media.Common.DerPressureByTemperature dp_sat_dT + "First-order partial derivative of saturation pressure w.r.t. temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real[2] coeff_s = {-13.9281690, 34.7078238} + "Coefficients of the gas-solid boundary"; + constant Real[6] coeff_l = {-7.85951783, 1.84408259, -11.7866497, + 22.6807411, -15.9618719, 1.80122502} + "Coefficients of the gas-liquid boundary"; + + constant Real[2] exp_s = {-1.5, -1.25} + "Exponents of the gas-solid boundary"; + constant Real[6] exp_l = {1, 1.5, 3, + 3.5, 4, 7.5} + "Exponents of the gas-liquid boundary"; + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_sat_s + "Saturation pressure of gas-solid boundary"; + Modelica.Media.Common.DerPressureByTemperature dp_sat_s_dT + "First-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + + Modelica.Units.SI.Pressure p_sat_l + "Saturation pressure of gas-liquid boundary"; + Modelica.Media.Common.DerPressureByTemperature dp_sat_l_dT + "First-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + + Real T_red_s = T_sat/T_water_trp + "Reduced temperature required for gas-solid boundary"; + Real T_red_fl = 1 - T_sat/T_water_crit + "Reduced temperature required for gas-liquid boundary"; + + Real lambda(unit="1") = SorpLib.Numerics.smoothTransition( + x=T_sat, transitionPoint=T_water_trp, transitionLength=1, noDiff=3) + "Transiation factor"; + Real dlambda_dT(unit="1/K") = SorpLib.Numerics.smoothTransition_der( + x=T_sat, transitionPoint=T_water_trp, transitionLength=1, noDiff=3, + x_der=1) + "First-order derivative of transiation factor w.r.t. temperature"; + +algorithm + // + // Calculate pressures + // + p_sat_s := p_water_trp * exp(coeff_s[1] - coeff_s[1] * T_red_s ^ exp_s[1] + + coeff_s[2] - coeff_s[2] * T_red_s ^ exp_s[2]) + "Saturation pressure of gas-solid boundary"; + p_sat_l := p_water_crit * exp(T_water_crit/T_sat * + (coeff_l[1] * T_red_fl ^ exp_l[1] + + coeff_l[2] * T_red_fl ^ exp_l[2] + + coeff_l[3] * T_red_fl ^ exp_l[3] + + coeff_l[4] * T_red_fl ^ exp_l[4] + + coeff_l[5] * T_red_fl ^ exp_l[5] + + coeff_l[6] * T_red_fl ^ exp_l[6])) + "Saturation pressure of gas-liquid boundary"; + + // + // Calculate first-order partial derivatives of pressures w.r.t. temperature + // + dp_sat_s_dT := -p_sat_s/T_sat * + (coeff_s[1] * exp_s[1] * T_red_s ^ exp_s[1] + + coeff_s[2] * exp_s[2] * T_red_s ^ exp_s[2]) + "First-order partial derivative of saturation pressure of gas-solid boundary + w.r.t. temperature"; + dp_sat_l_dT := -p_sat_l/T_sat * ( + log(p_sat_l/p_water_crit) + + coeff_l[1] + + coeff_l[2] * exp_l[2] * T_red_fl^(exp_l[2]-1) + + coeff_l[3] * exp_l[3] * T_red_fl^(exp_l[3]-1) + + coeff_l[4] * exp_l[4] * T_red_fl^(exp_l[4]-1) + + coeff_l[5] * exp_l[5] * T_red_fl^(exp_l[5]-1) + + coeff_l[6] * exp_l[6] * T_red_fl^(exp_l[6]-1)) + "First-order partial derivative of saturation pressure of gas-liquid boundary + w.r.t. temperature"; + + // + // Check for boundary + // + dp_sat_dT :=dlambda_dT*p_sat_s + + lambda*dp_sat_s_dT + + (-dlambda_dT)*p_sat_l + + (1-lambda)*dp_sat_l_dT + "First-order partial derivative of saturation pressure w.r.t. temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the first-order partial saturation pressure of water +with respect to temperature depending on the temperature. This functions covers +both, the solid-gas and the gas-liquid boundary. For details, please check the +function +<a href=\"Modelica://SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture.saturationPressureH2O_T\">SorpLib.Media.IdealGasMixtures.Interfaces.PartialIdealGasMixture.saturationPressureH2O_T</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dsaturationPressureH2O_dT; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dv_dT_pX.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dv_dT_pX.mo new file mode 100644 index 0000000000000000000000000000000000000000..5823daec32c6c9044dd73929c3e46296d6c6c677 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dv_dT_pX.mo @@ -0,0 +1,92 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dv_dT_pX + "Returns partial derivative of specific volume w.r.t. temperature at constant pressure and mass fractions" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerSpecificVolumeByTemperature dv_dT_pX + "Partial derivative of specific volume w.r.t. temperature at constant pressure + and mass fractions" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + + Real dx_sat_dT_pX(unit="kg/(kg.K)")= + ddryMassFractionSaturation_dT_pX(state=state) + "Partial derivative of saturated wasser mass fraction per dry air mass + w.r.t. temperature at constant pressure and mass fractions"; + +algorithm + // + // Calculate partial derivative per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + dv_dT_pX := sum(x[1:nX-1] ./ MMX[1:nX-1] .* Modelica.Constants.R ./ state.p) + "Partial derivative equals partial derivative of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + + elseif x[nX] <= x_sat then + dv_dT_pX := sum(x ./ MMX .* Modelica.Constants.R ./ state.p) + "Partial derivative equals partial derivative of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + + elseif state.T > T_water_trp then + dv_dT_pX := sum(x[1:nX-1] .* Modelica.Constants.R ./ MMX[1:nX-1] ./ state.p) + + Modelica.Constants.R / MMX[nX] * state.T / state.p * dx_sat_dT_pX + + x_sat * Modelica.Constants.R / MMX[nX] / state.p + + (-1) * v_water_liq * dx_sat_dT_pX + "Partial derivative equals partial derivative of saturated dry air, water vapor, + and liquid water: Calculated applying the law of ideal gas mixtures."; + + else + dv_dT_pX := sum(x[1:nX-1] .* Modelica.Constants.R ./ MMX[1:nX-1] ./ state.p) + + Modelica.Constants.R / MMX[nX] * state.T / state.p * dx_sat_dT_pX + + x_sat * Modelica.Constants.R / MMX[nX] / state.p + + (-1) * v_water_solid * dx_sat_dT_pX + "Partial derivative equals partial derivative of saturated dry air, water vapor, + and solid water: Calculated applying the law of ideal gas mixtures."; + + end if; + + // + // Convert result + // + dv_dT_pX := dv_dT_pX / (1 + x[nX]) + "Partial derivative per moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific volume with +respect to temperature at constant pressure and mass fractions as function of +the state record. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dv_dT_pX; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dv_dX_pT.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dv_dX_pT.mo new file mode 100644 index 0000000000000000000000000000000000000000..2d9df044f24dc428322c87eb35123e3a7ea0c804 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dv_dX_pT.mo @@ -0,0 +1,125 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dv_dX_pT + "Returns partial derivatives of specific volume w.r.t. mass fractions at constant pressure and temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Real[nX] dv_dX_pT(each unit="m3/kg") + "Partial derivatives of specific volume w.r.t. mass fractions at constant + pressure and temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + + Real[nX, nX] dx_dX(each unit="kg.kg/(kg.kg)")= + ddryAirMassFractions_dX(X=state.X) + "Partial derivatives of mass fractions given per dry air mass w.r.t. mass + fractions given per moist air mass: Rows are dry air mass and columns are + moist air mass"; + Real[nX] dx_sat_dX_pT(each unit="kg.kg/(kg.kg)")= + ddryMassFractionSaturation_dX_pT(state=state) + "Partial derivatives of saturated wasser mass fraction per dry air mass + w.r.t. mass fractions given per moist air mass at constant pressure and + temperature"; + + Modelica.Units.SI.SpecificVolume v + "Specific volume per dry air mass"; + +algorithm + // + // Calculate specific volume and partial derivatives per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + v := sum(x[1:nX-1] ./ MMX[1:nX-1] .* Modelica.Constants.R .* + state.T ./ state.p) + "Specific volume equals specific volume of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + dv_dX_pT := {sum(1 ./ MMX[1:nX-1] .* Modelica.Constants.R .* + state.T ./ state.p .* dx_dX[1:nX-1,ind]) for ind in 1:nX} + "Partial derivatives equal partial derivatives of unsaturated dry air + without water: Calculated applying the law of ideal gas mixtures."; + + elseif x[nX] <= x_sat then + v := sum(x ./ MMX .* Modelica.Constants.R .* + state.T ./ state.p) + "Specific volume equals specific volume of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + dv_dX_pT := {sum(1 ./ MMX .* Modelica.Constants.R .* + state.T ./ state.p .* dx_dX[1:nX,ind]) for ind in 1:nX} + "Partial derivatives equal partial derivatives of unsaturated dry air and + water vapor: Calculated applying the law of ideal gas mixtures."; + + elseif state.T > T_water_trp then + v := sum(x[1:nX-1] ./ MMX[1:nX-1] .* Modelica.Constants.R .* + state.T ./ state.p) + + x_sat * Modelica.Constants.R / MMX[nX] * state.T / state.p + + (x[nX] - x_sat) * v_water_liq + "Specific volume equals specific volume of saturated dry air, water vapor, + and liquid water: Calculated applying the law of ideal gas mixtures."; + dv_dX_pT := {sum(1 ./ MMX[1:nX-1] .* Modelica.Constants.R .* + state.T ./ state.p .* dx_dX[1:nX-1,ind]) for ind in 1:nX} .+ + 1 .* Modelica.Constants.R ./ MMX[nX] .* state.T ./ state.p .* + dx_sat_dX_pT .+ + (dx_dX[nX, 1:nX] - dx_sat_dX_pT) * v_water_liq + "Partial derivatives equal partial derivatives of saturated dry air, water + vapor, and liquid water: Calculated applying the law of ideal gas mixtures."; + + else + v := sum(x[1:nX-1] ./ MMX[1:nX-1] .* Modelica.Constants.R .* + state.T ./ state.p) + + x_sat * Modelica.Constants.R / MMX[nX] * state.T / state.p + + (x[nX] - x_sat) * v_water_solid + "Specific volume equals specific volume of saturated dry air, water vapor, + and solid water: Calculated applying the law of ideal gas mixtures."; + dv_dX_pT := {sum(1 ./ MMX[1:nX-1] .* Modelica.Constants.R .* + state.T ./ state.p .* dx_dX[1:nX-1,ind]) for ind in 1:nX} .+ + 1 .* Modelica.Constants.R ./ MMX[nX] .* state.T ./ state.p .* + dx_sat_dX_pT .+ + (dx_dX[nX, 1:nX] - dx_sat_dX_pT) * v_water_solid + "Partial derivatives equal partial derivatives of saturated dry air, water + vapor, and solid water: Calculated applying the law of ideal gas mixtures."; + + end if; + + // + // Convert result + // + dv_dX_pT := dv_dX_pT ./ (1 + x[nX]) .- v ./ (x[nX] + 1) ^2 .* dx_dX[nX,1:nX] + "Partial derivatives per moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivatives of the specific volume with +respect to mass fractions given per moist air mass at constant pressure and +temperature as function of the state record. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dv_dX_pT; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dv_dp_TX.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dv_dp_TX.mo new file mode 100644 index 0000000000000000000000000000000000000000..8bb7fe3194508ecd988a04ebed680d7270c781e1 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/dv_dp_TX.mo @@ -0,0 +1,95 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function dv_dp_TX + "Returns partial derivative of specific volume w.r.t. pressure at constant temperature and mass fractions" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerSpecificVolumeByPressure dv_dp_TX + "Partial derivative of specific volume w.r.t. pressure at constant temperature + and mass fractions" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + + Real dx_sat_dp_TX(unit="kg/(kg.Pa)")= + ddryMassFractionSaturation_dp_TX(state=state) + "Partial derivative of saturated wasser mass fraction per dry air mass + w.r.t. pressure at constant temperature and mass fractions"; + +algorithm + // + // Calculate partial derivative per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + dv_dp_TX := sum(-x[1:nX-1] ./ MMX[1:nX-1] .* + Modelica.Constants.R .* state.T ./ state.p^2) + "Partial derivative equals partial derivative of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + + elseif x[nX] <= x_sat then + dv_dp_TX := sum(-x ./ MMX .* Modelica.Constants.R .* state.T ./ state.p^2) + "Partial derivative equals partial derivative of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + + elseif state.T > T_water_trp then + dv_dp_TX := sum(-x[1:nX-1] .* Modelica.Constants.R ./ MMX[1:nX-1] .* + state.T ./ state.p^2) + + Modelica.Constants.R / MMX[nX] * state.T / state.p * dx_sat_dp_TX + + (-1) * x_sat * Modelica.Constants.R / MMX[nX] * state.T / state.p^2 + + (-1) * v_water_liq * dx_sat_dp_TX + "Partial derivative equals partial derivative of saturated dry air, water vapor, + and liquid water: Calculated applying the law of ideal gas mixtures."; + + else + dv_dp_TX := sum(-x[1:nX-1] .* Modelica.Constants.R ./ MMX[1:nX-1] .* + state.T ./ state.p^2) + + Modelica.Constants.R / MMX[nX] * state.T / state.p * dx_sat_dp_TX + + (-1) * x_sat * Modelica.Constants.R / MMX[nX] * state.T / state.p^2 + + (-1) * v_water_solid * dx_sat_dp_TX + "Partial derivative equals partial derivative of saturated dry air, water vapor, + and solid water: Calculated applying the law of ideal gas mixtures."; + + end if; + + // + // Convert result + // + dv_dp_TX := dv_dp_TX / (1 + x[nX]) + "Partial derivative per moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific volume with +respect to pressure at constant temperature and mass fractions as function of +the state record. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dv_dp_TX; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfCondensingComponent.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfCondensingComponent.mo new file mode 100644 index 0000000000000000000000000000000000000000..3be6c55f43a1f0c8a9cdf80bd48ef61bf8569791 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfCondensingComponent.mo @@ -0,0 +1,81 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function enthalpyOfCondensingComponent + "Returns specific enthalpy of condensing component (i.e., water) (per moist air mass)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy of condensing component (i.e., water) per moist air mass" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + +algorithm + // + // Calculate specific enthalpy per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + h := 0 + "Specific enthalpy equals zero because water is not within the mixture"; + + elseif x[nX] <= x_sat then + h := x[nX] * enthalpyOfCondensingGas(T=state.T) + "Specific enthalpy equals specific enthalpy of water vapor"; + + elseif state.T > T_water_trp then + h := x_sat * enthalpyOfCondensingGas(T=state.T) + + (x[nX]-x_sat) * enthalpyOfLiquid(p=state.p, T=state.T) + "Specific enthalpy equals specific enthalpy of water vapor and liquid + water"; + + else + h := x_sat * enthalpyOfCondensingGas(T=state.T) + + (x[nX]-x_sat) * enthalpyOfSolid(p=state.p, T=state.T) + "Specific enthalpy equals specific enthalpy of water vapor and solid + water"; + + end if; + + // + // Convert specific enthalpy per dry air mass + // + h := h / (1 + x[nX]) + "Specific enthalpy of condensing component (i.e., water) per moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy of the condensing component (i.e., +water) per moist air mass according to the models of an ideal solid, ideal liquid, +and ideal gas. +</p> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end enthalpyOfCondensingComponent; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfLiquidIce.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfLiquidIce.mo new file mode 100644 index 0000000000000000000000000000000000000000..7758f3e5ab4856c6d175e7651a145e3ff5a1444e --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfLiquidIce.mo @@ -0,0 +1,79 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function enthalpyOfLiquidIce + "Returns specific enthalpy of condensing component at solid or liquid state (i.e., ice or liquid water) (per moist air mass)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy of condensing component at solid or liquid state (i.e., + ice or liquid water) per moist air mass" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + +algorithm + // + // Calculate specific enthalpy per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + h := 0 + "Specific enthalpy equals zero because water is not within the mixture"; + + elseif x[nX] <= x_sat then + h := 0 + "Specific enthalpy equals zero because air is not saturated"; + + elseif state.T > T_water_trp then + h := (x[nX]-x_sat) * enthalpyOfLiquid(p=state.p, T=state.T) + "Specific enthalpy equals specific enthalpy of liquid water"; + + else + h := (x[nX]-x_sat) * enthalpyOfSolid(p=state.p, T=state.T) + "Specific enthalpy equals specific enthalpy of solid water"; + + end if; + + // + // Convert specific enthalpy per dry air mass + // + h := h / (1 + x[nX]) + "Specific enthalpy of condensing component at solid or liquid state per moist + air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy of the condensing component at the +solid or liquid state (i.e., ice or liquid water) per moist air mass according to +the models of an ideal solid or liquid. +</p> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end enthalpyOfLiquidIce; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfNonCondensingComponents.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfNonCondensingComponents.mo new file mode 100644 index 0000000000000000000000000000000000000000..dda6d512ea944f7299e187777d55648ae864d315 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfNonCondensingComponents.mo @@ -0,0 +1,55 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function enthalpyOfNonCondensingComponents + "Returns specific enthalpy of non-condensing components (i.e., dry air) (per moist air mass)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy of non-condensing components (i.e., dry air)" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + +algorithm + h := state.X[1:nX-1] * {Modelica.Media.IdealGases.Common.Functions.h_T( + data=data[i], + T=state.T, + exclEnthForm=true, + refChoice=Modelica.Media.Interfaces.Choices.ReferenceEnthalpy.UserDefined, + h_off=h_dryAir_off) for i in 1:nX-1} + "Specific enthalpy of dry air"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy of the non-condensing components +(i.e., dry air) per moist air mass according to the model of an ideal gas mixture +as function of temperature and mass fractions. The specific enthalpy is calculated +using NASA Glenn Coefficients. For more details, check the function +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.h_TX\">Modelica.Media.IdealGases.Common.MixtureGasNasa.h_TX</a>.</p> + +<h4>References</h4> +<ul> + <li> + McBride, B.J. and Zehe, M.J. and Gordon, S. (2002). NASA Glenn Coefficients for Calculating Thermodynamic Properties of Individual Species, Technical report, NASA/TP—2002-211556. URL: https://ntrs.nasa.gov/citations/20020085330. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end enthalpyOfNonCondensingComponents; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfSolid.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfSolid.mo new file mode 100644 index 0000000000000000000000000000000000000000..61be1c983a812bd3b22dea3381b867a972f1a9d5 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfSolid.mo @@ -0,0 +1,95 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function enthalpyOfSolid + "Returns specific enthalpy of solid water (per water mass)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy of solid water" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real[7] coefficients= + {2.19406894387930e-11, -2.21186473219202e-8, 8.60754642146296e-6, + -1.57223901063024e-3, 1.24518779128263e-1, 5.27605328970081, + 1.18325880591863e+1} + "Coefficients of polynomical function"; + constant Real[7] exponents= + {6, 5, 4, 3, 2, 1, 0} + "Exponents of polynomical function"; + +algorithm + h := h_water_ref - dh_fus_water_ref + v_water_solid * (p - p_water_ref) + + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T, + T_ref=T_water_trp, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) - + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T_water_ref, + T_ref=T_water_trp, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Specific enthalpy of liquid water"; + + // + // Assertations + // + if print_warnings then + assert(50 <= T and T <= T_water_trp+1, + "Temperature (" + String(T) + " K) is not between 50 and 274.16 K. " + + "Calculation of specific enthalpy of ice may not be valid!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy of the condensing component's +(i.e., water) solid phase per solid mass according to the model of an ideal solid +as function of pressure and temperature. The specific heat capacity is calculated +as a polynomial fit to specific heat capacity data calculated with the reference +equation of state for ice. The data was calculated for fixed pressure +(p_water_trp = 611.657 Pa) and temperature varying from 50 K to 274.16 K. Note +that this function does not consider the actual water mass fraction. To calculate +the specific enthalpy of the solid water that is actually present, use the function +<a href=\"Modelica://SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture.enthalpyOfLiquidIce\">SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture.enthalpyOfLiquidIce</a>. +</p> + +<h4>References</h4> +<ul> + <li> + The International Association for the Properties of Water and Steam (2009). Revised Release on the Equation of State 2006 for H2O Ice Ih. URL: https://iapws.org/relguide/Ice-2009.html. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end enthalpyOfSolid; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfVapor.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfVapor.mo new file mode 100644 index 0000000000000000000000000000000000000000..e0071e54c1e1a473ccd16cbd7195d147255e24bf --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/enthalpyOfVapor.mo @@ -0,0 +1,75 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function enthalpyOfVapor + "Returns specific enthalpy of condensing component at gas state (i.e., water vapor) (per moist air mass)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy of condensing component at gas state (i.e., water vapor) + per moist air mass" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + +algorithm + // + // Calculate specific enthalpy per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + h := 0 + "Specific enthalpy equals zero because water is not within the mixture"; + + elseif x[nX] <= x_sat then + h := x[nX] * enthalpyOfCondensingGas(T=state.T) + "Specific enthalpy equals specific enthalpy of water vapor (unsaturated)"; + + else + h := x_sat * enthalpyOfCondensingGas(T=state.T) + "Specific enthalpy equals specific enthalpy of water vapor (saturated)"; + + end if; + + // + // Convert specific enthalpy per dry air mass + // + h := h / (1 + x[nX]) + "Specific enthalpy of condensing component at gas state (i.e., water vapor) + per moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy of the condensing component at the +gas state (i.e., vaporous water) per moist air mass according to the model of an +ideal gas. +</p> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end enthalpyOfVapor; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfCondensingGas.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfCondensingGas.mo new file mode 100644 index 0000000000000000000000000000000000000000..98ab1b2744a047805d5ed17036ac04eaac703ccb --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfCondensingGas.mo @@ -0,0 +1,95 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function entropyOfCondensingGas + "Returns specific entropy of vaporous water (per water mass)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEntropy s + "Specific entropy of vaporous water" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real[10] coefficients= + {7.03241022996521e-23, -4.12454440465976e-19, 1.05640534898709e-15, + -1.54797437245421e-12, 1.42577474111776e-9, -8.51385633913246e-7, + 3.26064390458737e-4, -7.52464997116974e-2, 9.42339113729594, + 1.36103845934352e+3} + "Coefficients of polynomical function"; + constant Real[10] exponents= + {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} .- 1 + "Exponents of polynomical function"; + +algorithm + s := s_water_ref + ds_vap_water_ref + + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T, + T_ref=T_water_crit, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) - + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T_water_ref, + T_ref=T_water_crit, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) - + Modelica.Constants.R / MMX[nX] * Modelica.Math.log(max(p, + Modelica.Constants.eps) / reference_p) + "Specific entropy of vaporous water"; + + // + // Assertations + // + if print_warnings then + assert(200 <= T and T <= 1000, + "Temperature (" + String(T) + " K) is not between 200 and 1000 K. " + + "Calculation of specific entropy of vapor may not be valid!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific entropy of the condensing component's +(i.e., water) vapor phase per mass of water according to the model of an ideal +gas as function of pressue and temperature. The specific heat capacity is calculated +as a polynomial fit to specific heat capacity data calculated according to the NASA +Glenn Coefficients. The data was calculated for a temperature varying from 200 K +to 1000 K. Note that this function does not consider the actual water mass fraction. +</p> + +<h4>References</h4> +<ul> + <li> + McBride, B.J. and Zehe, M.J. and Gordon, S. (2002). NASA Glenn Coefficients for Calculating Thermodynamic Properties of Individual Species, Technical report, NASA/TP—2002-211556. URL: https://ntrs.nasa.gov/citations/20020085330. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end entropyOfCondensingGas; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfLiquid.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfLiquid.mo new file mode 100644 index 0000000000000000000000000000000000000000..92620116bfc074c043eca76619b8b0c2d6fed4dd --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfLiquid.mo @@ -0,0 +1,91 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function entropyOfLiquid + "Returns specific entropy of liquid water (per water mass)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEntropy s + "Specific entropy of liquid water" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real[10] coefficients= + {4.66348457415926e-19, -1.16579701193758e-15, 9.49925152355854e-13, + 5.81553479401465e-11, -6.55387915784314e-7, 5.30868446475702e-4, + -2.18234813641286e-1, 5.13043718148301e1, -6.58121774333134e3, + 3.63215816205503e5} + "Coefficients of polynomical function"; + constant Real[10] exponents= + {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} .- 1 + "Exponents of polynomical function"; + +algorithm + s := s_water_ref + + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T, + T_ref=T_water_crit, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) - + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T_water_ref, + T_ref=T_water_crit, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Specific entropy of liquid water"; + + // + // Assertations + // + if print_warnings then + assert(T_water_trp-1 <= T and T <= 573.15, + "Temperature (" + String(T) + " K) is not between 272.16 and 573.15 K. " + + "Calculation of specific entropy of liquid may not be valid!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific entropy of the condensing component's +(i.e., water) liquid phase per water mass according to the model of an ideal +liquid as function of pressure and temperature. The specific heat capacity is +calculated as a polynomial fit to specific heat capacity data calculated at +saturated liquid state with the reference equation of state for water. The data +was calculated for temperature varying from 273.16 K to 573.15 K. Note that this +function does not consider the actual water mass fraction. +</p> + +<h4>References</h4> +<ul> + <li> + The International Association for the Properties of Water and Steam (2009). Revised Release on the Equation of State 2006 for H2O Ice Ih. URL: https://iapws.org/relguide/Ice-2009.html. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end entropyOfLiquid; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfNonCondensingGas.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfNonCondensingGas.mo new file mode 100644 index 0000000000000000000000000000000000000000..e68bae306107f14622ccbbf2c1927cffc891ccfc --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfNonCondensingGas.mo @@ -0,0 +1,64 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function entropyOfNonCondensingGas + "Returns specific entropy of non-condensing components (i.e., dry air) (per dry air mass)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Pressure[nX] p_i + "Partial pressures" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEntropy s + "Specific entropy of non-condensing components (i.e., dry air)" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + +algorithm + s := X[1:nX-1] / sum(X[1:nX-1]) * {s_dryAir_off + + Modelica.Media.IdealGases.Common.Functions.s0_T(data=data[i], T=T) - + Modelica.Constants.R / MMX[i] * Modelica.Math.log(max(p_i[i], + Modelica.Constants.eps) / reference_p) for i in 1:nX-1} + "Specific entropy of non-condensing components (i.e., dry air)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific entropy of the non-condensing components +(i.e., dry air) per moist air mass according to the model of an ideal gas mixture +as function of partial pressures, temperature, and mass fractions. The specific +entropy is calculated using NASA Glenn Coefficients. For more details, check the +functions +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.specificEntropy\">Modelica.Media.IdealGases.Common.MixtureGasNasa.specificEntropy</a>, +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.specificEntropyOfpTX\">Modelica.Media.IdealGases.Common.MixtureGasNasa.specificEntropyOfpTX</a>, +and +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.s_TX\">Modelica.Media.IdealGases.Common.MixtureGasNasa.s_TX</a>. +</p> + +<h4>References</h4> +<ul> + <li> + McBride, B.J. and Zehe, M.J. and Gordon, S. (2002). NASA Glenn Coefficients for Calculating Thermodynamic Properties of Individual Species, Technical report, NASA/TP—2002-211556. URL: https://ntrs.nasa.gov/citations/20020085330. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end entropyOfNonCondensingGas; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfSolid.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfSolid.mo new file mode 100644 index 0000000000000000000000000000000000000000..971388a2538195a744312af22b39a3e2fc5d8f6b --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/entropyOfSolid.mo @@ -0,0 +1,90 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function entropyOfSolid + "Returns specific entropy of solid water (per water mass)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEntropy s + "Specific entropy of solid water" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real[7] coefficients= + {2.19406894387930e-11, -2.21186473219202e-8, 8.60754642146296e-6, + -1.57223901063024e-3, 1.24518779128263e-1, 5.27605328970081, + 1.18325880591863e+1} + "Coefficients of polynomical function"; + constant Real[7] exponents= + {6, 5, 4, 3, 2, 1, 0} .- 1 + "Exponents of polynomical function"; + +algorithm + s := s_water_ref - ds_fus_water_ref + + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T, + T_ref=T_water_crit, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) - + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T_water_ref, + T_ref=T_water_crit, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Specific entropy of solid water"; + + // + // Assertations + // + if print_warnings then + assert(50 <= T and T <= T_water_trp+1, + "Temperature (" + String(T) + " K) is not between 50 and 274.16 K. " + + "Calculation of specific entropy of ice may not be valid!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific entropy of the condensing component's +(i.e., water) solid phase per solid mass according to the model of an ideal solid +as function of temperature. The specific heat capacity is calculated as a +polynomial fit to specific heat capacity data calculated with the reference +equation of state for ice. The data was calculated for fixed pressure +(p_water_trp = 611.657 Pa) and temperature varying from 50 K to 274.16 K. Note +that this function does not consider the actual water mass fraction. +</p> + +<h4>References</h4> +<ul> + <li> + The International Association for the Properties of Water and Steam (2009). Revised Release on the Equation of State 2006 for H2O Ice Ih. URL: https://iapws.org/relguide/Ice-2009.html. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end entropyOfSolid; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/massFractionSaturation.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/massFractionSaturation.mo new file mode 100644 index 0000000000000000000000000000000000000000..04ef20f7cb53d25c2068e7bfbda552bc45bd9c1f --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/massFractionSaturation.mo @@ -0,0 +1,49 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function massFractionSaturation + "Return saturation mass fraction of condensing component (i.e., water) (per saturated moist air mass)" + extends Modelica.Icons.Function; + + // + // Deifnition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Deifnition of outputs + // + output Modelica.Units.SI.MassFraction X_sat + "Saturation mass fraction per saturated moist air" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + MassFraction x_sat = dryMassFractionSaturation(state=state) + "Saturation mass fraction per dry air"; + +algorithm + X_sat :=x_sat / (1 + x_sat) + "Saturation mass fraction per saturated moist air"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the saturation mass fraction of the condensing component +(i.e., water) per saturated moist air as function of the state record. Note that +the saturation mass fraction can only be calculated if the partial pressure of the +condensing component is less than the pressure of the ideal gas-vapor mixture. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end massFractionSaturation; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/massFractions_pTxDryPhi.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/massFractions_pTxDryPhi.mo new file mode 100644 index 0000000000000000000000000000000000000000..ffd41b3363f674e80ee306bcfe0b09b598005692 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/massFractions_pTxDryPhi.mo @@ -0,0 +1,89 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function massFractions_pTxDryPhi + "Returns mass fractions per moist air mass based on pressure, temperature, compoition of dry air, and relative humidity" + extends Modelica.Icons.Function; + + // + // Deifnition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MassFraction[nX-1] x + "Mass fractions of dry air components per dry air mass" + annotation (Dialog(tab="General",group="Inputs")); + input Real phi(min=0, max=1) + "Relative humidity" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Deifnition of outputs + // + output Modelica.Units.SI.MassFraction[nX] X + "Mass fractions per moist air mass" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MoleFraction[nX-1] y= + massToMoleFractions(X=x, MMX=MMX) + "Mole fractions of dry air components per dry air amount of substances"; + Modelica.Units.SI.Pressure p_sat= + saturationPressureH2O_T(T_sat = T) + "Saturation pressure"; + + Modelica.Units.SI.MassFraction x_water + "Water mass fraction per dry air mass"; + +algorithm + x_water := MMX[nX] / (y * MMX[1:nX-1]) * + phi*p_sat / max((p - phi*p_sat), Modelica.Constants.small) + "Water mass fraction per dry air mass"; + + X :=cat( + 1, + x ./ (1 + x_water), + {x_water} ./ (1 + x_water)) + "Mass fractions per moist air mass"; + + // + // Assertations + // + if print_warnings then + assert(0 <= phi and phi <= 1, + "Relative humidity (" + String(phi) + " ) is not between 0 and 1. Thus, the" + + "calculation of the water mass fraction is not sound!", + level = AssertionLevel.warning); + + assert(phi*p_sat <= p, + "Partial pressure of water (" + String(phi*p_sat) + " Pa ) is greater " + + "than the total pressure (" + String(p) + " Pa ) . Thus, the calculation " + + " of the water mass fraction is not sound!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the mass fractions per moist air mass based on the pressure, +temperature, mass fractions of the dry air components per dry air mass, and relative +humidity. Note that this function only returns reasonable results for unsaturated +air. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end massFractions_pTxDryPhi; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/moistAirToDryAirMassBasedProperties.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/moistAirToDryAirMassBasedProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..fe45fb8fa365bc88562fa1618f4822d27364b1c8 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/moistAirToDryAirMassBasedProperties.mo @@ -0,0 +1,44 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function moistAirToDryAirMassBasedProperties + "Converts 'moist air'-specific property to 'dry air'-specific property" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real z_moistAir + "Abitrary property given per moist air mass" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.MassFraction X_water + "Mass fraction of water based on moist air mass" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real z_dryAir + "Abitrary property given per dry air mass" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + z_dryAir := z_moistAir * (1 + X_water / (1 - X_water)) + "Abitrary property given per dry air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function converts an abitrary property given per moist air mass so that it is +given per dry air mass. +</p> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end moistAirToDryAirMassBasedProperties; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/moistAirToDryAirMassFractions.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/moistAirToDryAirMassFractions.mo new file mode 100644 index 0000000000000000000000000000000000000000..e46843b6ba9b211633fe1cdc9ed531fe0491a40a --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/moistAirToDryAirMassFractions.mo @@ -0,0 +1,44 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function moistAirToDryAirMassFractions + "Convert mass fractions from 'moist air'-based to 'dry air'-based" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions based on moist air mass" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.MassFraction[nX] x + "Mass fractions based on dry air mass" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + x :=cat( + 1, + X[1:nX-1] .* (1 + X[nX] / (1 - X[nX])), + {X[nX] / (1 - X[nX])}) + "Mass fractions based on dry air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function converts mass fractions given per moist air mass to mass fractions +given per dry air mass. +</p> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end moistAirToDryAirMassFractions; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/package.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..3fad5aa7674c60a8e8662ad05f234be77df7348d --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/package.mo @@ -0,0 +1,1583 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces; +partial package PartialIdealGasWaterVaporMixture "Medium model of an ideal gas-vapor mixture with water as condensing component based on NASA source " + extends Modelica.Media.Interfaces.PartialCondensingGases( + redeclare final record FluidConstants = + Modelica.Media.Interfaces.Types.IdealGas.FluidConstants, + final ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.pTX, + final singleState=false, + final reducedX=true, + final fixedX=false, + final reference_p=1e5, + final reference_T(min=0)=0); + + // + // Definition of constants + // + constant Modelica.Media.IdealGases.Common.DataRecord[:] data + "Data records of ideal gas-vapor components. Note that water is the vapor + substance and must be the last data record."; + constant Modelica.Units.SI.MolarMass[nX] MMX=data[:].MM + "Molar masses of components"; + + constant Modelica.Units.SI.Pressure p_water_trp = 611.657 + "Triple point pressure of water"; + constant Modelica.Units.SI.Pressure p_water_crit = 22.064e6 + "Critical pressure of water"; + + constant Modelica.Units.SI.Temperature T_water_trp = 273.16 + "Triple point temperature of water"; + constant Modelica.Units.SI.Temperature T_water_crit = 647.096 + "Critical temperature of water"; + + constant Modelica.Units.SI.Density d_water_crit = 322 + "Critical density of water"; + + constant Modelica.Units.SI.SpecificVolume v_water_liq = 1/1000 + "Specific volume of condensing component (i.e., water) at liquid phase + assuming an ideal liquid"; + constant Modelica.Units.SI.SpecificVolume v_water_solid = 1/918 + "Specific volume of condensing component (i.e., water) at solid phase + assuming an ideal solid"; + + constant Modelica.Units.SI.Pressure p_water_ref = p_water_trp + "Reference pressure of water"; + constant Modelica.Units.SI.Temperature T_water_ref = T_water_trp + "Reference temperature of water"; + constant Modelica.Units.SI.SpecificEnthalpy h_water_ref = 0 + "Reference specific enthalpy of water (at liquid state)"; + constant Modelica.Units.SI.SpecificEnthalpy dh_vap_water_ref = 2500910 + "Reference specific enthalpy of vaporization of water"; + constant Modelica.Units.SI.SpecificEnthalpy dh_fus_water_ref = 333550 + "Reference specific enthalpy of fusion of water"; + constant Modelica.Units.SI.SpecificEntropy s_water_ref = 0 + "Reference specific entropy of water (at liquid state)"; + constant Modelica.Units.SI.SpecificEntropy ds_vap_water_ref= + dh_vap_water_ref / T_water_ref + "Reference specific entropy of vaporization of water"; + constant Modelica.Units.SI.SpecificEntropy ds_fus_water_ref= + dh_fus_water_ref / T_water_ref + "Reference specific entropy of fusion of water"; + + constant Modelica.Units.SI.SpecificEnthalpy h_dryAir_off = 25097.2 + "Specific enthalpy offset of ideal gas mixture of dry air components to + ensure that specific enthalpy of ideal dry air gas mixture is zero at + reference state of water and reference mass fractions"; + constant Modelica.Units.SI.SpecificEntropy s_dryAir_off = -8239.74 + "Specific enthalpy offset of ideal gas mixture of dry air components to + ensure that specific enthalpy of ideal dry air gas mixture is zero at + reference state of water and reference mass fractions"; + + constant Boolean print_warnings = false + "= true, if warnings indicating bounds of validity shall be printed"; + + // + // Redeclare functions regarding states + // + redeclare final record extends ThermodynamicState + "Thermodynamic state variables" + Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions (i.e., (component amount of substances)/(total amount of + substances) n_i/n)"; + end ThermodynamicState; + + redeclare replaceable model extends BaseProperties( + T(stateSelect=if preferredMediumStates then StateSelect.prefer else + StateSelect.default), + p(stateSelect=if preferredMediumStates then StateSelect.prefer else + StateSelect.default), + Xi(each stateSelect=if preferredMediumStates then StateSelect.prefer else + StateSelect.default), + final standardOrderComponents=true) + "Calculats base properties of the ideal gas-vapor mixture" + + // + // Definition of variables + // + Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions of ideal gas vapor mixture"; + + Modelica.Units.SI.MassFraction[nX] x + "Mass fractions given per dry air mass"; + + Modelica.Units.SI.MassFraction X_sat + "Saturation mass fraction given per saturated moist air mass"; + Modelica.Units.SI.MassFraction X_vapor + "Water vapor fraction given per moist air mass"; + Modelica.Units.SI.MassFraction X_liquidIce + "Liquid or solid water fraction given per moist air mass"; + + Modelica.Units.SI.MassFraction x_sat + "Saturation mass fraction given per dry air mass"; + Modelica.Units.SI.MassFraction x_vapor + "Water vapor fraction given per dry air mass"; + Modelica.Units.SI.MassFraction x_liquidIce + "Liquid or solid water fraction given per dry air mass"; + + Real phi(min=0, max=1) + "Relative humidity"; + + equation + // + // Calculate mass fractions, mole fractions, and relative humidity + // + Y = massToMoleFractions(X=X, MMX=MMX) + "Mole fractions of ideal gas-vapor mixture"; + + x = moistAirToDryAirMassFractions(X=X) + "Mass fractions given per dry air mass"; + + X_sat = massFractionSaturation(state=state) + "Saturation mass fraction given per saturated moist air mass"; + X_vapor = X[nX] - X_liquidIce + "Water vapor fraction given per moist air mass"; + X_liquidIce = max(0.0, X[nX] - X_sat) + "Liquid or solid water fraction given per moist air mass"; + + x_sat = dryMassFractionSaturation(state=state) + "Saturation mass fraction given per dry air mass"; + x_vapor = x[nX] - x_liquidIce + "Water vapor fraction given per dry air mass"; + x_liquidIce = max(0.0, x[nX] - x_sat) + "Liquid or solid water fraction given per dry air mass"; + + phi = relativeHumidity(state=state) + "Relative humidity"; + + // + // Calculate state properties + // + d = rho_pTXY(p=p, T=T, X=X, Y=Y) + "Density"; + h =specificEnthalpy_pTXY( + p=p, + T=T, + X=X, + Y=Y) + "Specific enthalpy per moist air mass"; + u = h - p / d + "Specific internal energy per moist air mass"; + + state.p = p + "State record: Pressure"; + state.T = T + "State record: Temperature"; + state.X = X + "State record: Mass fractions"; + state.Y = Y + "State record: Mole fractions"; + + // + // Calculate additional properties + // + MM = molarMass(state=state) + "Molar mass of the ideal gas-vapor mixture"; + R_s = gasConstant(state=state) + "Specific ideal gas constant of the ideal gas-vapor mixture"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the base properties of an ideal gas-vapor mixture, including +pressure p, temperature T, density d, specific enthalpy h, specific internal +energy u, the specific ideal gas constant R_s, and the molar mass MM. Additionally, +a state record is provided. Furthermore, this model calculates the relative humidity +phi as well as the saturation mass fraction X/x_sat, water vapor mass fraction +X/x_vapor, and water liquid/ice mass fraction X/x_liquidIce per moist air mass (X) +and dry air mass (x). Note that preffered states are pressure, temperature, and +mass fractions of dry air to avoid non-linear equations. +</p> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end BaseProperties; + + redeclare function extends setState_pTX + "Return thermodynamic state as function of pressure p, temperature T, and composition X" + algorithm + state := if size(X, 1) == nX then + ThermodynamicState( + p=p, + T=T, + X=X, + Y=massToMoleFractions(X=X, MMX=MMX)) else + ThermodynamicState( + p=p, + T=T, + X=cat(1, X, {1 - sum(X)}), + Y=massToMoleFractions(X=cat(1, X, {1 - sum(X)}), MMX=MMX)) + "Thermodynamic state record"; + end setState_pTX; + + redeclare function extends setState_phX + "Return thermodynamic state as function of pressure p, specific enthalpy h, and composition X" + algorithm + state :=if size(X, 1) == nX then ThermodynamicState( + p=p, + T=temperature_phXY( + p=p, + h=h, + X=X, + Y=massToMoleFractions(X=X, MMX=MMX)), + X=X, + Y=massToMoleFractions(X=X, MMX=MMX)) else ThermodynamicState( + p=p, + T=temperature_phXY( + p=p, + h=h, + X=cat( + 1, + X, + {1 - sum(X)}), + Y=massToMoleFractions(X=cat( + 1, + X, + {1 - sum(X)}), MMX=MMX)), + X=cat( + 1, + X, + {1 - sum(X)}), + Y=massToMoleFractions(X=cat( + 1, + X, + {1 - sum(X)}), MMX=MMX)) + "Thermodynamic state record"; + end setState_phX; + + redeclare function extends setState_psX + "Return thermodynamic state as function of pressure p, specific enthalpy h, and composition X" + algorithm + state :=if size(X, 1) == nX then ThermodynamicState( + p=p, + T=temperature_psXY( + p=p, + s=s, + X=X, + Y=massToMoleFractions(X=X, MMX=MMX)), + X=X, + Y=massToMoleFractions(X=X, MMX=MMX)) else ThermodynamicState( + p=p, + T=temperature_psXY( + p=p, + s=s, + X=cat( + 1, + X, + {1 - sum(X)}), + Y=massToMoleFractions(X=cat( + 1, + X, + {1 - sum(X)}), MMX=MMX)), + X=cat( + 1, + X, + {1 - sum(X)}), + Y=massToMoleFractions(X=cat( + 1, + X, + {1 - sum(X)}), MMX=MMX)) + "Thermodynamic state record"; + end setState_psX; + + redeclare function extends setState_dTX + "Return thermodynamic state as function of density d, temperature T, and composition X" + algorithm + state :=if size(X, 1) == nX then ThermodynamicState( + p=pressure_dTXY( + d=d, + T=T, + X=X, + Y=massToMoleFractions(X=X, MMX=MMX)), + T=T, + X=X, + Y=massToMoleFractions(X=X, MMX=MMX)) else ThermodynamicState( + p=pressure_dTXY( + d=d, + T=T, + X=cat( + 1, + X, + {1 - sum(X)}), + Y=massToMoleFractions(X=cat( + 1, + X, + {1 - sum(X)}), MMX=MMX)), + T=T, + X=cat( + 1, + X, + {1 - sum(X)}), + Y=massToMoleFractions(X=cat( + 1, + X, + {1 - sum(X)}), MMX=MMX)) + "Thermodynamic state record"; + end setState_dTX; + + redeclare function extends setSmoothState + "Return thermodynamic state so that it smoothly approximates: If x > 0, then state_a else state_b" + algorithm + state := ThermodynamicState( + p=Modelica.Media.Common.smoothStep( + x, + state_a.p, + state_b.p, + x_small), + T=Modelica.Media.Common.smoothStep( + x, + state_a.T, + state_b.T, + x_small), + X=Modelica.Media.Common.smoothStep( + x, + state_a.X, + state_b.X, + x_small), + Y=Modelica.Media.Common.smoothStep( + x, + state_a.Y, + state_b.Y, + x_small)); + end setSmoothState; + // + // Redeclare functions regarding state properties + // + redeclare function extends pressure + "Returns pressure of the ideal gas-vapor mixture" + algorithm + p := state.p + "Pressure of ideal gas-vapor mixture"; + end pressure; + + redeclare function extends temperature + "Returns temperature of the ideal gas-vapor mixture" + algorithm + T := state.T + "Tempeerature of ideal gas-vapor mixture"; + end temperature; + + redeclare function extends density + "Returns density of the ideal gas-vapor mixture" + algorithm + d := rho_pTXY(p=state.p, T=state.T, X=state.X, Y=state.Y) + "Density of ideal gas-vapor mixture"; + end density; + + redeclare function extends specificEnthalpy + "Returns specific enthalpy of the ideal gas-vapor mixture" + algorithm + h :=specificEnthalpy_pTXY( + p=state.p, + T=state.T, + X=state.X, + Y=state.Y) + "Specific enthalpy of ideal gas-vapor mixture"; + end specificEnthalpy; + + redeclare function extends specificInternalEnergy + "Returns specific internal energy of the ideal gas-vapor mixture" + algorithm + u :=specificEnthalpy_pTXY( + p=state.p, + T=state.T, + X=state.X, + Y=state.Y) - state.p/rho_pTXY( + p=state.p, + T=state.T, + X=state.X, + Y=state.Y) + "Specific internal energy of ideal gas-vapor mixture"; + end specificInternalEnergy; + + redeclare function extends specificEntropy + "Returns specific entropy of the ideal gas-vapor mixture" + algorithm + s :=specificEntropy_pTXY( + p=state.p, + T=state.T, + X=state.X, + Y=state.Y) + "Specific entropy of ideal gas-vapor mixture"; + end specificEntropy; + + redeclare function extends specificGibbsEnergy + "Returns specific Gibbs energy of the ideal gas-vapor mixture" + algorithm + g :=specificEnthalpy_pTXY( + p=state.p, + T=state.T, + X=state.X, + Y=state.Y) - state.T*specificEntropy_pTXY( + p=state.p, + T=state.T, + X=state.X, + Y=state.Y) + "Specific Gibbs energy of ideal gas-vapor mixture"; + end specificGibbsEnergy; + + redeclare function extends specificHelmholtzEnergy + "Returns specific Helmholtz energy of the ideal gas-vapor mixture" + algorithm + f :=specificEnthalpy_pTXY( + p=state.p, + T=state.T, + X=state.X, + Y=state.Y) - state.p/rho_pTXY( + p=state.p, + T=state.T, + X=state.X, + Y=state.Y) - state.T*specificEntropy_pTXY( + p=state.p, + T=state.T, + X=state.X, + Y=state.Y) + "Specific Helmholtz energy of ideal gas-vapor mixture"; + end specificHelmholtzEnergy; + // + // Redeclare functions regarding additional properties + // + redeclare function extends dynamicViscosity + "Returns dynamic viscosity" + + // + // Definition of constants + // +protected + constant Modelica.Units.SI.Temperature A_liq = 0.45047 + "First constant of liquid water"; + constant Modelica.Units.SI.Temperature B_liq = 1.39753 + "Second constant of liquid water"; + constant Modelica.Units.SI.Temperature C_liq = 613.181 + "Third constant of liquid water"; + constant Modelica.Units.SI.Temperature D_liq = 63.697 + "fourth constant of liquid water"; + constant Modelica.Media.Interfaces.Types.DynamicViscosity E_liq = 0.00006896 + "Fivth constant of liquid water"; + + // + // Definition of variables + // + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + + Modelica.Units.SI.Pressure[nX] p_i= + partialPressures(state=state) + "Partial pressures"; + + Modelica.Units.SI.SpecificVolume v_dryAirVapor + "Specific volume of dry air and water vapor per dry air mass"; + Modelica.Units.SI.SpecificVolume v_liquidSolid + "Specific volume of liquid or solid water per dry air mass"; + + Modelica.Media.Interfaces.Types.DynamicViscosity[nX] eta_gasVapor + "Dynamic viscosities of components at gas or vapor state"; + Modelica.Media.Interfaces.Types.DynamicViscosity eta_dryAirVapor + "Dynamic viscosity of dry air and water vapor"; + Modelica.Media.Interfaces.Types.DynamicViscosity eta_liquidSolid + "Dynamic viscosity of water's liquid or solid phase"; + + algorithm + // + // Calculate dynamic viscosity of ideal gas-vapor mixture at gas state + // + for ind in 1:nX loop + eta_gasVapor[ind] := + Modelica.Media.IdealGases.Common.Functions.dynamicViscosityLowPressure( + T=state.T, + Tc=fluidConstants[ind].criticalTemperature, + M=fluidConstants[ind].molarMass, + Vc=fluidConstants[ind].criticalMolarVolume, + w=fluidConstants[ind].acentricFactor, + mu=fluidConstants[ind].dipoleMoment) + "Dynamic viscosities of components at gas or vapor state"; + end for; + + eta_dryAirVapor := gasMixtureViscosity( + yi=p_i./state.p, + M=MMX, + eta=eta_gasVapor) + "Dynamic viscosity of dry air and water vapor"; + + // + // Calculate densities and dynamic viscosity of water at liquid or solid state + // + if x[nX] <= x_sat then + v_dryAirVapor := + (sum(x ./ MMX .* Modelica.Constants.R .* state.T ./ state.p)) + "Specific volume of dry air and water vapor per dry air mass"; + v_liquidSolid :=0 + "Specific volume of liquid or solid water per dry air mass"; + eta_liquidSolid :=0 + "Dynamic viscosity of water's liquid or solid phase"; + + elseif state.T > T_water_trp then + v_dryAirVapor := + (sum(x[1:nX-1] .* Modelica.Constants.R ./ MMX[1:nX-1] .* state.T ./ + state.p) + + x_sat * Modelica.Constants.R / MMX[nX] * state.T / state.p) + "Specific volume of dry air and water vapor per dry air mass"; + v_liquidSolid := + ((x[nX] - x_sat) * v_water_liq) + "Specific volume of liquid or solid water per dry air mass"; + eta_liquidSolid := + E_liq * Modelica.Math.exp(A_liq * + ((C_liq - state.T)/(state.T - D_liq)) ^ (1/3) + B_liq * + ((C_liq - state.T)/(state.T - D_liq)) ^ (4/3)) + "Dynamic viscosity of water's liquid or solid phase"; + + else + /* + Note that the dynamic viscosity of solid water is neglected + */ + v_dryAirVapor := + (sum(x[1:nX-1] .* Modelica.Constants.R ./ MMX[1:nX-1] .* state.T ./ + state.p) + + x_sat * Modelica.Constants.R / MMX[nX] * state.T / state.p) + "Specific volume of dry air and water vapor per dry air mass"; + v_liquidSolid := + ((x[nX] - x_sat) * v_water_solid) * 0 + "Specific volume of liquid or solid water per dry air mass"; + eta_liquidSolid := 1e14 + "Dynamic viscosity of water's liquid or solid phase"; + + end if; + + // + // Calculate density averaged dynamic viscosity + // + eta := v_dryAirVapor / (v_dryAirVapor + v_liquidSolid) * eta_dryAirVapor + + v_liquidSolid / (v_dryAirVapor + v_liquidSolid) * eta_liquidSolid + "Dynamic viscosity"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the dynamic viscosity of the ideal gas-vapor mixture as +function of the state record. For the case of saturated dry air with liquid or +solid water, the dynamic viscosity is calculated as average dynamic viscosity +using the specific volumes of the different phases for averaging. Note that the +dynamic viscosity of solid water is neglected. For the ideal gas-vapor mixture, +this function applies a simplification of the kinetic theory (Chapman and Enskog +theory) neglecting the second-order effects. Details can be found in the orginal +implementations: +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.dynamicViscosity\">Modelica.Media.IdealGases.Common.MixtureGasNasa.dynamicViscosity</a> +and +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.gasMixtureViscosity\">Modelica.Media.IdealGases.Common.MixtureGasNasa.gasMixtureViscosity</a>. +For liquid water, a generalized function is applied according to the VDI Heat +Atlas. +</p> + +<h4>References</h4> +<ul> + <li> + Kleiber, M. and Joh, R. and Span, R. (2002). D3 Properties of Pure Fluid Substances, In: VDI Heat Atlas, 2nd Edition. DOI: https://doi.org/10.1007/978-3-540-77877-6. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end dynamicViscosity; + + redeclare function extends thermalConductivity + "Returns thermal conductivity" + // + // Definition of constants + // +protected + constant Modelica.Units.SI.ThermalConductivity A_liq = -2.4149 + "First constant of liquid water"; + constant Real B_liq(unit="W/(m.K2)") = 2.45165e-2 + "Second constant of liquid water"; + constant Real C_liq(unit="W/(m.K3)") = -0.73121e-4 + "Third constant of liquid water"; + constant Real D_liq(unit="W/(m.K4)") = 0.99492e-7 + "fourth constant of liquid water"; + constant Real E_liq(unit="W/(m.K5)") = -0.53730e-10 + "Fivth constant of liquid water"; + + constant Modelica.Units.SI.ThermalConductivity A_solid = 2.60970865 + "First constant of solid water"; + constant Real B_solid(unit="W/(m.K2)") = 3.72962320e-2 + "Second constant of solid water"; + constant Real C_solid(unit="W/(m.K3)") = -2.63535950e-4 + "Third constant of solid water"; + constant Real D_solid(unit="W/(m.K4)") = 4.45674690e-7 + "fourth constant of solid water"; + + // + // Definition of variables + // + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + + Modelica.Units.SI.Pressure[nX] p_i= + partialPressures(state=state) + "Partial pressures"; + + Modelica.Units.SI.SpecificVolume v_dryAirVapor + "Specific volume of dry air and water vapor per dry air mass"; + Modelica.Units.SI.SpecificVolume v_liquidSolid + "Specific volume of liquid or solid water per dry air mass"; + + Modelica.Units.SI.SpecificHeatCapacity[nX] cp_gasVapor + "Specific heat capacities of components at gas or vapor state"; + Modelica.Units.SI.DynamicViscosity[nX] eta_gasVapor + "Dynamic viscosities of components at gas or vapor state"; + + Modelica.Units.SI.ThermalConductivity[nX] lambda_gasVapor + "Thermal conductivities of components at gas or vapor state"; + Modelica.Units.SI.ThermalConductivity lambda_dryAirVapor + "Thermal conductivity of dry air and water vapor"; + Modelica.Units.SI.ThermalConductivity lambda_liquidSolid + "Thermal conductivity of water's liquid or solid phase"; + + algorithm + // + // Calculate dynamic viscosity of ideal gas-vapor mixture at gas state + // + for ind in 1:nX loop + cp_gasVapor[ind] := + Modelica.Media.IdealGases.Common.Functions.cp_T( + data=data[ind], + T=state.T) + "Specific heat capacities of components at gas or vapor state"; + + eta_gasVapor[ind] := + Modelica.Media.IdealGases.Common.Functions.dynamicViscosityLowPressure( + T=state.T, + Tc=fluidConstants[ind].criticalTemperature, + M=fluidConstants[ind].molarMass, + Vc=fluidConstants[ind].criticalMolarVolume, + w=fluidConstants[ind].acentricFactor, + mu=fluidConstants[ind].dipoleMoment) + "Dynamic viscosities of components at gas or vapor state"; + + lambda_gasVapor[ind] := + Modelica.Media.IdealGases.Common.Functions.thermalConductivityEstimate( + Cp=cp_gasVapor[ind], + eta=eta_gasVapor[ind], + method=1, + data=data[ind]) + "Thermal conductivities of components at gas or vapor state"; + end for; + + lambda_dryAirVapor := lowPressureThermalConductivity( + y=p_i./state.p, + T=state.T, + Tc=fluidConstants[:].criticalTemperature, + Pc=fluidConstants[:].criticalPressure, + M=MMX, + lambda=lambda_gasVapor) + "Thermal conductivity of dry air and water vapor"; + + // + // Calculate densities and dynamic viscosity of water at liquid or solid state + // + if x[nX] <= x_sat then + v_dryAirVapor := + (sum(x ./ MMX .* Modelica.Constants.R .* state.T ./ state.p)) + "Specific volume of dry air and water vapor per dry air mass"; + v_liquidSolid :=0 + "Specific volume of liquid or solid water per dry air mass"; + lambda_liquidSolid :=0 + "Thermal conductivity of water's liquid or solid phase"; + + elseif state.T > T_water_trp then + v_dryAirVapor := + (sum(x[1:nX-1] .* Modelica.Constants.R ./ MMX[1:nX-1] .* state.T ./ + state.p) + + x_sat * Modelica.Constants.R / MMX[nX] * state.T / state.p) + "Specific volume of dry air and water vapor per dry air mass"; + v_liquidSolid := + ((x[nX] - x_sat) * v_water_liq) + "Specific volume of liquid or solid water per dry air mass"; + lambda_liquidSolid := + A_liq + B_liq * state.T + C_liq * state.T^2 + + D_liq * state.T^3 + E_liq * state.T^4 + "Thermal conductivity of water's liquid or solid phase"; + + else + v_dryAirVapor := + (sum(x[1:nX-1] .* Modelica.Constants.R ./ MMX[1:nX-1] .* state.T ./ + state.p) + + x_sat * Modelica.Constants.R / MMX[nX] * state.T / state.p) + "Specific volume of dry air and water vapor per dry air mass"; + v_liquidSolid := + ((x[nX] - x_sat) * v_water_solid) + "Specific volume of liquid or solid water per dry air mass"; + lambda_liquidSolid := + A_solid + B_solid * state.T + C_solid * state.T^2 + D_solid * state.T^3 + "Thermal conductivity of water's liquid or solid phase"; + + end if; + + // + // Calculate density averaged dynamic viscosity + // + lambda := v_dryAirVapor / (v_dryAirVapor + v_liquidSolid) * lambda_dryAirVapor + + v_liquidSolid / (v_dryAirVapor + v_liquidSolid) * lambda_liquidSolid + "Thermal conductivity"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the thermal conductivity of the ideal gas-vapor mixture +as function of the state record. For the case of saturated dry air with liquid or +solid water, the thermal conductivity is calculated as average dynamic viscosity +using the specific volumes of the different phases for averaging. For the ideal +gas-vapor mixture, this function applies the Masson and Saxena modification of the +Wassiljewa Equation for the thermal conductivity for gas mixtures of n elements +at low pressure. Details can be found in the orginal implementations: +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.thermalConductivity\">Modelica.Media.IdealGases.Common.MixtureGasNasa.thermalConductivity</a> +and +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.lowPressureThermalConductivity\">Modelica.Media.IdealGases.Common.MixtureGasNasa.lowPressureThermalConductivity</a>. +For liquid water, a generalized function is applied according to the VDI Heat +Atlas. For solid water, a polynomial fit is applied using data from the +Engineering Toolbox. +</p> + +<h4>References</h4> +<ul> + <li> + The Engineering ToolBox (2004). Ice - Thermal Properties. URL: https://www.engineeringtoolbox.com/ice-thermal-properties-d_576.html [Accessed November 27, 2023]. + </li> + <li> + Kleiber, M. and Joh, R. and Span, R. (2002). D3 Properties of Pure Fluid Substances, In: VDI Heat Atlas, 2nd Edition. DOI: https://doi.org/10.1007/978-3-540-77877-6. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end thermalConductivity; + + redeclare function extends specificHeatCapacityCp + "Returns specific heat capacity at constant pressure" + algorithm + cp := dh_dT_pX(state=state) + "Specific heat capacity at constant pressure"; + end specificHeatCapacityCp; + + redeclare function extends specificHeatCapacityCv + "Returns specific heat capacity at constant volume" + + // + // Definition of variables + // +protected + SorpLib.Units.DerSpecificVolumeByPressure dv_dp_TX_= + dv_dp_TX(state=state) + "Partial derivative of specific volume w.r.t. pressure at constant + temperature and mass fractions"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_dT_pX_= + dv_dT_pX(state=state) + "Partial derivative of specific volume w.r.t. temperature at constant pressure + and mass fractions"; + + algorithm + cv := dh_dT_pX(state=state) - state.p * dv_dT_pX_ - + dh_dp_TX(state=state) * dv_dT_pX_ / dv_dp_TX_ + + 1 / density(state=state) * dv_dT_pX_ / dv_dp_TX_ + + state.p * dv_dT_pX_ + "Specific heat capacity at constant volume"; + end specificHeatCapacityCv; + + redeclare function extends isentropicExponent + "Returns isentropic exponent that is only sound for unsaturated air" + algorithm + gamma := specificHeatCapacityCp(state=state) / + specificHeatCapacityCv(state=state) + "Isentropic exponent"; + end isentropicExponent; + + redeclare function extends isentropicEnthalpy + "Returns isentropic enthalpy" + algorithm + h_is := specificEnthalpy_pTXY( + p=p_downstream, + T=temperature_psXY( + p=p_downstream, + s=specificEntropy(state=refState), + X=refState.Y, + Y=refState.Y), + X=refState.X, + Y=refState.Y) + "Isentropic enthalpy"; + end isentropicEnthalpy; + + redeclare function extends velocityOfSound + "Return veolicity of sound" + algorithm + a := sqrt(1 / (-density(state=state)^2 * (dv_dp_TX(state=state) + + dv_dT_pX(state=state)^2 * state.T / specificHeatCapacityCp(state=state)))) + "Velocity of sound"; + end velocityOfSound; + + redeclare function extends isobaricExpansionCoefficient + "Returns isobaric expansion coefficient" + algorithm + beta := density(state=state) * dv_dT_pX(state=state) + "Isobaric expansion coefficient"; + end isobaricExpansionCoefficient; + + redeclare function extends isothermalCompressibility + "Returns isothermal compressibility" + algorithm + kappa := -density(state=state) * dv_dp_TX(state=state) + "Isothermal compressibility"; + end isothermalCompressibility; + + redeclare function extends density_derp_h + "Returns partial derivative of density w.r.t. pressure at constant specific enthalpy and mass fractions" + algorithm + ddph := density_derp_T(state=state) - density_derT_p(state=state) * + dh_dp_TX(state=state) / dh_dT_pX(state=state) + "Partial derivative of density w.r.t. pressure at constant specific + enthalpy and mass fractions"; + end density_derp_h; + + redeclare function extends density_derh_p + "Returns partial derivative of density w.r.t. specific enthalpy at constant pressure and mass fractions" + algorithm + ddhp := density_derT_p(state=state) / dh_dT_pX(state=state) + "Partial derivative of density w.r.t. specific enthalpy at constant + pressure and mass fractions"; + end density_derh_p; + + redeclare function extends density_derp_T + "Returns partial derivative of density w.r.t. pressure at constant temperature and mass fractions" + algorithm + ddpT := -rho_pTXY(p=state.p, T=state.T, X=state.X, Y=state.Y)^2 * + dv_dp_TX(state=state) + "Partial derivative of density w.r.t. pressure at constant temperature + and mass fractions"; + end density_derp_T; + + redeclare function extends density_derT_p + "Returns partial derivative of density w.r.t. temperature at constant pressure and mass fractions" + algorithm + ddTp := -rho_pTXY(p=state.p, T=state.T, X=state.X, Y=state.Y)^2 * + dv_dT_pX(state=state) + "Partial derivative of density w.r.t. temperature at constant pressure + and mass fractions"; + end density_derT_p; + + redeclare function extends density_derX + "Returns partial derivatives of density w.r.t. mass fractions at constant pressure and temperature" + algorithm + dddX := -rho_pTXY(p=state.p, T=state.T, X=state.X, Y=state.Y)^2 .* + dv_dX_pT(state=state) + "Partial derivative of density w.r.t. mass fractions at constant pressure + and temperature"; + end density_derX; + + redeclare function extends molarMass + "Returns molar mass of the ideal gas-vapor mixture" + algorithm + MM := state.Y * MMX + "Molar mass of the ideal gas-vapor mixture"; + end molarMass; + + redeclare function extends gasConstant + "Returns specific ideal gas constant of the ideal gas-vapor mixture" + algorithm + if (state.X[nX] / (1 - state.X[nX])) > + dryMassFractionSaturation(state=state) then + R_s := Modelica.Constants.R / + sum(partialPressures(state=state) ./ state.p .* MMX) + "Specific ideal gas constant for saturated gas-vapor mixture "; + + else + R_s := Modelica.Constants.R * sum(state.X ./ MMX) + "Specific ideal gas constant for unsaturated gas-vapor mixture "; + + end if; + end gasConstant; + + redeclare function extends enthalpyOfNonCondensingGas + "Returns specific enthalpy of non-condensing components (i.e., dry air) (per dry air mass)" + + // + // Definition of inputs + // + input Modelica.Units.SI.MassFraction[:] X + "Vector of mass fractions" + annotation (Dialog(tab="General",group="Inputs")); + + algorithm + h := X[1:nX-1] / sum(X[1:nX-1]) * + {Modelica.Media.IdealGases.Common.Functions.h_T( + data=data[i], + T=T, + exclEnthForm=true, + refChoice=Modelica.Media.Interfaces.Choices.ReferenceEnthalpy.UserDefined, + h_off=h_dryAir_off) for i in 1:nX-1} + "Specific enthalpy of dry air"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy of the non-condensing components +(i.e., dry air) per dry air mass according to the model of an ideal gas mixture +as function of temperature and mass fractions. The specific enthalpy is calculated +using NASA Glenn Coefficients. For more details, check the function +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.h_TX\">Modelica.Media.IdealGases.Common.MixtureGasNasa.h_TX</a>. +Note that this function does assume that no water is present. To calculate the +specific enthalpy of the non-condensing components that are actually present, +use the function +<a href=\"Modelica://SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture.enthalpyOfNonCondensingComponents\">SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture.enthalpyOfNonCondensingComponents</a>. +</p> + +<h4>References</h4> +<ul> + <li> + McBride, B.J. and Zehe, M.J. and Gordon, S. (2002). NASA Glenn Coefficients for Calculating Thermodynamic Properties of Individual Species, Technical report, NASA/TP—2002-211556. URL: https://ntrs.nasa.gov/citations/20020085330. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end enthalpyOfNonCondensingGas; + + redeclare function extends enthalpyOfGas( + T=state.T, + X=state.X) + "Returns specific enthalpy of non-condensing components (i.e., dry air) and vaporous water (per moist air mass)" + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + + algorithm + // + // Calculate specific enthalpy per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + h := enthalpyOfNonCondensingGas(T=state.T, X=x) + "Specific enthalpy equals specific enthalpy of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + + elseif x[nX] <= x_sat then + h := enthalpyOfNonCondensingGas(T=state.T, X=x) + + x[nX] * enthalpyOfCondensingGas(T=state.T) + "Specific enthalpy equals specific enthalpy of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + + else + h := enthalpyOfNonCondensingGas(T=state.T, X=x) + + x_sat * enthalpyOfCondensingGas(T=state.T) + "Specific enthalpy equals specific enthalpy of saturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + + end if; + + // + // Convert specific enthalpy per dry air mass + // + h := h / (1 + x[nX]) + "Specific enthalpy per moist air mass"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy of the non-condensing components +(i.e., dry air) and vaporous water (i.e., vapor) per moist air mass according to +the model of an ideal gas-vapor mixture as function of temperature and mass +fractions. +</p> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end enthalpyOfGas; + // + // Redeclare functions regarding condensing component + // + redeclare function extends saturationPressure + "Returns saturation pressure of condensing fluid (i.e., water)" + algorithm + psat := saturationPressureH2O_T(Tsat) + "Saturation pressure"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(Tsat=saturationTemperature(p_sat=psat))); + end saturationPressure; + + redeclare function extends enthalpyOfVaporization + "Returns specific enthalpy of vaporization of water (per water mass)" + + // + // Definition of constants + // +protected + constant Real[7] coefficients_liq= + {1, 1.99274064, 1.09965342, -0.510839303, + -1.75493479, -45.5170352, -6.74694450e5} + "Coefficients of saturated liquid density"; + constant Real[6] coefficients_vap= + {-2.03150240, -2.68302940, -5.38626492, -17.2991605, + -44.7586581, -63.9201063} + "Coefficients of saturated vapor density"; + + constant Real[7] exponents_liq= + {0, 1/3, 2/3, 5/3, 16/3, 43/3, 110/3} + "Exponents of saturated liquid density"; + constant Real[6] exponents_vap= + {2/6, 4/6, 8/6, 18/6, 37/6, 71/6} + "Exponents of saturated vapor density"; + + // + // Definition of variables + // + Modelica.Media.Common.DerPressureByTemperature dp_sat_dT= + dsaturationPressureH2O_dT(T_sat=T) + "First-order partial derivative of saturation pressure w.r.t. temperature"; + + Modelica.Units.SI.Density rho_sat_liq= + SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T, + T_ref=T_water_crit, + z_ref=d_water_crit, + coefficients=coefficients_liq, + exponents=exponents_liq, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionReducedTemperature) + "Density of saturated liquid"; + Modelica.Units.SI.Density rho_sat_vap= + SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T, + T_ref=T_water_crit, + z_ref=d_water_crit, + coefficients=coefficients_vap, + exponents=exponents_vap, + approach=SorpLib.Choices.GeneralizedFunctionApproach.ExponentialFunctionReducedTemperature) + "Density of saturated vapor"; + + algorithm + r0 := (T/rho_sat_vap - T/rho_sat_liq) * dp_sat_dT + "Specific enthalpy of vaporization of water"; + + // + // Assertations + // + if print_warnings then + assert(T_water_trp <= T and T <= T_water_crit, + "Temperature (" + String(T) + " K) is not between 273.16 and 647.096 K. " + + "Calculation of specific enthalpy of vaporization is not possible!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy of vaporization of the condensing +component (i.e., water) per water mass as function of the temperature. +</p> + +<h4>References</h4> +<ul> + <li> + Wagner, W. and Pruß, A (2002). The IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, Journal of Physical and Chemical Reference Data, 31:387. DOI: https://doi.org/10.1063/1.1461829. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end enthalpyOfVaporization; + + redeclare function extends enthalpyOfLiquid + "Returns enthalpy of liquid water (per water mass)" + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of constants + // +protected + constant Real[10] coefficients= + {4.66348457415926e-19, -1.16579701193758e-15, 9.49925152355854e-13, + 5.81553479401465e-11, -6.55387915784314e-7, 5.30868446475702e-4, + -2.18234813641286e-1, 5.13043718148301e1, -6.58121774333134e3, + 3.63215816205503e5} + "Coefficients of polynomical function"; + constant Real[10] exponents= + {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} + "Exponents of polynomical function"; + + algorithm + h := h_water_ref + v_water_liq * (p - p_water_ref) + + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T, + T_ref=573.15, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) - + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T_water_ref, + T_ref=573.15, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Specific enthalpy of liquid water"; + + // + // Assertations + // + if print_warnings then + assert(T_water_trp-1 <= T and T <= 573.15, + "Temperature (" + String(T) + " K) is not between 272.16 and 573.15 K. " + + "Calculation of specific enthalpy of liquid may not be valid!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy of the condensing component's +(i.e., water) liquid phase per water mass according to the model of an ideal +liquid as function of pressure and temperature. The specific heat capacity is +calculated as a polynomial fit to specific heat capacity data calculated at +saturated liquid state with the reference equation of state for water. The data +was calculated for temperature varying from 273.16 K to 573.15 K. Note that this +function does not consider the actual water mass fraction. To calculate the +specific enthalpy of the liquid water that is actually present, use the function +<a href=\"Modelica://SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture.enthalpyOfLiquidIce\">SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture.enthalpyOfLiquidIce</a>. +</p> + +<h4>References</h4> +<ul> + <li> + McBride, B.J. and Zehe, M.J. and Gordon, S. (2002). NASA Glenn Coefficients for Calculating Thermodynamic Properties of Individual Species, Technical report, NASA/TP—2002-211556. URL: https://ntrs.nasa.gov/citations/20020085330. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end enthalpyOfLiquid; + + redeclare function extends enthalpyOfCondensingGas + "Returns enthalpy of vaporous water (per water mass)" + + // + // Definition of constants + // +protected + constant Real[10] coefficients= + {7.03241022996521e-23, -4.12454440465976e-19, 1.05640534898709e-15, + -1.54797437245421e-12, 1.42577474111776e-9, -8.51385633913246e-7, + 3.26064390458737e-4, -7.52464997116974e-2, 9.42339113729594, + 1.36103845934352e+3} + "Coefficients of polynomical function"; + constant Real[10] exponents= + {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} + "Exponents of polynomical function"; + + algorithm + h := h_water_ref + dh_vap_water_ref + + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T, + T_ref=T_water_crit, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) - + SorpLib.Media.Functions.Utilities.intGeneralizedFunction_dT( + T=T_water_ref, + T_ref=T_water_crit, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Specific enthalpy of vaporous water"; + + // + // Assertations + // + if print_warnings then + assert(200 <= T and T <= 1000, + "Temperature (" + String(T) + " K) is not between 200 and 1000 K. " + + "Calculation of specific enthalpy of vapor may not be valid!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy of the condensing component's +(i.e., water) vapor phase per mass of water according to the model of an ideal +gas as function of temperature. The specific heat capacity is calculated as a +polynomial fit to specific heat capacity data calculated according to the NASA +Glenn Coefficients. The data was calculated for a temperature varying from 200 K +to 1000 K. Note that this function does not consider the actual water mass fraction. +To calculate the specific enthalpy of the vaporous water that is actually present, +use the function +<a href=\"Modelica://SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture.enthalpyOfVapor\">SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture.enthalpyOfVapor</a>. +</p> + +<h4>References</h4> +<ul> + <li> + McBride, B.J. and Zehe, M.J. and Gordon, S. (2002). NASA Glenn Coefficients for Calculating Thermodynamic Properties of Individual Species, Technical report, NASA/TP—2002-211556. URL: https://ntrs.nasa.gov/citations/20020085330. + </li> +</ul> + +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end enthalpyOfCondensingGas; + // + // Add new functions + // + function saturationTemperature + "Returns saturation temperature of condensing fluid (i.e., water)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_sat + "Saturation pressure" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Temperature T_sat + "Saturation temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of protected funtions + // +protected + function p_sat_T_sat + "Function used to solve non-linear equation 0 = p_sat(T_sat) - p_sat" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p_sat + "Saturation pressure"; + + algorithm + y :=saturationPressureH2O_T(T_sat=u) - p_sat + "Zero point problem"; + end p_sat_T_sat; + + algorithm + T_sat := Modelica.Math.Nonlinear.solveOneNonlinearEquation( + f = function p_sat_T_sat(p_sat=p_sat), + u_min = 50, + u_max = T_water_crit-1, + tolerance = 100*Modelica.Constants.eps) + "Saturation temperature"; + + // + // Annotations + // + annotation (Inline=false, + InlineAfterIndexReduction=false, + LateInline=true, + inverse(p_sat=saturationPressure(Tsat=T_sat)), + Documentation(info="<html> +<p> +This function calculates the vapor temperature as function of the vapor pesssure +by solving a non-linear equation via the very efficient function +<a href=\"Modelica://Modelica.Math.Nonlinear.solveOneNonlinearEquation\">Modelica.Math.Nonlinear.solveOneNonlinearEquation</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end saturationTemperature; + +protected + function gasMixtureViscosity + "Returns viscosities of gas mixtures (at low pressures according to the Wilke method)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MoleFraction[nX] yi + "Mole fractions" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MolarMass[nX] M + "Mole masses" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.DynamicViscosity[nX] eta + "Pure component viscosities" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.DynamicViscosity etam + "Viscosity of the mixture" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real fi[nX,nX]; + + algorithm + for i in 1:nX loop + // + // Check if calculation is possible + // + assert(fluidConstants[i].hasDipoleMoment,"Dipole moment for " + + fluidConstants[i].chemicalFormula + + " not known. Can not compute viscosity."); + assert(fluidConstants[i].hasCriticalData, "Critical data for " + + fluidConstants[i].chemicalFormula + + " not known. Can not compute viscosity."); + + // + // Calculate viscosity + // + for j in 1:nX loop + if i==1 then + fi[i,j] := (1 + (eta[i]/eta[j])^(1/2)*(M[j]/M[i])^(1/4))^2/ + (8*(1 + M[i]/M[j]))^(1/2); + elseif j<i then + fi[i,j] := eta[i]/eta[j]*M[j]/M[i]*fi[j,i]; + else + fi[i,j] := (1 + (eta[i]/eta[j])^(1/2)*(M[j]/M[i])^(1/4))^2/ + (8*(1 + M[i]/M[j]))^(1/2); + end if; + end for; + end for; + + etam := sum(yi[i]*eta[i]/sum(yi[j]*fi[i,j] for j in 1:nX) for i in 1:nX); + + // + // Annotations + // + annotation (smoothOrder=2, Documentation(info="<html> +<p> +Simplification of the kinetic theory (Chapman and Enskog theory) approach +neglecting the second-order effects. This function is a copy of function +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.gasMixtureViscosity\">Modelica.Media.IdealGases.Common.MixtureGasNasa.gasMixtureViscosity</a>, +to be able to use this function within the curent media model. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end gasMixtureViscosity; + + function lowPressureThermalConductivity + "Returns thermal conductivity (at low pressure according to the Mason and Saxena modification)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.MoleFraction[nX] y + "Mole fraction of the components in the gas mixture" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature[nX] Tc + "Critical temperatures" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.AbsolutePressure[nX] Pc + "Critical pressures" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MolarMass[nX] M + "Molecular weights" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.ThermalConductivity[nX] lambda + "Thermal conductivities of the pure gases" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.ThermalConductivity lambdam + "Thermal conductivity of the gas mixture" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real epsilon = 1.0 + "Numerical constant near unity"; + + // + // Definition of variables + // + Modelica.Units.SI.MolarMass[nX] gamma; + Real[nX] Tr + "Reduced temperature"; + Real[nX,nX] A + "Mason and Saxena Modification"; + + algorithm + for i in 1:nX loop + gamma[i] := 210*(Tc[i]*M[i]^3/Pc[i]^4)^(1/6); + Tr[i] := T/Tc[i]; + + end for; + + for i in 1:nX loop + for j in 1:nX loop + A[i,j] := epsilon*(1 + (gamma[j]*(Modelica.Math.exp(0.0464*Tr[i]) - + Modelica.Math.exp(-0.2412*Tr[i])) / + (gamma[i]*(Modelica.Math.exp(0.0464*Tr[j]) - + Modelica.Math.exp(-0.2412*Tr[j])))) ^ + (1/2)*(M[i]/M[j])^(1/4))^2/(8*(1 + M[i]/M[j]))^(1/2); + end for; + end for; + + lambdam := + sum(y[i]*lambda[i]/(sum(y[j]*A[i,j] for j in 1:nX)) for i in 1:nX); + + // + // Annotations + // + annotation (smoothOrder=2, Documentation(info="<html> +<p> +This function applies the Masson and Saxena modification of the Wassiljewa +Equation for the thermal conductivity for gas mixtures of n elements at low +pressure. This function is a copy of function +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa.lowPressureThermalConductivity\">Modelica.Media.IdealGases.Common.MixtureGasNasa.lowPressureThermalConductivity</a>, +to be able to use this function within the curent media model. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end lowPressureThermalConductivity; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model extends the medium model of an ideal gas-vapor mixture provided +in the Modelica Standard Library by additional functions needed in SorpLib. +Furthermore, the media model is modified so that it can describe an ideal gas +mixture with any number of non-condensing components and one ideal condensing +component. The condensing component is water and must always be the last component +when defining a medium model. The properties of the ideal gas mixture of the +non-condensing components are calculated according to the media model +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa\">Modelica.Media.IdealGases.Common.MixtureGasNasa</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialIdealGasWaterVaporMixture; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/package.order b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/package.order new file mode 100644 index 0000000000000000000000000000000000000000..aa4d172405cadd4a6f1da96a63db7ac4f54f2e47 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/package.order @@ -0,0 +1,104 @@ +data +MMX +p_water_trp +p_water_crit +T_water_trp +T_water_crit +d_water_crit +v_water_liq +v_water_solid +p_water_ref +T_water_ref +h_water_ref +dh_vap_water_ref +dh_fus_water_ref +s_water_ref +ds_vap_water_ref +ds_fus_water_ref +h_dryAir_off +s_dryAir_off +print_warnings +ThermodynamicState +BaseProperties +setState_pTX +setState_phX +setState_psX +setState_dTX +setSmoothState +pressure +temperature +density +specificEnthalpy +specificInternalEnergy +specificEntropy +specificGibbsEnergy +specificHelmholtzEnergy +dynamicViscosity +thermalConductivity +specificHeatCapacityCp +specificHeatCapacityCv +isentropicExponent +isentropicEnthalpy +velocityOfSound +isobaricExpansionCoefficient +isothermalCompressibility +density_derp_h +density_derh_p +density_derp_T +density_derT_p +density_derX +molarMass +gasConstant +enthalpyOfNonCondensingGas +enthalpyOfGas +saturationPressure +enthalpyOfVaporization +enthalpyOfLiquid +enthalpyOfCondensingGas +rho_pTXY +specificEnthalpy_pTXY +specificEntropy_pTXY +pressure_dTXY +temperature_phXY +temperature_psXY +massFractions_pTxDryPhi +partialPressures +enthalpyOfNonCondensingComponents +entropyOfNonCondensingGas +specificEnthalpy_i +specificEntropy_i +dmassToMoleFractions_dX +dv_dp_TX +dv_dT_pX +dv_dX_pT +dh_dp_TX +dh_dT_pX +dh_dX_pT +drho_dX_ph +saturationTemperature +saturationPressureH2O_T +dsaturationPressureH2O_dT +ddsaturationPressureH2O_dT_dT +relativeHumidity +massFractionSaturation +dryMassFractionSaturation +ddryMassFractionSaturation_dp_TX +ddryMassFractionSaturation_dT_pX +ddryMassFractionSaturation_dX_pT +specificHeatCapacitySolid +specificHeatCapacityLiquid +specificHeatCapacityVapor +enthalpyOfSolid +enthalpyOfCondensingComponent +enthalpyOfVapor +enthalpyOfLiquidIce +entropyOfSolid +entropyOfLiquid +entropyOfCondensingGas +moistAirToDryAirMassFractions +dryAirToMoistAirMassFractions +moistAirToDryAirMassBasedProperties +dryAirToMoistAirMassBasedProperties +ddryAirMassFractions_dX +gasMixtureViscosity +lowPressureThermalConductivity diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/partialPressures.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/partialPressures.mo new file mode 100644 index 0000000000000000000000000000000000000000..3da7827cb44c8272050687e5cb2164621d115537 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/partialPressures.mo @@ -0,0 +1,71 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function partialPressures + "Returns partial pressures" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure[nX] p_i + "Partial pressures" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_sat= + saturationPressure(Tsat=state.T) + "Saturation pressure of condensing fluid (i.e., water)"; + Modelica.Units.SI.Pressure p_dryAir + "Partial pressure of dry air (i.e., without condensing component)"; + + Modelica.Units.SI.SpecificVolume v_dryAir + "Specific volume of dry air (i.e., without condensing component) related + to mass of moist air"; + +algorithm + if (state.X[nX] / (1 - state.X[nX])) > + dryMassFractionSaturation(state=state) then + p_dryAir :=state.p - p_sat + "Partial pressure of dry air (i.e., without partial pressure of water)"; + v_dryAir := sum(state.X[1:nX-1] ./ MMX[1:nX-1]) .* Modelica.Constants.R .* + state.T ./ p_dryAir + "Specific volume of dry air (i.e., without condensing component) related + to mass of moist air"; + + p_i[1:nX-1] := state.X[1:nX-1] ./ MMX[1:nX-1] .* Modelica.Constants.R .* + state.T ./ v_dryAir + "Partial pressures of non-condensing components"; + p_i[nX] := p_sat + "Partial pressures of condensing component"; + + else + p_i := state.Y .* state.p + "Partial pressures"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial pressures as function of the state record. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end partialPressures; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/pressure_dTXY.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/pressure_dTXY.mo new file mode 100644 index 0000000000000000000000000000000000000000..8380d8925c3285e0933ee54ed499d6039b0a7530 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/pressure_dTXY.mo @@ -0,0 +1,79 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function pressure_dTXY + "Returns pressure as inverse of function rho_pTXY" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Density d + "Density" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of protected funtions + // +protected + function rho_pTXY_inverse + "Function used to solve non-linear equation 0 = d(p,T,X,Y) - d" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Density d + "Density"; + input Modelica.Units.SI.Temperature T + "Pressure"; + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions"; + input Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions"; + + algorithm + y :=rho_pTXY(p=u, T=T, X=X, Y=Y) - d + "Zero point problem"; + end rho_pTXY_inverse; + +algorithm + p := Modelica.Math.Nonlinear.solveOneNonlinearEquation( + f = function rho_pTXY_inverse(d=d, T=T, X=X, Y=Y), + u_min = 1e-6, + u_max = 100*10e5, + tolerance = 100*Modelica.Constants.eps) + "Pressure"; + + // + // Annotations + // + annotation (Inline=false, InlineAfterIndexReduction=false, LateInline=true, +inverse(d=rho_pTXY(p=p, T=T, X=X, Y=Y)),Documentation(info="<html> +<p> +This function calculates the pressure of the ideal gas-vapor mixture as function +of density, temperature, mass fractions, and mole fractions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end pressure_dTXY; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/relativeHumidity.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/relativeHumidity.mo new file mode 100644 index 0000000000000000000000000000000000000000..e5d6fae7692a9f0a2f36a0f66b179c4e18a189b8 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/relativeHumidity.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function relativeHumidity + "Returns relative humidity" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Real phi(min=0, max=1) + "Relative humidity" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + +algorithm + phi := if (state.X[nX] / (1 - state.X[nX])) > + dryMassFractionSaturation(state=state) then 1 else + state.Y[nX] * state.p / saturationPressure(Tsat=state.T) + "Relative humidity"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the relative humidity as function of the state record. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end relativeHumidity; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/rho_pTXY.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/rho_pTXY.mo new file mode 100644 index 0000000000000000000000000000000000000000..46f94b62fcb579afa974ab46b0728affa3078998 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/rho_pTXY.mo @@ -0,0 +1,96 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function rho_pTXY + "Returns density of the ideal gas-vapor mixture" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Density rho + "Density" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=ThermodynamicState(p=p, T=T, X=X, Y=Y)) + "Saturation mass fraction of condensing component per dry air"; + + Modelica.Units.SI.SpecificVolume v + "Specific volume per dry air mass"; + +algorithm + // + // Calculate specific volume per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + v := sum(x[1:nX-1] ./ MMX[1:nX-1] .* Modelica.Constants.R .* T ./ p) + "Specific volume equals specific volume of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + + elseif x[nX] <= x_sat then + v := sum(x ./ MMX .* Modelica.Constants.R .* T ./ p) + "Specific volume equals specific volume of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + + elseif T > T_water_trp then + v := sum(x[1:nX-1] .* Modelica.Constants.R ./ MMX[1:nX-1] .* T ./ p) + + x_sat * Modelica.Constants.R / MMX[nX] * T / p + + (x[nX] - x_sat) * v_water_liq + "Specific volume equals specific volume of saturated dry air, water vapor, + and liquid water: Calculated applying the law of ideal gas mixtures."; + + else + v := sum(x[1:nX-1] .* Modelica.Constants.R ./ MMX[1:nX-1] .* T ./ p) + + x_sat * Modelica.Constants.R / MMX[nX] * T / p + + (x[nX] - x_sat) * v_water_solid + "Specific volume equals specific volume of saturated dry air, water vapor, + and solid water: Calculated applying the law of ideal gas mixtures."; + + end if; + + // + // Convert specific volume to density + // + rho := 1 / (v / (1 + x[nX])) + "Density of ideal gas-vapor mixture"; + + // + // Annotations + // + annotation (Inline=false, InlineAfterIndexReduction=false, LateInline=true, +inverse(p=pressure_dTXY(d=rho, T=T, X=X, Y=Y)), Documentation(info="<html> +<p> +This function calculates the density of the ideal gas-vapor mixture as function +of pressure, temperature, mass fractions, and mole fractions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end rho_pTXY; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/saturationPressureH2O_T.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/saturationPressureH2O_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..72d9d84c55271d0a70fbcc5083e35560e99b2bb2 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/saturationPressureH2O_T.mo @@ -0,0 +1,99 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function saturationPressureH2O_T + "Returns saturatation pressure of water" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_sat + "Saturation temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_sat + "Saturation pressure" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real[2] coeff_s = {-13.9281690, 34.7078238} + "Coefficients of the gas-solid boundary"; + constant Real[6] coeff_l = {-7.85951783, 1.84408259, -11.7866497, + 22.6807411, -15.9618719, 1.80122502} + "Coefficients of the gas-liquid boundary"; + + constant Real[2] exp_s = {-1.5, -1.25} + "Exponents of the gas-solid boundary"; + constant Real[6] exp_l = {1, 1.5, 3, + 3.5, 4, 7.5} + "Exponents of the gas-liquid boundary"; + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_sat_s + "Saturation pressure of gas-solid boundary"; + Modelica.Units.SI.Pressure p_sat_l + "Saturation pressure of gas-liquid boundary"; + + Real T_red_s = T_sat/T_water_trp + "Reduced temperature required for gas-solid boundary"; + Real T_red_fl = 1 - T_sat/T_water_crit + "Reduced temperature required for gas-liquid boundary"; + + Real lambda(unit="1") = SorpLib.Numerics.smoothTransition( + x=T_sat, transitionPoint=T_water_trp, transitionLength=1, noDiff=3) + "Transition factor"; + +algorithm + // + // Calculate pressures + // + p_sat_s := p_water_trp * exp(coeff_s[1] - coeff_s[1] * T_red_s ^ exp_s[1] + + coeff_s[2] - coeff_s[2] * T_red_s ^ exp_s[2]) + "Saturation pressure of gas-solid boundary"; + p_sat_l := p_water_crit * exp(T_water_crit/T_sat * + (coeff_l[1] * T_red_fl ^ exp_l[1] + + coeff_l[2] * T_red_fl ^ exp_l[2] + + coeff_l[3] * T_red_fl ^ exp_l[3] + + coeff_l[4] * T_red_fl ^ exp_l[4] + + coeff_l[5] * T_red_fl ^ exp_l[5] + + coeff_l[6] * T_red_fl ^ exp_l[6])) + "Saturation pressure of gas-liquid boundary"; + + // + // Check for boundary + // + p_sat :=lambda*p_sat_s + (1-lambda)*p_sat_l + "Saturation pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the saturation pressure of water depending on +the temperature. This functions covers both, the solid-gas and the gas- +liquid boundary. +</p> + +<h4>References</h4> +<ul> + <li> + Wagner, W. and Pruß, A (2002). The IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, Journal of Physical and Chemical Reference Data, 31:387. DOI: https://doi.org/10.1063/1.1461829. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end saturationPressureH2O_T; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEnthalpy_i.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEnthalpy_i.mo new file mode 100644 index 0000000000000000000000000000000000000000..688577721dc7215910252b4fdcf600a7ee3617cd --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEnthalpy_i.mo @@ -0,0 +1,84 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function specificEnthalpy_i + "Returns specific enthalpy of component i per component mass" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Integer ind_component + "Component index whose specific enthalpy is to be calculated" + annotation (Dialog(tab="General", group="Inputs")); + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy of component ind_component" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + +algorithm + if ind_component <> nX then + h := Modelica.Media.IdealGases.Common.Functions.h_T( + data=data[ind_component], + T=state.T, + exclEnthForm=true, + refChoice=Modelica.Media.Interfaces.Choices.ReferenceEnthalpy.UserDefined, + h_off=h_dryAir_off) + "Specific enthalpy equals specific enthalpy of dry air component"; + + elseif Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + h := 0 + "Specific enthalpy equals specific enthalpy of water but water is not + within the ideal gas-vapor mixture"; + + elseif x[nX] <= x_sat then + h := enthalpyOfCondensingGas(T=state.T) + "Specific enthalpy equals specific enthalpy of water: Unsaturated dry + air"; + + elseif state.T > T_water_trp then + h := x_sat/x[nX] * enthalpyOfCondensingGas(T=state.T) + + (x[nX]-x_sat)/x[nX] * enthalpyOfLiquid(p=state.p, T=state.T) + "Specific enthalpy equals specific enthalpy of water: Saturated dry + air with liquid water"; + + else + h := x_sat/x[nX] * enthalpyOfCondensingGas(T=state.T) + + (x[nX]-x_sat)/x[nX] * enthalpyOfSolid(p=state.p, T=state.T) + "Specific enthalpy equals specific enthalpy of water: Saturated dry + air with solid water"; + + end if; + + // + // Annotations + // + annotation(Documentation(info="<html> +<p> +This function calculates the specific enthalpy of component i per component mass. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end specificEnthalpy_i; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEnthalpy_pTXY.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEnthalpy_pTXY.mo new file mode 100644 index 0000000000000000000000000000000000000000..893ceb7a8a31d1a0109be808608b5dad67df8690 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEnthalpy_pTXY.mo @@ -0,0 +1,94 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function specificEnthalpy_pTXY + "Returns specific enthalpy of the ideal gas-vapor mixture" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=ThermodynamicState(p=p, T=T, X=X, Y=Y)) + "Saturation mass fraction of condensing component per dry air"; + +algorithm + // + // Calculate specific enthalpy per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + h := enthalpyOfNonCondensingGas(T=T, X=x) + "Specific enthalpy equals specific enthalpy of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + + elseif x[nX] <= x_sat then + h := enthalpyOfNonCondensingGas(T=T, X=x) + + x[nX] * enthalpyOfCondensingGas(T=T) + "Specific enthalpy equals specific enthalpy of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + + elseif T > T_water_trp then + h := enthalpyOfNonCondensingGas(T=T, X=x) + + x_sat * enthalpyOfCondensingGas(T=T) + + (x[nX]-x_sat) * enthalpyOfLiquid(p=p, T=T) + "Specific enthalpy equals specific enthalpy of saturated dry air, water + vapor, liquid water: Calculated applying the law of ideal gas mixtures."; + + else + h := enthalpyOfNonCondensingGas(T=T, X=x) + + x_sat * enthalpyOfCondensingGas(T=T) + + (x[nX]-x_sat) * enthalpyOfSolid(p=p, T=T) + "Specific enthalpy equals specific enthalpy of saturated dry air, water + vapor, solid water: Calculated applying the law of ideal gas mixtures."; + + end if; + + // + // Convert specific enthalpy per dry air mass + // + h := h / (1 + x[nX]) + "Specific enthalpy per moist air mass"; + + // + // Annotations + // + annotation (Inline=false, InlineAfterIndexReduction=false, LateInline=true, +inverse(T=temperature_phXY(p=p, h=h, X=X, Y=Y)),Documentation(info="<html> +<p> +This function calculates the specific enthalpy of the ideal gas-vapor mixture as +function of pressure, temperature, mass fractions, and mole fractions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end specificEnthalpy_pTXY; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEntropy_i.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEntropy_i.mo new file mode 100644 index 0000000000000000000000000000000000000000..7a5c0cc065f27545e393b95c90ea4e9a66552f88 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEntropy_i.mo @@ -0,0 +1,86 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function specificEntropy_i + "Returns specific entropy of component i per componentmass" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Integer ind_component + "Component index whose specific entropy is to be calculated" + annotation (Dialog(tab="General", group="Inputs")); + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEntropy s + "Specific entropy of component ind_component" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=state.X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=state) + "Saturation mass fraction of condensing component per dry air"; + + Modelica.Units.SI.Pressure[nX] p_i= + partialPressures(state=state) + "Partial pressures"; + +algorithm + if ind_component <> nX then + s := s_dryAir_off + Modelica.Media.IdealGases.Common.Functions.s0_T( + data=data[ind_component], T=state.T) - Modelica.Constants.R / + MMX[ind_component] * Modelica.Math.log(max(p_i[ind_component], + Modelica.Constants.eps) / reference_p) + "Specific entropy equals specific entropy of dry air component"; + + elseif Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + s := 0 + "Specific entropy equals specific entropy of water but water is not + within the ideal gas-vapor mixture"; + + elseif x[nX] <= x_sat then + s := entropyOfCondensingGas(T=state.T, p=p_i[nX]) + "Specific entropy equals specific entropy of water: Unsaturated dry + air"; + + elseif state.T > T_water_trp then + s := x_sat/x[nX] * entropyOfCondensingGas(T=state.T, p=p_i[nX]) + + (x[nX]-x_sat)/x[nX] * entropyOfLiquid(T=state.T) + "Specific entropy equals specific entropy of water: Saturated dry + air with liquid water"; + + else + s := x_sat/x[nX] * entropyOfCondensingGas(T=state.T, p=p_i[nX]) + + (x[nX]-x_sat)/x[nX] * entropyOfSolid(T=state.T) + "Specific entropy equals specific entropy of water: Saturated dry + air with solid water"; + + end if; + + // + // Annotations + // + annotation(Documentation(info="<html> +<p> +This function calculates the specific entropy of component i per component mass. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end specificEntropy_i; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEntropy_pTXY.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEntropy_pTXY.mo new file mode 100644 index 0000000000000000000000000000000000000000..a04590c94cf872e9f23c3ab64d637157de62cac3 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificEntropy_pTXY.mo @@ -0,0 +1,98 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function specificEntropy_pTXY + "Returns specific entropy of the ideal gas-vapor mixture" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEntropy s + "Specific entropy" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Modelica.Units.SI.MassFraction[nX] x= + moistAirToDryAirMassFractions(X=X) + "Mass fractions per dry air"; + Modelica.Units.SI.MassFraction x_sat= + dryMassFractionSaturation(state=ThermodynamicState(p=p, T=T, X=X, Y=Y)) + "Saturation mass fraction of condensing component per dry air"; + + Modelica.Units.SI.Pressure[nX] p_i= + partialPressures(state=ThermodynamicState(p=p, T=T, X=X, Y=Y)) + "Partial pressures"; + +algorithm + // + // Calculate specific enthalpy per dry air mass + // + if Modelica.Math.isEqual(s1=x[nX], s2=0, eps=100*Modelica.Constants.eps) then + s := entropyOfNonCondensingGas(T=T, X=x, p_i=p_i) + "Specific entropy equals specific entropy of unsaturated dry air without + water: Calculated applying the law of ideal gas mixtures."; + + elseif x[nX] <= x_sat then + s := entropyOfNonCondensingGas(T=T, X=x, p_i=p_i) + + x[nX] * entropyOfCondensingGas(T=T, p=p_i[nX]) + "Specific entropy equals specific entropy of unsaturated dry air and water + vapor: Calculated applying the law of ideal gas mixtures."; + + elseif T > T_water_trp then + s := entropyOfNonCondensingGas(T=T, X=x, p_i=p_i) + + x_sat * entropyOfCondensingGas(T=T, p=p_i[nX]) + + (x[nX]-x_sat) * entropyOfLiquid(T=T) + "Specific entropy equals specific entropy of saturated dry air, water + vapor, liquid water: Calculated applying the law of ideal gas mixtures."; + + else + s := entropyOfNonCondensingGas(T=T, X=x, p_i=p_i) + + x_sat * entropyOfCondensingGas(T=T, p=p_i[nX]) + + (x[nX]-x_sat) * entropyOfSolid(T=T) + "Specific entropy equals specific entropy of saturated dry air, water + vapor, solid water: Calculated applying the law of ideal gas mixtures."; + + end if; + + // + // Convert specific enthalpy per dry air mass + // + s := s / (1 + x[nX]) + "Specific entropy per moist air mass"; + + // + // Annotations + // + annotation (Inline=false, InlineAfterIndexReduction=false, LateInline=true, + inverse(T=temperature_psXY(p=p, s=s, X=X, Y=Y)), Documentation(info="<html> +<p> +This function calculates the specific entropy of the ideal gas-vapor mixture as +function of pressure, temperature, mass fractions, and mole fractions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end specificEntropy_pTXY; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificHeatCapacityLiquid.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificHeatCapacityLiquid.mo new file mode 100644 index 0000000000000000000000000000000000000000..0a816ad816afb68d215e87462d071c23d402c070 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificHeatCapacityLiquid.mo @@ -0,0 +1,80 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function specificHeatCapacityLiquid + "Returns specific heat capacity c of condensing component's liquid phase (per water mass)" + extends Modelica.Icons.Function; + + // + // Deifnition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Deifnition of outputs + // + output Modelica.Units.SI.SpecificHeatCapacity c + "Specific heat capacity of liquid" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real[10] coefficients= + {4.66348457415926e-19, -1.16579701193758e-15, 9.49925152355854e-13, + 5.81553479401465e-11, -6.55387915784314e-7, 5.30868446475702e-4, + -2.18234813641286e-1, 5.13043718148301e1, -6.58121774333134e3, + 3.63215816205503e5} + "Coefficients of polynomical function"; + constant Real[10] exponents= + {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} + "Exponents of polynomical function"; + +algorithm + c := SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=state.T, + T_ref=573.15, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Specific heat capacity of liquid"; + + // + // Assertations + // + if print_warnings then + assert(T_water_trp-1 <= state.T and state.T <= 573.15, + "Temperature (" + String(state.T) + " K) is not between 272.16 and 573.15 K. " + + "Calculation of specific heat capacity of liquid may not be valid!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific heat capacity of the condensing component +(i.e., water) at its liquid phase as function of the state record. The specific +heat capacity is calculated as a polynomial fit to specific heat capacity data +calculated at saturated liquid state with the reference equation of state for +water. The data was calculated for temperature varying from 273.16 K to 573.15 K. +</p> + +<h4>References</h4> +<ul> + <li> + Wagner, W. and Pruß, A (2002). The IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, Journal of Physical and Chemical Reference Data, 31:387. DOI: https://doi.org/10.1063/1.1461829. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end specificHeatCapacityLiquid; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificHeatCapacitySolid.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificHeatCapacitySolid.mo new file mode 100644 index 0000000000000000000000000000000000000000..1cacbc26fce46fa8c22b18048f59909e354af725 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificHeatCapacitySolid.mo @@ -0,0 +1,80 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function specificHeatCapacitySolid + "Returns specific heat capacity c of condensing component's solid phase (i.e., ice) (per water mass)" + extends Modelica.Icons.Function; + + // + // Deifnition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Deifnition of outputs + // + output Modelica.Units.SI.SpecificHeatCapacity c + "Specific heat capacity of ice" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real[7] coefficients= + {2.19406894387930e-11, -2.21186473219202e-8, 8.60754642146296e-6, + -1.57223901063024e-3, 1.24518779128263e-1, 5.27605328970081, + 1.18325880591863e+1} + "Coefficients of polynomical function"; + constant Real[7] exponents= + {6, 5, 4, 3, 2, 1, 0} + "Exponents of polynomical function"; + +algorithm + c := SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=state.T, + T_ref=T_water_trp, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Specific heat capacity of ice"; + + // + // Assertations + // + if print_warnings then + assert(50 <= state.T and state.T <= T_water_trp+1, + "Temperature (" + String( state.T) + " K) is not between 50 and 274.16 K. " + + "Calculation of specific heat capacity of ice may not be valid!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific heat capacity of the condensing component +(i.e., water) at its solid phase (i.e., ice) as function of the state record. The +specific heat capacity is calculated as a polynomial fit to specific heat capacity +data calculated with the reference equation of state for ice. The data was calculated +for fixed pressure (p_water_trp = 611.657 Pa) and temperature varying from 50 K +to 274.16 K. +</p> + +<h4>References</h4> +<ul> + <li> + The International Association for the Properties of Water and Steam (2009). Revised Release on the Equation of State 2006 for H2O Ice Ih. URL: https://iapws.org/relguide/Ice-2009.html. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end specificHeatCapacitySolid; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificHeatCapacityVapor.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificHeatCapacityVapor.mo new file mode 100644 index 0000000000000000000000000000000000000000..d3d5caf909fbdd02f6a8c7fa159b35523a87d257 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/specificHeatCapacityVapor.mo @@ -0,0 +1,80 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function specificHeatCapacityVapor + "Returns specific heat capacity cp of condensing component's ideal gas phase (i.e., vapor) (per water mass)" + extends Modelica.Icons.Function; + + // + // Deifnition of inputs + // + input ThermodynamicState state + "Thermodynamic state record" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Deifnition of outputs + // + output Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity of vapor" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of constants + // +protected + constant Real[10] coefficients= + {7.03241022996521e-23, -4.12454440465976e-19, 1.05640534898709e-15, + -1.54797437245421e-12, 1.42577474111776e-9, -8.51385633913246e-7, + 3.26064390458737e-4, -7.52464997116974e-2, 9.42339113729594, + 1.36103845934352e+3} + "Coefficients of polynomical function"; + constant Real[10] exponents= + {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} + "Exponents of polynomical function"; + +algorithm + cp := SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=state.T, + T_ref=T_water_crit, + z_ref=1, + coefficients=coefficients, + exponents=exponents, + approach=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature) + "Specific heat capacity of vapor"; + + // + // Assertations + // + if print_warnings then + assert(200 <= state.T and state.T <= 1000, + "Temperature (" + String(state.T) + " K) is not between 200 and 1000 K. " + + "Calculation of specific heat capacity of vapor may not be valid!", + level = AssertionLevel.warning); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific heat capacity of the condensing component +(i.e., water) at its ideal gas phase (i.e., vapor) as function of the state record. +The specific heat capacity is calculated as a polynomial fit to specific heat capacity +data calculated according to the NASA Glenn Coefficients. The data was calculated +for a temperature varying from 200 K to 1000 K. +</p> + +<h4>References</h4> +<ul> + <li> + McBride, B.J. and Zehe, M.J. and Gordon, S. (2002). NASA Glenn Coefficients for Calculating Thermodynamic Properties of Individual Species, Technical report, NASA/TP—2002-211556. URL: https://ntrs.nasa.gov/citations/20020085330. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end specificHeatCapacityVapor; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/temperature_phXY.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/temperature_phXY.mo new file mode 100644 index 0000000000000000000000000000000000000000..7d7dd22572db36e583d2de9c7b70ec10dfd23855 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/temperature_phXY.mo @@ -0,0 +1,83 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function temperature_phXY + "Returns temperature as inverse of function h_pTXY" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of protected funtions + // +protected + function h_pTXY_inverse + "Function used to solve non-linear equation 0 = h(p,T,X,Y) - h" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure"; + input Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy"; + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions"; + input Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions"; + + algorithm + y :=specificEnthalpy_pTXY( + p=p, + T=u, + X=X, + Y=Y) - h + "Zero point problem"; + end h_pTXY_inverse; + +algorithm + T := Modelica.Math.Nonlinear.solveOneNonlinearEquation( + f = function h_pTXY_inverse(p=p, h=h, X=X, Y=Y), + u_min = 200, + u_max = 573.15, + tolerance = 1e-6) + "Temperature"; + + // + // Annotations + // + annotation (Inline=false, InlineAfterIndexReduction=false, LateInline=true, + inverse(h=specificEnthalpy_pTXY(p=p, T=T, X=X, Y=Y)), Documentation(info="<html> +<p> +This function calculates the temperature of the ideal gas-vapor mixture as function +of pressure, specific enthalpy, mass fractions, and mole fractions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end temperature_phXY; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/temperature_psXY.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/temperature_psXY.mo new file mode 100644 index 0000000000000000000000000000000000000000..73b2c90849f92c7198c739178f286657ed687f58 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/PartialIdealGasWaterVaporMixture/temperature_psXY.mo @@ -0,0 +1,83 @@ +within SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture; +function temperature_psXY + "Returns temperature as inverse of function s_pTXY" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.SpecificEntropy s + "Specific entropy" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Outputs", enable=false)); + + // + // Definition of protected funtions + // +protected + function s_pTXY_inverse + "Function used to solve non-linear equation 0 = s(p,T,X,Y) - s" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure"; + input Modelica.Units.SI.SpecificEntropy s + "Specific entropy"; + input Modelica.Units.SI.MassFraction[nX] X + "Mass fractions"; + input Modelica.Units.SI.MoleFraction[nX] Y + "Mole fractions"; + + algorithm + y :=specificEntropy_pTXY( + p=p, + T=u, + X=X, + Y=Y) - s + "Zero point problem"; + end s_pTXY_inverse; + +algorithm + T := Modelica.Math.Nonlinear.solveOneNonlinearEquation( + f = function s_pTXY_inverse(p=p, s=s, X=X, Y=Y), + u_min = 200, + u_max = 573.15, + tolerance = 1e-6) + "Temperature"; + + // + // Annotations + // + annotation (Inline=false, InlineAfterIndexReduction=false, LateInline=true, + inverse(s=specificEntropy_pTXY(p=p, T=T, X=X, Y=Y)), Documentation(info="<html> +<p> +This function calculates the temperature of the ideal gas-vapor mixture as function +of pressure, specific entropy, mass fractions, and mole fractions. +</p> +</html>", revisions="<html> +<ul> + <li> + November 27, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end temperature_psXY; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/package.mo b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..7af3bfd0e389c06dcf956745dc0f329512655603 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.IdealGasVaporMixtures; +package Interfaces "Interfaces for models of ideal gas-vapor mixtures" +extends Modelica.Icons.InterfacesPackage; + +annotation (Documentation(info="<html> +<p> +This package provides definitions of basic interfaces for models +of ideal gas-vapor mixtures. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Interfaces; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Interfaces/package.order b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/package.order new file mode 100644 index 0000000000000000000000000000000000000000..d3770d96907b5fdd20cecf4d0d6e91dc7d780f3c --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Interfaces/package.order @@ -0,0 +1 @@ +PartialIdealGasWaterVaporMixture diff --git a/SorpLib/Media/IdealGasVaporMixtures/MoistAir_N2_O2_Ar_H2O/package.mo b/SorpLib/Media/IdealGasVaporMixtures/MoistAir_N2_O2_Ar_H2O/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..0f25eb83ff7e0530a500cd3bb46c715f55f86b87 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/MoistAir_N2_O2_Ar_H2O/package.mo @@ -0,0 +1,38 @@ +within SorpLib.Media.IdealGasVaporMixtures; +package MoistAir_N2_O2_Ar_H2O "SorpLib: Simple moist air consisting of N2, O2, Ar, and H2O" + extends + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture( + mediumName="MoistAir_N2_O2_Ar_H2O", + data={Modelica.Media.IdealGases.Common.SingleGasesData.N2, + Modelica.Media.IdealGases.Common.SingleGasesData.O2, + Modelica.Media.IdealGases.Common.SingleGasesData.Ar, + Modelica.Media.IdealGases.Common.SingleGasesData.H2O}, + fluidConstants={Modelica.Media.IdealGases.Common.FluidData.N2, + Modelica.Media.IdealGases.Common.FluidData.O2, + Modelica.Media.IdealGases.Common.FluidData.Ar, + Modelica.Media.IdealGases.Common.FluidData.H2O}, + substanceNames={"Nitrogen", + "Oxygen", + "Argon", + "Water"}, + final reference_X={0.7552/0.9994,0.2313/0.9994,0.0129/0.9994,1e-5}, + h_dryAir_off = 25097.2, + s_dryAir_off = -8239.74); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the fluid property of moist air modeled as ideal gas-vapor +mixture of N<sub>2</sub>, O<sub>2</sub>, Ar, and H<sub>2</sub>0. +</p> +</html>", revisions="<html> +<ul> + <li> + November 28, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MoistAir_N2_O2_Ar_H2O; diff --git a/SorpLib/Media/IdealGasVaporMixtures/MoistAir_N2_O2_Ar_H2O/package.order b/SorpLib/Media/IdealGasVaporMixtures/MoistAir_N2_O2_Ar_H2O/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGasVaporMixtures/MoistAir_N2_O2_CO2_H2O/package.mo b/SorpLib/Media/IdealGasVaporMixtures/MoistAir_N2_O2_CO2_H2O/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..750a3760c303edcf2393cc3b0ad292b168099653 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/MoistAir_N2_O2_CO2_H2O/package.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.IdealGasVaporMixtures; +package MoistAir_N2_O2_CO2_H2O "SorpLib: Simple moist air consisting of N2, O2, CO2, and H2O" + extends SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture( + mediumName="MoistAir_N2_O2_CO2_H2O", + data={Modelica.Media.IdealGases.Common.SingleGasesData.N2, + Modelica.Media.IdealGases.Common.SingleGasesData.O2, + Modelica.Media.IdealGases.Common.SingleGasesData.CO2, + Modelica.Media.IdealGases.Common.SingleGasesData.H2O}, + fluidConstants={Modelica.Media.IdealGases.Common.FluidData.N2, + Modelica.Media.IdealGases.Common.FluidData.O2, + Modelica.Media.IdealGases.Common.FluidData.CO2, + Modelica.Media.IdealGases.Common.FluidData.H2O}, + substanceNames={"Nitrogen", + "Oxygen", + "Carbondioxide", + "Water"}, + final reference_X={0.7650,0.2344,5.90e-4,1e-5}, + h_dryAir_off = 25252.5, + s_dryAir_off = -10137.3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the fluid property of moist air modeled as ideal gas-vapor +mixture of N<sub>2</sub>, O<sub>2</sub>, CO<sub>2</sub>, and H<sub>2</sub>0. +</p> +</html>", revisions="<html> +<ul> + <li> + November 28, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MoistAir_N2_O2_CO2_H2O; diff --git a/SorpLib/Media/IdealGasVaporMixtures/MoistAir_N2_O2_CO2_H2O/package.order b/SorpLib/Media/IdealGasVaporMixtures/MoistAir_N2_O2_CO2_H2O/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGasVaporMixtures/Tester/Test_MoistAir_N2_O2_Ar_H2O.mo b/SorpLib/Media/IdealGasVaporMixtures/Tester/Test_MoistAir_N2_O2_Ar_H2O.mo new file mode 100644 index 0000000000000000000000000000000000000000..c4d6479c725a72d559dfce21f1d2dbd3b3c0faba --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Tester/Test_MoistAir_N2_O2_Ar_H2O.mo @@ -0,0 +1,1023 @@ +within SorpLib.Media.IdealGasVaporMixtures.Tester; +model Test_MoistAir_N2_O2_Ar_H2O + "Tester for moist air consisting of N2, O2, Ar, and H2O" + extends Modelica.Icons.Example; + + // + // Definition of paramters + // + replaceable package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_Ar_H2O(s_dryAir_off=-6625) + constrainedby + SorpLib.Media.IdealGasVaporMixtures.Interfaces.PartialIdealGasWaterVaporMixture + "Medium" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true); + package MediumMoistAir = + Modelica.Media.Air.MoistAir(reference_X={1e-5,1-1e-5}) + "Ideal moist air" + annotation (Dialog(tab="General",group="Models and Media")); + package MediumReferenceMoistAir = + Modelica.Media.Air.ReferenceMoistAir(reference_X={1e-5,1-1e-5}) + "Reference moist air" + annotation (Dialog(tab="General",group="Models and Media")); + + parameter Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference used to calculate partial derivatives numerically" + annotation (Dialog(tab="Numerics", group="Derivatives"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculate partial derivatives numerically" + annotation (Dialog(tab="Numerics", group="Derivatives"), + Evaluate=true, + HideResult=true); + parameter Real dX = 1e-6 + "Mass fraction difference used to calculate partial derivatives numerically" + annotation (Dialog(tab="Numerics", group="Derivatives"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables regarding state properties + // + Modelica.Units.SI.Pressure p(start=150, fixed=true) + "Pressure"; + Modelica.Units.SI.Pressure p_solid(start=5, fixed=true) + "Pressure used to check solid properties"; + Modelica.Units.SI.Pressure p_liquid(start=612, fixed=true) + "Pressure used to check liquid properties"; + Modelica.Units.SI.Pressure p_vapor(start=150, fixed=true) + "Pressure used to check vaporous properties"; + + Modelica.Units.SI.Temperature T(start=223.15, fixed=true) + "Temperature"; + Modelica.Units.SI.Temperature T_solid(start=50, fixed=true) + "Temperature used to check solid properties"; + Modelica.Units.SI.Temperature T_liquid(start=273.16, fixed=true) + "Temperature used to check liquid properties"; + Modelica.Units.SI.Temperature T_vapor(start=200, fixed=true) + "Temperature used to check vapor properties"; + + Modelica.Units.SI.MassFraction[Medium.nX] X + "Mass fractions"; + Modelica.Units.SI.MassFraction[MediumMoistAir.nX] X_MoistAir + "Mass fractions"; + Modelica.Units.SI.MassFraction[MediumReferenceMoistAir.nX] X_ReferenceMoistAir + "Mass fractions"; + + Modelica.Units.SI.MassFraction[Medium.nX] x + "Mass fractions per dry air mass"; + Modelica.Units.SI.MassFraction[Medium.nX] X_from_x + "Mass fractions per moist air mass calculated from x"; + Modelica.Units.SI.MassFraction[Medium.nX] X_from_xDryAirPhi + "Mass fractions per moist air mass calculated from x of dry air components + and phi"; + + Medium.ThermodynamicState state_pTX + "State properties calculated with pressure, temperature, and composition"; + Medium.ThermodynamicState state_phX + "State properties calculated with pressure, specific enthalpy, and composition"; + Medium.ThermodynamicState state_psX + "State properties calculated with pressure, specific entropy, and composition"; + Medium.ThermodynamicState state_dTX + "State properties calculated with density, temperature, and composition"; + + Medium.BaseProperties medium_pTX + "State properties"; + MediumMoistAir.BaseProperties mediumMoistAir_pTX + "Base properties calculated with pressure, temperature, and mass fractions"; + MediumReferenceMoistAir.BaseProperties mediumReferenceMoistAir_pTX + "Base properties calculated with pressure, temperature, and mass fractions"; + + Modelica.Units.SI.MassFraction x_sat + "Saturation uptake per unit of dry air"; + Modelica.Units.SI.MassFraction x_sat_MoistAir + "Saturation uptake per unit of dry air"; + Modelica.Units.SI.MassFraction x_sat_ReferenceMoistAir + "Saturation uptake per unit of dry air"; + + Modelica.Units.SI.MassFraction X_sat + "Saturation uptake per unit of moist air"; + Modelica.Units.SI.MassFraction X_sat_MoistAir + "Saturation uptake per unit of moist air"; + Modelica.Units.SI.MassFraction X_sat_ReferenceMoistAir + "Saturation uptake per unit of moist air"; + + Modelica.Units.SI.SpecificEnthalpy h_1 + "Specific enthalpy of component 1"; + Modelica.Units.SI.SpecificEnthalpy h_last + "Specific enthalpy of last component"; + + Modelica.Units.SI.SpecificEntropy s + "Specific entropy"; + Modelica.Units.SI.SpecificEntropy s_1 + "Specific entropy of component 1"; + Modelica.Units.SI.SpecificEntropy s_last + "Specific entropy of last component"; + Modelica.Units.SI.SpecificEntropy s_MoistAir + "Specific entropy"; + Modelica.Units.SI.SpecificEntropy s_ReferenceMoistAir + "Specific entropy"; + + // + // Definition of variables regarding additional properties + // + Modelica.Units.SI.Pressure[Medium.nX] p_i + "Partial pressures"; + Modelica.Units.SI.Pressure p_water_ReferenceMoistAir + "Partial pressure of water"; + + Modelica.Media.Interfaces.Types.DynamicViscosity eta + "Dynamic viscosity"; + Modelica.Media.Interfaces.Types.DynamicViscosity eta_MoistAir + "Dynamic viscosity"; + Modelica.Media.Interfaces.Types.DynamicViscosity eta_ReferenceMoistAir + "Dynamic viscosity"; + + Modelica.Media.Interfaces.Types.ThermalConductivity lambda + "Thermal conductivity"; + Modelica.Media.Interfaces.Types.ThermalConductivity lambda_MoistAir + "Thermal conductivity"; + Modelica.Media.Interfaces.Types.ThermalConductivity lambda_ReferenceMoistAir + "Thermal conductivity"; + + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity"; + Modelica.Units.SI.SpecificHeatCapacity cp_MoistAir + "Specific heat capacity"; + Modelica.Units.SI.SpecificHeatCapacity cp_ReferenceMoistAir + "Specific heat capacity"; + + Modelica.Units.SI.SpecificHeatCapacity cv + "Specific heat capacity"; + Modelica.Units.SI.SpecificHeatCapacity cv_MoistAir + "Specific heat capacity"; + Modelica.Units.SI.SpecificHeatCapacity cv_ReferenceMoistAir + "Specific heat capacity"; + + Modelica.Media.Interfaces.Types.IsentropicExponent gamma + "Isentropic coefficient"; + Modelica.Media.Interfaces.Types.IsentropicExponent gamma_MoistAir + "Isentropic coefficient"; + Modelica.Media.Interfaces.Types.IsentropicExponent gamma_ReferenceMoistAir + "Isentropic coefficient"; + + Modelica.Units.SI.SpecificEnthalpy h_is + "Isentropic specific enthalpy"; + Modelica.Units.SI.SpecificEnthalpy h_is_MoistAir + "Isentropic specific enthalpy"; + Modelica.Units.SI.SpecificEnthalpy h_is_ReferenceMoistAir + "Isentropic specific enthalpy"; + + Modelica.Media.Interfaces.Types.VelocityOfSound w_is + "Velocity of sound"; + Modelica.Media.Interfaces.Types.VelocityOfSound w_is_MoistAir + "Velocity of sound"; + Modelica.Media.Interfaces.Types.VelocityOfSound w_is_ReferenceMoistAir + "Velocity of sound"; + + Modelica.Units.SI.RelativePressureCoefficient beta + "Isobaric expansion coefficient"; + Modelica.Units.SI.RelativePressureCoefficient beta_MoistAir + "Isobaric expansion coefficient"; + + Modelica.Units.SI.IsothermalCompressibility kappa + "Isothermal compressibility"; + Modelica.Units.SI.IsothermalCompressibility kappa_MoistAir + "Isothermal compressibility"; + + Modelica.Units.SI.SpecificEnthalpy h_dryAir + "Specific enthalpy of non-condensing components calculated for T_vapor"; + Modelica.Units.SI.SpecificEnthalpy h_dryAir_MoistAir + "Specific enthalpy of liquid water calculated for T_vapor"; + Modelica.Units.SI.SpecificEnthalpy h_dryAir_ReferenceMoistAir + "Specific enthalpy of non-condensing components calculated for T_vapor and + p_vapor"; + + Modelica.Units.SI.SpecificEnthalpy h_dryAirVapor + "Specific enthalpy of non-condensing components and vapor"; + Modelica.Units.SI.SpecificEnthalpy h_dryAirVapor_MoistAir + "Specific enthalpy of non-condensing components and vapor"; + Modelica.Units.SI.SpecificEnthalpy h_dryAirVapor_ReferenceMoistAir + "Specific enthalpy of non-condensing components and vapor"; + + // + // Definition of variables regarding partial derivatives + // + SorpLib.Units.DerSpecificVolumeByPressure dv_dp_TX + "Partial derivative of specific volume w.r.t. pressure at constant + temperature and mass fractions"; + SorpLib.Units.DerSpecificVolumeByPressure dv_dp_TX_num + "Partial derivative of specific volume w.r.t. pressure at constant + temperature and mass fractions calculated numerically"; + + SorpLib.Units.DerSpecificVolumeByTemperature dv_dT_pX + "Partial derivative of specific volume w.r.t. temperature at constant + pressure and mass fractions"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_dT_pX_num + "Partial derivative of specific volume w.r.t. temperature at constant + pressure and mass fractions calculated numerically"; + + Real[Medium.nX] dv_dX_pT(each unit="m3/kg") + "Partial derivatives of specific volume w.r.t. mass fractions at constant + pressure and temperature"; + Real[Medium.nX] dv_dX_pT_num(each unit="m3/kg") + "Partial derivatives of specific volume w.r.t. mass fractions at constant + pressure and temperature calculated numerically"; + + SorpLib.Units.DerSpecificEnthalpyByPressure dh_dp_TX + "Partial derivative of specific enthalpy w.r.t. pressure at constant + temperature and mass fractions"; + SorpLib.Units.DerSpecificEnthalpyByPressure dh_dp_TX_num + "Partial derivative of specific enthalpy w.r.t. pressure at constant + temperature and mass fractions calculated numerically"; + + Modelica.Units.SI.SpecificHeatCapacity dh_dT_pX + "Partial derivative of specific enthalpy w.r.t. temperature at constant + pressure and mass fractions"; + Modelica.Units.SI.SpecificHeatCapacity dh_dT_pX_num + "Partial derivative of specific enthalpy w.r.t. temperature at constant + pressure and mass fractions calculated numerically"; + + Real[Medium.nX] dh_dX_pT(each unit="J/kg") + "Partial derivative of specific enthalpy w.r.t. mass fractions at constant + pressure and temperature"; + Real[Medium.nX] dh_dX_pT_num(each unit="J/kg") + "Partial derivative of specific enthalpy w.r.t. mass fractions at constant + pressure and temperature calculated numerically"; + + Modelica.Media.Interfaces.Types.DerDensityByPressure drho_dp_hX + "Partial derivative of density w.r.t. pressure at constant specific enthalpy + and mass fractions"; + Modelica.Media.Interfaces.Types.DerDensityByPressure drho_dp_hX_MoistAir + "Partial derivative of density w.r.t. pressure at constant specific enthalpy + and mass fractions"; + + Modelica.Media.Interfaces.Types.DerDensityByEnthalpy drho_dh_pX + "Partial derivative of density w.r.t. specific enthalpy at constant pressure + and mass fractions"; + Modelica.Media.Interfaces.Types.DerDensityByEnthalpy drho_dh_pX_MoistAir + "Partial derivative of density w.r.t. specific enthalpy at constant pressure + and mass fractions"; + + Real[Medium.nX] drho_dX_ph(each unit="kg.kg/(m3.kg)") + "Partial derivative of density w.r.t. mass fractions at constant pressure + and specific enthalpy"; + Real[Medium.nX] drho_dX_ph_num(each unit="kg.kg/(m3.kg)") + "Partial derivative of density w.r.t. mass fractions at constant pressure + and specific enthalpy calculated numerically"; + + Modelica.Media.Interfaces.Types.DerDensityByPressure drho_dp_TX + "Partial derivative of density w.r.t. pressure at constant temperature and + mass fractions"; + Modelica.Media.Interfaces.Types.DerDensityByPressure drho_dp_TX_MoistAir + "Partial derivative of density w.r.t. pressure at constant temperature and + mass fractions"; + + Modelica.Media.Interfaces.Types.DerDensityByTemperature drho_dT_pX + "Partial derivative of density w.r.t. pressure at constant temperature and + mass fractions"; + Modelica.Media.Interfaces.Types.DerDensityByTemperature drho_dT_pX_MoistAir + "Partial derivative of density w.r.t. pressure at constant temperature and + mass fractions"; + + Real[Medium.nX] drho_dX_pT(each unit="kg.kg/(m3.kg)") + "Partial derivative of density w.r.t. mass fractions at constant pressure + and temperature"; + Real[Medium.nX] drho_dX_pT_num(each unit="kg.kg/(m3.kg)") + "Partial derivative of density w.r.t. mass fractions at constant pressure + and temperature calculated numerically"; + + // + // Definition of variables regarding condensing component + // + Modelica.Units.SI.Pressure p_sat + "Saturation pressure of water"; + Modelica.Units.SI.Pressure p_sat_MoistAir + "Saturation pressure of water"; + Modelica.Units.SI.Pressure p_sat_ReferenceMoistAir + "Saturation pressure of water"; + + Modelica.Units.SI.Temperature T_sat_p_sat + "Saturation temperature of water at saturation pressure of water"; + + Modelica.Units.SI.SpecificHeatCapacity c_solid + "Specific heat capacity of ice calculated fot T_solid"; + Modelica.Units.SI.SpecificHeatCapacity c_liquid + "Specific heat capacity of ice calculated fot T_liquid"; + Modelica.Units.SI.SpecificHeatCapacity cp_vapor + "Specific heat capacity of vapor calculated for T_vapor"; + + Modelica.Units.SI.SpecificEnthalpy dh_vap + "Specific enthalpy of vaporization calculated for T_liquid"; + Modelica.Units.SI.SpecificEnthalpy dh_vap_MoistAir + "Specific enthalpy of vaporization calculated for T_liquid"; + Modelica.Units.SI.SpecificEnthalpy dh_vap_ReferenceMoistAir + "Specific enthalpy of vaporization calculated for T_liquid and p_liquid"; + + Modelica.Units.SI.SpecificEnthalpy h_solid + "Specific enthalpy of solid water calculated for T_solid and p_solid"; + Modelica.Units.SI.SpecificEnthalpy h_solid_MoistAir + "Specific enthalpy of solid water calculated for T_solid"; + Modelica.Units.SI.SpecificEnthalpy h_solid_ReferenceMoistAir + "Specific enthalpy of solid water calculated for T_solid and p_solid"; + + Modelica.Units.SI.SpecificEnthalpy h_liquid + "Specific enthalpy of liquid water calculated for T_liquid and p_liquid"; + Modelica.Units.SI.SpecificEnthalpy h_liquid_MoistAir + "Specific enthalpy of liquid water calculated for T_liquid"; + Modelica.Units.SI.SpecificEnthalpy h_liquid_ReferenceMoistAir + "Specific enthalpy of liquid water calculated for T_liquid and p_liquid"; + + Modelica.Units.SI.SpecificEnthalpy h_vapor + "Specific enthalpy of vaporous water calculated for T_vapor"; + Modelica.Units.SI.SpecificEnthalpy h_vapor_MoistAir + "Specific enthalpy of vaporous water calculated for T_vapor"; + Modelica.Units.SI.SpecificEnthalpy h_vapor_ReferenceMoistAir + "Specific enthalpy of vaporous water calculated for T_vapor and p_vapor"; + + Modelica.Units.SI.SpecificEnthalpy h_water + "Specific enthalpy of whole water"; + Modelica.Units.SI.SpecificEnthalpy h_solidLiquid_water + "Specific enthalpy of solid or liquid water"; + Modelica.Units.SI.SpecificEnthalpy h_vapor_water + "Specific enthalpy of vaporous water"; + + // + // Definition of protected variables + // +protected + Modelica.Units.SI.MassFraction X_water + "Mass fraction of water"; + Modelica.Units.SI.MassFraction X_dryAir + "Mass fraction of dry air (i.e., without water)"; + + Medium.ThermodynamicState state_pdp + "Thermodynamic state: p + dp"; + Medium.ThermodynamicState state_mdp + "Thermodynamic state: p - dp"; + + Medium.ThermodynamicState state_pdT + "Thermodynamic state: T + dT"; + Medium.ThermodynamicState state_mdT + "Thermodynamic state: T - dT"; + + // + // Definitio of parameters correcting reference states + // + parameter Modelica.Units.SI.SpecificEnthalpy dh_MoistAir= + Medium.specificEnthalpy( + state=Medium.ThermodynamicState( + p=Medium.p_water_ref, + T=Medium.T_water_ref, + X=Medium.reference_X, + Y=Medium.massToMoleFractions(X=Medium.reference_X, MMX=Medium.MMX))) - + MediumMoistAir.specificEnthalpy( + state=MediumMoistAir.ThermodynamicState( + p=Medium.p_water_ref, + T=Medium.T_water_ref, + X={Medium.reference_X[Medium.nX],1-Medium.reference_X[Medium.nX]})) + "Difference of reference points: Ideal gas-vapor mixture"; + parameter Modelica.Units.SI.SpecificEnthalpy dh_ReferenceMoistAir= + Medium.specificEnthalpy( + state=Medium.ThermodynamicState( + p=Medium.p_water_ref, + T=Medium.T_water_ref, + X=Medium.reference_X, + Y=Medium.massToMoleFractions(X=Medium.reference_X, MMX=Medium.MMX))) - + MediumReferenceMoistAir.specificEnthalpy( + state=MediumReferenceMoistAir.ThermodynamicState( + p=Medium.p_water_ref, + T=Medium.T_water_ref, + X={Medium.reference_X[Medium.nX],1-Medium.reference_X[Medium.nX]})) + "Difference of reference points: Ideal gas-vapor mixture"; + + parameter Modelica.Units.SI.SpecificEntropy ds_MoistAir= + Medium.specificEntropy( + state=Medium.ThermodynamicState( + p=Medium.p_water_ref, + T=Medium.T_water_ref, + X=Medium.reference_X, + Y=Medium.massToMoleFractions(X=Medium.reference_X, MMX=Medium.MMX))) - + MediumMoistAir.specificEntropy( + state=MediumMoistAir.ThermodynamicState( + p=Medium.p_water_ref, + T=Medium.T_water_ref, + X={Medium.reference_X[Medium.nX],1-Medium.reference_X[Medium.nX]})) + "Difference of reference points: Ideal gas-vapor mixture"; + parameter Modelica.Units.SI.SpecificEntropy ds_ReferenceMoistAir= + Medium.specificEntropy( + state=Medium.ThermodynamicState( + p=Medium.p_water_ref, + T=Medium.T_water_ref, + X=Medium.reference_X, + Y=Medium.massToMoleFractions(X=Medium.reference_X, MMX=Medium.MMX))) - + MediumReferenceMoistAir.specificEntropy( + state=MediumReferenceMoistAir.ThermodynamicState( + p=Medium.p_water_ref, + T=Medium.T_water_ref, + X={Medium.reference_X[Medium.nX],1-Medium.reference_X[Medium.nX]})) + "Difference of reference points: Ideal gas-vapor mixture"; + + parameter Modelica.Units.SI.SpecificEnthalpy dh_dryAir_MoistAir= + Medium.enthalpyOfNonCondensingGas( + T=Medium.T_water_ref, + X=Medium.reference_X) - + MediumMoistAir.enthalpyOfNonCondensingGas( + T=Medium.T_water_ref) + "Difference of reference points: Ideal gas mixture of dry gas"; + parameter Modelica.Units.SI.SpecificEnthalpy dh_dryAir_ReferenceMoistAir= + Medium.enthalpyOfNonCondensingGas( + T=Medium.T_water_ref, + X=Medium.reference_X) - + MediumReferenceMoistAir.enthalpyOfNonCondensingGas( + state=MediumReferenceMoistAir.ThermodynamicState( + p=Medium.p_water_ref, + T=Medium.T_water_ref, + X={Medium.reference_X[Medium.nX],1-Medium.reference_X[Medium.nX]})) + "Difference of reference points: Ideal gas mixture of dry gas"; + +equation + // + // Change independent state variables + // + der(p) = (90e5 - 150) / 20 + "Predescribed slope of pressure"; + der(p_solid) = (90e5 - 5) / 20 + "Predescribed slope of pressure used to check solid properties"; + der(p_liquid) = (90e5 - 612) / 20 + "Predescribed slope of pressure used to check liquid properties"; + der(p_vapor) = (90e5 - 150) / 20 + "Predescribed slope of pressure used to check vaporous properties"; + + der(T) = (563.15 - 223.15) / 20 + "Predescribed slope of temperature"; + der(T_solid) = (273.16 - 50) / 20 + "Predescribed slope of temperature used to check solid properties"; + der(T_liquid) = (573.15 - 273.16) / 20 + "Predescribed slope of temperature used to check liquid properties"; + der(T_vapor) = (1000 - 200) / 20 + "Predescribed slope of temperature used to check vapor properties"; + + X_water = 0.5 + 0.5 * Modelica.Math.sin(2*Modelica.Constants.pi * 1/5 * time) + "Mass fraction of water"; + X_dryAir = 1 - X_water + "Mass fraction of dry air (i.e., without water)"; + + X = cat( + 1, + Medium.reference_X[1:end-1] ./ sum(Medium.reference_X[1:end-1]) * X_dryAir, + {X_water}) + "Mass fractions"; + X_MoistAir = {X_water, X_dryAir} + "Mass fractions"; + X_ReferenceMoistAir = {X_water, X_dryAir} + "Mass fractions"; + + x = Medium.moistAirToDryAirMassFractions(X=X) + "Mass fractions per dry air mass"; + X_from_x = Medium.dryAirToMoistAirMassFractions(x=x) + "Mass fractions per moist air mass calculated from x"; + X_from_xDryAirPhi = + Medium.massFractions_pTxDryPhi(p=p, T=T, x=x[1:end-1], phi=medium_pTX.phi) + "Mass fractions per moist air mass calculated from x of dry air components + and phi"; + + // + // Calculate state variables + // + state_pdp = Medium.setState_pTX(p=p+dp, T=T, X=X) + "Thermodynamic state: p + dp"; + state_mdp = Medium.setState_pTX(p=p-dp, T=T, X=X) + "Thermodynamic state: p - dp"; + + state_pdT = Medium.setState_pTX(p=p, T=T+dT, X=X) + "Thermodynamic state: T + dT"; + state_mdT = Medium.setState_pTX(p=p, T=T-dT, X=X) + "Thermodynamic state: T - dT"; + + state_pTX = Medium.setState_pTX(p=p, T=T, X=X) + "State properties calculated with pressure, temperature, and composition"; + state_phX = Medium.setState_phX(p=p, h=medium_pTX.h, X=X) + "State properties calculated with pressure, specific enthalpy, and composition"; + state_psX = Medium.setState_psX(p=p, s=s, X=X) + "State properties calculated with pressure, specific entropy, and composition"; + state_dTX = Medium.setState_dTX(d=medium_pTX.d, T=T, X=X) + "State properties calculated with density, temperature, and composition"; + + medium_pTX.p = p + "Base properties calculated with pressure and temperature"; + medium_pTX.T = T + "Base properties calculated with pressure and temperature"; + medium_pTX.X[1:end-1] = X[1:end-1] + "Base properties calculated with pressure and temperature"; + + mediumMoistAir_pTX.p = p + "Base properties calculated with pressure and temperature"; + mediumMoistAir_pTX.T = T + "Base properties calculated with pressure and temperature"; + mediumMoistAir_pTX.X[1] = X_MoistAir[1] + "Base properties calculated with pressure and temperature"; + + mediumReferenceMoistAir_pTX.p = p + "Base properties calculated with pressure and temperature"; + mediumReferenceMoistAir_pTX.T = T + "Base properties calculated with pressure and temperature"; + mediumReferenceMoistAir_pTX.X[1] = X_ReferenceMoistAir[1] + "Base properties calculated with pressure and temperature"; + + x_sat = + Medium.dryMassFractionSaturation(state=medium_pTX.state) + "Saturation uptake per unit of dry air"; + x_sat_MoistAir = + MediumMoistAir.xsaturation(state=mediumMoistAir_pTX.state) + "Saturation uptake per unit of dry air"; + x_sat_ReferenceMoistAir= + MediumReferenceMoistAir.xsaturation( + state=mediumReferenceMoistAir_pTX.state) + "Saturation uptake per unit of dry air"; + + X_sat = + Medium.massFractionSaturation(state=medium_pTX.state) + "Saturation uptake per unit of moist air"; + X_sat_MoistAir = + MediumMoistAir.Xsaturation(state=mediumMoistAir_pTX.state) + "Saturation uptake per unit of moist air"; + X_sat_ReferenceMoistAir= + MediumReferenceMoistAir.Xsaturation( + state=mediumReferenceMoistAir_pTX.state) + "Saturation uptake per unit of moist air"; + + h_1 = + Medium.specificEnthalpy_i(ind_component=1, state=medium_pTX.state) + "Specific enthalpy of component 1"; + h_last = + Medium.specificEnthalpy_i(ind_component=Medium.nX, state=medium_pTX.state) + "Specific enthalpy of last component"; + + s = + Medium.specificEntropy(state=medium_pTX.state) + "Specific entropy"; + s_1 = + Medium.specificEntropy_i(ind_component=1, state=medium_pTX.state) + "Specific entropy of component 1"; + s_last = + Medium.specificEntropy_i(ind_component=Medium.nX, state=medium_pTX.state) + "Specific entropy of last component"; + s_MoistAir = + MediumMoistAir.specificEntropy(state=mediumMoistAir_pTX.state) + + ds_MoistAir + "Specific entropy"; + s_ReferenceMoistAir = + MediumReferenceMoistAir.specificEntropy( + state=mediumReferenceMoistAir_pTX.state) + + ds_ReferenceMoistAir + "Specific entropy"; + + // + // Calculate further properties + // + p_i = Medium.partialPressures(state=medium_pTX.state) + "Partial pressures"; + p_water_ReferenceMoistAir = MediumReferenceMoistAir.Utilities.pd_pTX( + p=mediumReferenceMoistAir_pTX.state.p, + T=mediumReferenceMoistAir_pTX.state.T, + X=mediumReferenceMoistAir_pTX.state.X) + "Partial pressure of water"; + + eta = + Medium.dynamicViscosity(state=medium_pTX.state) + "Dynamic viscosity"; + eta_MoistAir = + MediumMoistAir.dynamicViscosity(state=mediumMoistAir_pTX.state) + "Dynamic viscosity"; + eta_ReferenceMoistAir = + MediumReferenceMoistAir.dynamicViscosity( + state=mediumReferenceMoistAir_pTX.state) + "Dynamic viscosity"; + + lambda = + Medium.thermalConductivity(state=medium_pTX.state) + "Thermal conductivity"; + lambda_MoistAir = + MediumMoistAir.thermalConductivity(state=mediumMoistAir_pTX.state) + "Thermal conductivity"; + lambda_ReferenceMoistAir = + MediumReferenceMoistAir.thermalConductivity( + state=mediumReferenceMoistAir_pTX.state) + "Thermal conductivity"; + + cp = + Medium.specificHeatCapacityCp(state=medium_pTX.state) + "Specific heat capacity"; + cp_MoistAir = + MediumMoistAir.specificHeatCapacityCp(state=mediumMoistAir_pTX.state) + "Specific heat capacity"; + cp_ReferenceMoistAir = + MediumReferenceMoistAir.specificHeatCapacityCp( + state=mediumReferenceMoistAir_pTX.state) + "Specific heat capacity"; + + cv = + Medium.specificHeatCapacityCv(state=medium_pTX.state) + "Specific heat capacity"; + cv_MoistAir = + MediumMoistAir.specificHeatCapacityCv(state=mediumMoistAir_pTX.state) + "Specific heat capacity"; + cv_ReferenceMoistAir = + MediumReferenceMoistAir.specificHeatCapacityCv( + state=mediumReferenceMoistAir_pTX.state) + "Specific heat capacity"; + + gamma = + Medium.isentropicExponent(state=medium_pTX.state) + "Isentropic coefficient"; + gamma_MoistAir= + MediumMoistAir.isentropicExponent(state=mediumMoistAir_pTX.state) + "Isentropic coefficient"; + gamma_ReferenceMoistAir= + MediumReferenceMoistAir.isentropicExponent( + state=mediumReferenceMoistAir_pTX.state) + "Isentropic coefficient"; + + h_is = + Medium.isentropicEnthalpy( + p_downstream=p, refState=medium_pTX.state) + "Isentropic specific enthalpy"; + h_is_MoistAir = + MediumMoistAir.isentropicEnthalpy( + p_downstream=p, refState=mediumMoistAir_pTX.state) + + dh_MoistAir + "Isentropic specific enthalpy"; + h_is_ReferenceMoistAir = + MediumReferenceMoistAir.isentropicEnthalpy( + p_downstream=p, refState=mediumReferenceMoistAir_pTX.state)+ + dh_ReferenceMoistAir + "Isentropic specific enthalpy"; + + w_is = + Medium.velocityOfSound( + state=medium_pTX.state) + "Velocity of sound"; + w_is_MoistAir = + MediumMoistAir.velocityOfSound( + state=mediumMoistAir_pTX.state) + "Velocity of sound"; + w_is_ReferenceMoistAir = + MediumReferenceMoistAir.velocityOfSound( + state=mediumReferenceMoistAir_pTX.state) + "Velocity of sound"; + + beta = + Medium.beta(state=medium_pTX.state) + "Isobaric expansion coefficient"; + beta_MoistAir = + MediumMoistAir.beta(state=mediumMoistAir_pTX.state) + "Isobaric expansion coefficient"; + + kappa = + Medium.kappa(state=medium_pTX.state) + "Isothermal compressibility"; + kappa_MoistAir = + MediumMoistAir.kappa(state=mediumMoistAir_pTX.state) + "Isothermal compressibility"; + + h_dryAir = + Medium.enthalpyOfNonCondensingGas( + T=T_vapor, + X=X) + "Specific enthalpy of non-condensing components calculated for T_vapor"; + h_dryAir_MoistAir = + MediumMoistAir.enthalpyOfNonCondensingGas(T=T_vapor) + + dh_dryAir_MoistAir + "Specific enthalpy of liquid water calculated for T_vapor"; + h_dryAir_ReferenceMoistAir = + MediumReferenceMoistAir.enthalpyOfNonCondensingGas( + state=MediumReferenceMoistAir.ThermodynamicState( + p=p_vapor, + T=T_vapor, + X=X_ReferenceMoistAir)) + + dh_dryAir_ReferenceMoistAir + "Specific enthalpy of non-condensing components calculated for T_vapor and + p_vapor"; + + h_dryAirVapor = + Medium.enthalpyOfGas(state=medium_pTX.state) + "Specific enthalpy of non-condensing components and vapor"; + h_dryAirVapor_MoistAir = + MediumMoistAir.enthalpyOfGas( + T=T, + X=X_MoistAir) + + dh_MoistAir + "Specific enthalpy of non-condensing components and vapor"; + h_dryAirVapor_ReferenceMoistAir = + MediumReferenceMoistAir.enthalpyOfGas( + state=mediumReferenceMoistAir_pTX.state) / + (1 + X_ReferenceMoistAir[1] / (1 - X_ReferenceMoistAir[1])) + + dh_ReferenceMoistAir + "Specific enthalpy of non-condensing components and vapor"; + + // + // Calculate partial derivatives + // + dv_dp_TX = Medium.dv_dp_TX(state=medium_pTX.state) + "Partial derivative of specific volume w.r.t. pressure at constant + temperature and mass fractions"; + dv_dp_TX_num = -1/medium_pTX.d^2 * + ((Medium.density(state=state_pdp) - + Medium.density(state=state_mdp)) / (2*dp)) + "Partial derivative of specific volume w.r.t. pressure at constant + temperature and mass fractions calculated numerically"; + + dv_dT_pX = Medium.dv_dT_pX(state=medium_pTX.state) + "Partial derivative of specific volume w.r.t. temperature at constant + pressure and mass fractions"; + dv_dT_pX_num = -1/medium_pTX.d^2 * + ((Medium.density(state=state_pdT) - + Medium.density(state=state_mdT)) / (2*dT)) + "Partial derivative of specific volume w.r.t. temperature at constant + pressure and mass fractions calculated numerically"; + + dv_dX_pT = Medium.dv_dX_pT(state=medium_pTX.state) + "Partial derivatives of specific volume w.r.t. mass fractions at constant + pressure and temperature"; + for ind in 1:Medium.nX loop + dv_dX_pT_num[ind] = -1/medium_pTX.d^2 * + ((Medium.density( + state=Medium.setState_pTX( + p=p, + T=T, + X=cat(1, + X[1:ind-1], + {X[ind] + dX}, + X[ind+1:Medium.nX]))) - + Medium.density( + state=Medium.setState_pTX( + p=p, + T=T, + X=cat(1, + X[1:ind-1], + {X[ind] - dX}, + X[ind+1:Medium.nX])))) / (2*dX)) + "Partial derivatives of specific volume w.r.t. mass fractions at constant + pressure and temperature calculated numerically"; + end for; + + dh_dp_TX = Medium.dh_dp_TX(state=medium_pTX.state) + "Partial derivative of specific enthalpy w.r.t. pressure at constant + temperature and mass fractions"; + dh_dp_TX_num = (Medium.specificEnthalpy(state=state_pdp) - + Medium.specificEnthalpy(state=state_mdp)) / (2*dp) + "Partial derivative of specific enthalpy w.r.t. pressure at constant + temperature and mass fractions calculated numerically"; + + dh_dT_pX = Medium.dh_dT_pX(state=medium_pTX.state) + "Partial derivative of specific enthalpy w.r.t. temperature at constant + pressure and mass fractions"; + dh_dT_pX_num = (Medium.specificEnthalpy(state=state_pdT) - + Medium.specificEnthalpy(state=state_mdT)) / (2*dT) + "Partial derivative of specific enthalpy w.r.t. temperature at constant + pressure and mass fractions calculated numerically"; + + dh_dX_pT = Medium.dh_dX_pT(state=medium_pTX.state) + "Partial derivative of specific enthalpy w.r.t. mass fractions at constant + pressure and temperature"; + for ind in 1:Medium.nX loop + dh_dX_pT_num[ind] = + (Medium.specificEnthalpy( + state=Medium.setState_pTX( + p=p, + T=T, + X=cat(1, + X[1:ind-1], + {X[ind] + dX}, + X[ind+1:Medium.nX]))) - + Medium.specificEnthalpy( + state=Medium.setState_pTX( + p=p, + T=T, + X=cat(1, + X[1:ind-1], + {X[ind] - dX}, + X[ind+1:Medium.nX]))))/ (2*dX) + "Partial derivative of specific enthalpy w.r.t. mass fractions at constant + pressure and temperature calculated numerically"; + end for; + + drho_dp_hX = + Medium.density_derp_h(state=medium_pTX.state) + "Partial derivative of density w.r.t. pressure at constant specific enthalpy + and mass fractions"; + drho_dp_hX_MoistAir = + MediumMoistAir.density_derp_h(state=mediumMoistAir_pTX.state) + "Partial derivative of density w.r.t. pressure at constant specific enthalpy + and mass fractions"; + + drho_dh_pX = + Medium.density_derh_p(state=medium_pTX.state) + "Partial derivative of density w.r.t. specific enthalpy at constant pressure + and mass fractions"; + drho_dh_pX_MoistAir = + MediumMoistAir.density_derh_p(state=mediumMoistAir_pTX.state) + "Partial derivative of density w.r.t. specific enthalpy at constant pressure + and mass fractions"; + + drho_dX_ph = Medium.drho_dX_ph(state=medium_pTX.state) + "Partial derivative of density w.r.t. mass fractions at constant pressure + and specific enthalpy"; + for ind in 1:Medium.nX loop + drho_dX_ph_num[ind] = + ((Medium.density( + state=Medium.setState_phX( + p=p, + h=medium_pTX.h, + X=cat(1, + X[1:ind-1], + {X[ind] + dX}, + X[ind+1:Medium.nX]))) - + Medium.density( + state=Medium.setState_phX( + p=p, + h=medium_pTX.h, + X=cat(1, + X[1:ind-1], + {X[ind] - dX}, + X[ind+1:Medium.nX])))) / (2*dX)) + "Partial derivative of density w.r.t. mass fractions at constant pressure + and specific enthalpy calculated numerically"; + end for; + + drho_dp_TX = + Medium.density_derp_T(state=medium_pTX.state) + "Partial derivative of density w.r.t. pressure at constant temperature and + mass fractions"; + drho_dp_TX_MoistAir = + MediumMoistAir.density_derp_T(state=mediumMoistAir_pTX.state) + "Partial derivative of density w.r.t. pressure at constant temperature and + mass fractions"; + + drho_dT_pX = + Medium.density_derT_p(state=medium_pTX.state) + "Partial derivative of density w.r.t. pressure at constant temperature and + mass fractions"; + drho_dT_pX_MoistAir= + MediumMoistAir.density_derT_p(state=mediumMoistAir_pTX.state) + "Partial derivative of density w.r.t. pressure at constant temperature and + mass fractions"; + + drho_dX_pT = + Medium.density_derX(state=medium_pTX.state) + "Partial derivative of density w.r.t. mass fractions at constant pressure + and temperature"; + for ind in 1:Medium.nX loop + drho_dX_pT_num[ind] = + ((Medium.density( + state=Medium.setState_pTX( + p=p, + T=T, + X=cat(1, + X[1:ind-1], + {X[ind] + dX}, + X[ind+1:Medium.nX]))) - + Medium.density( + state=Medium.setState_pTX( + p=p, + T=T, + X=cat(1, + X[1:ind-1], + {X[ind] - dX}, + X[ind+1:Medium.nX])))) / (2*dX)) + "Partial derivatives of density w.r.t. mass fractions at constant + pressure and temperature calculated numerically"; + end for; + + // + // Calculate properties regarding condensing component + // + p_sat = + Medium.saturationPressure(Tsat=T) + "Saturation pressure of water"; + p_sat_MoistAir = + MediumMoistAir.saturationPressure(Tsat=T) + "Saturation pressure of water"; + p_sat_ReferenceMoistAir= + MediumReferenceMoistAir.saturationPressure( + state=mediumReferenceMoistAir_pTX.state) + "Saturation pressure of water"; + + T_sat_p_sat = + Medium.saturationTemperature(p_sat=p_sat) + "Saturation temperature of water at saturation pressure of water"; + + c_solid = + Medium.specificHeatCapacitySolid(state=Medium.ThermodynamicState( + p=p_solid, + T=T_solid, + X=medium_pTX.state.X, + Y=medium_pTX.state.Y)) + "Specific heat capacity of solid calculated for T_solid and p_solid"; + c_liquid = + Medium.specificHeatCapacityLiquid(state=Medium.ThermodynamicState( + p=p_liquid, + T=T_liquid, + X=medium_pTX.state.X, + Y=medium_pTX.state.Y)) + "Specific heat capacity of liquid calculated for T_liquid and p_liquid"; + cp_vapor = + Medium.specificHeatCapacityVapor(state=Medium.ThermodynamicState( + p=p_vapor, + T=T_vapor, + X=medium_pTX.state.X, + Y=medium_pTX.state.Y)) + "Specific heat capacity of vapor calculated for T_vapor and p_vapor"; + + dh_vap = + Medium.enthalpyOfVaporization(T=T_liquid) + "Specific enthalpy of vaporization calculated for T_liquid"; + dh_vap_MoistAir = + MediumMoistAir.enthalpyOfVaporization(T=T_liquid) + "Specific enthalpy of vaporization calculated for T_liquid"; + dh_vap_ReferenceMoistAir= + MediumReferenceMoistAir.enthalpyOfVaporization( + state=MediumReferenceMoistAir.ThermodynamicState( + p=p_liquid, + T=T_liquid, + X=X_ReferenceMoistAir)) + "Specific enthalpy of vaporization calculated for T_liquid and p_liquid"; + + h_solid = + Medium.enthalpyOfSolid( + p=p_solid, + T=T_solid) + "Specific enthalpy of solid water calculated for T_solid and p_solid"; + h_solid_MoistAir = + MediumMoistAir.enthalpyOfWater(T=T_solid) + "Specific enthalpy of solid water calculated for T_solid"; + h_solid_ReferenceMoistAir = + MediumReferenceMoistAir.Utilities.Ice09_Utilities.h_pT( + p=p_solid, + T=T_solid) + "Specific enthalpy of solid water calculated for T_solid and p_solid"; + + h_liquid = + Medium.enthalpyOfLiquid( + p=p_liquid, + T=T_liquid) + "Specific enthalpy of liquid water calculated for T_liquid and p_liquid"; + h_liquid_MoistAir = + MediumMoistAir.enthalpyOfWater(T=T_liquid) + "Specific enthalpy of liquid water calculated for T_liquid"; + h_liquid_ReferenceMoistAir= + Modelica.Media.Water.IF97_Utilities.h_pT( + p=p_liquid, + T=T_liquid, + region=1) + "Specific enthalpy of liquid water calculated for T_liquid and p_liquid"; + + h_vapor = + Medium.enthalpyOfCondensingGas(T=T_vapor) + "Specific enthalpy of vaporous water calculated for T_vapor"; + h_vapor_MoistAir = + MediumMoistAir.enthalpyOfCondensingGas(T=T_vapor) + "Specific enthalpy of vaporous water calculated for T_vapor"; + h_vapor_ReferenceMoistAir= + MediumReferenceMoistAir.enthalpyOfCondensingGas( + state=MediumReferenceMoistAir.ThermodynamicState( + p=p_vapor, + T=T_vapor, + X=X_ReferenceMoistAir)) / + (X_ReferenceMoistAir[1] / (1 - X_ReferenceMoistAir[1])) + "Specific enthalpy of vaporous water calculated for T_vapor and p_vapor"; + + h_water = + Medium.enthalpyOfCondensingComponent(state=medium_pTX.state) + "Specific enthalpy of whole water"; + h_solidLiquid_water = + Medium.enthalpyOfLiquidIce(state=medium_pTX.state) + "Specific enthalpy of solid or liquid water"; + h_vapor_water = + Medium.enthalpyOfVapor(state=medium_pTX.state) + "Specific enthalpy of vaporous water"; + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal gas-vapor mixture +of N<sub>2</sub>, O<sub>2</sub>, Ar, and H<sub>2</sub>O. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 28, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_MoistAir_N2_O2_Ar_H2O; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Tester/Test_MoistAir_N2_O2_CO2_H2O.mo b/SorpLib/Media/IdealGasVaporMixtures/Tester/Test_MoistAir_N2_O2_CO2_H2O.mo new file mode 100644 index 0000000000000000000000000000000000000000..031ab1c0cbe4506aee0309bcca126f3575f78ded --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Tester/Test_MoistAir_N2_O2_CO2_H2O.mo @@ -0,0 +1,28 @@ +within SorpLib.Media.IdealGasVaporMixtures.Tester; +model Test_MoistAir_N2_O2_CO2_H2O + "Tester for moist air consisting of N2, O2, CO2, and H2O" + extends SorpLib.Media.IdealGasVaporMixtures.Tester.Test_MoistAir_N2_O2_Ar_H2O( + redeclare package Medium = + SorpLib.Media.IdealGasVaporMixtures.MoistAir_N2_O2_CO2_H2O(s_dryAir_off=-6625)); + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal gas-vapor mixture +of N<sub>2</sub>, O<sub>2</sub>, CO<sub>2</sub>, and H<sub>2</sub>O. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 28, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_MoistAir_N2_O2_CO2_H2O; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Tester/package.mo b/SorpLib/Media/IdealGasVaporMixtures/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..cde30da003871e7ada0e9936455a9f0a74e8786d --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.IdealGasVaporMixtures; +package Tester "Package containing testers to test and varify models calculating fluid property data of ideal gas mixtures" + extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented fluid +property models of ideal gas-vapor mixtures. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Media/IdealGasVaporMixtures/Tester/package.order b/SorpLib/Media/IdealGasVaporMixtures/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..cea5a475b277f680d221f0e9cf53678a2eba4b51 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/Tester/package.order @@ -0,0 +1,2 @@ +Test_MoistAir_N2_O2_Ar_H2O +Test_MoistAir_N2_O2_CO2_H2O diff --git a/SorpLib/Media/IdealGasVaporMixtures/package.mo b/SorpLib/Media/IdealGasVaporMixtures/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..69100d112c8a75ceea6faafb4e608c4bf5240afa --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/package.mo @@ -0,0 +1,25 @@ +within SorpLib.Media; +package IdealGasVaporMixtures "Package containing medium models of ideal gas-vapor mixtures" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains models of ideal gas-vapor mixtures. These models are based +on the Modelica Standard Library but extended by new functions required in +SorpLib. Note that the reference temperature must be 0 K and the reference +enthalpy and entropy must be 0 J/kg and 0 J/(Kg.K) for functions taken for the +Modelica Standard Library (i.e., mixture properties calculated using the medium +package +<a href=\"Modelica://Modelica.Media.IdealGases.Common.MixtureGasNasa\">Modelica.Media.IdealGases.Common.MixtureGasNasa</a>). +Otherwise, absolute values caloric and entropic properties may not be correctly +calculated. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end IdealGasVaporMixtures; diff --git a/SorpLib/Media/IdealGasVaporMixtures/package.order b/SorpLib/Media/IdealGasVaporMixtures/package.order new file mode 100644 index 0000000000000000000000000000000000000000..73e1adbf9f631f4d14ac0de120d88bd0f7368df1 --- /dev/null +++ b/SorpLib/Media/IdealGasVaporMixtures/package.order @@ -0,0 +1,4 @@ +Interfaces +MoistAir_N2_O2_Ar_H2O +MoistAir_N2_O2_CO2_H2O +Tester diff --git a/SorpLib/Media/IdealGases/Ar/package.mo b/SorpLib/Media/IdealGases/Ar/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5ac230728022361d3548a4c47bf3a0e167aafdb9 --- /dev/null +++ b/SorpLib/Media/IdealGases/Ar/package.mo @@ -0,0 +1,25 @@ +within SorpLib.Media.IdealGases; +package Ar "SorpLib: Ideal gas Ar from NASA Glenn coefficients" + extends Modelica.Media.IdealGases.SingleGases.Ar( + final reference_T(min=0) = 0, + final reference_p = 1e5, + final reference_X=fill(1/nX, nX)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This medium model calculates fluid property data of Ar. For details, +check the package +<a href=\"Modelica://Modelica.Media.IdealGases.SingleGases.Ar\">Modelica.Media.IdealGases.SingleGases.Ar</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Ar; diff --git a/SorpLib/Media/IdealGases/Ar/package.order b/SorpLib/Media/IdealGases/Ar/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGases/CH4/package.mo b/SorpLib/Media/IdealGases/CH4/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..708b99a0883214be4d2643bdcd08e944682cbffe --- /dev/null +++ b/SorpLib/Media/IdealGases/CH4/package.mo @@ -0,0 +1,25 @@ +within SorpLib.Media.IdealGases; +package CH4 "SorpLib: Ideal gas CH4 from NASA Glenn coefficients" + extends Modelica.Media.IdealGases.SingleGases.CH4( + final reference_T(min=0) = 0, + final reference_p = 1e5, + final reference_X=fill(1/nX, nX)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This medium model calculates fluid property data of CH<sub>4</sub>. For details, +check the package +<a href=\"Modelica://Modelica.Media.IdealGases.SingleGases.CH4\">Modelica.Media.IdealGases.SingleGases.CH4</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CH4; diff --git a/SorpLib/Media/IdealGases/CH4/package.order b/SorpLib/Media/IdealGases/CH4/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGases/CO2/package.mo b/SorpLib/Media/IdealGases/CO2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e89f37f0cd4ebcee7c23ddce4fb456976c667bd2 --- /dev/null +++ b/SorpLib/Media/IdealGases/CO2/package.mo @@ -0,0 +1,25 @@ +within SorpLib.Media.IdealGases; +package CO2 "SorpLib: Ideal gas CO2 from NASA Glenn coefficients" + extends Modelica.Media.IdealGases.SingleGases.CO2( + final reference_T(min=0) = 0, + final reference_p = 1e5, + final reference_X=fill(1/nX, nX)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This medium model calculates fluid property data of CO<sub>2</sub>. For details, +check the package +<a href=\"Modelica://Modelica.Media.IdealGases.SingleGases.CO2\">Modelica.Media.IdealGases.SingleGases.CO2</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CO2; diff --git a/SorpLib/Media/IdealGases/CO2/package.order b/SorpLib/Media/IdealGases/CO2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGases/H2O/package.mo b/SorpLib/Media/IdealGases/H2O/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c938d9b8d4d2cabc2ff60cc0c3e7456aaa9d6547 --- /dev/null +++ b/SorpLib/Media/IdealGases/H2O/package.mo @@ -0,0 +1,25 @@ +within SorpLib.Media.IdealGases; +package H2O "SorpLib: Ideal gas H2O from NASA Glenn coefficients" + extends Modelica.Media.IdealGases.SingleGases.H2O( + final reference_T(min=0) = 0, + final reference_p = 1e5, + final reference_X=fill(1/nX, nX)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This medium model calculates fluid property data of H<sub>2</sub>O. For details, +check the package +<a href=\"Modelica://Modelica.Media.IdealGases.SingleGases.H2O\">Modelica.Media.IdealGases.SingleGases.H2O</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end H2O; diff --git a/SorpLib/Media/IdealGases/H2O/package.order b/SorpLib/Media/IdealGases/H2O/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGases/He/package.mo b/SorpLib/Media/IdealGases/He/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e6e8132f7dba6fb7a42a0de71ec1b9decab00fdb --- /dev/null +++ b/SorpLib/Media/IdealGases/He/package.mo @@ -0,0 +1,25 @@ +within SorpLib.Media.IdealGases; +package He "SorpLib: Ideal gas He from NASA Glenn coefficients" + extends Modelica.Media.IdealGases.SingleGases.He( + final reference_T(min=0) = 0, + final reference_p = 1e5, + final reference_X=fill(1/nX, nX)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This medium model calculates fluid property data of He. For details, +check the package +<a href=\"Modelica://Modelica.Media.IdealGases.SingleGases.He\">Modelica.Media.IdealGases.SingleGases.He</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end He; diff --git a/SorpLib/Media/IdealGases/He/package.order b/SorpLib/Media/IdealGases/He/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGases/N2/package.mo b/SorpLib/Media/IdealGases/N2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..cfd6d0adaabdf9c8f7bb9d95f98d0e4ee511c2b1 --- /dev/null +++ b/SorpLib/Media/IdealGases/N2/package.mo @@ -0,0 +1,25 @@ +within SorpLib.Media.IdealGases; +package N2 "SorpLib: Ideal gas N2 from NASA Glenn coefficients" + extends Modelica.Media.IdealGases.SingleGases.N2( + final reference_T(min=0) = 0, + final reference_p = 1e5, + final reference_X=fill(1/nX, nX)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This medium model calculates fluid property data of N<sub>2</sub>. For details, +check the package +<a href=\"Modelica://Modelica.Media.IdealGases.SingleGases.N2\">Modelica.Media.IdealGases.SingleGases.N2</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end N2; diff --git a/SorpLib/Media/IdealGases/N2/package.order b/SorpLib/Media/IdealGases/N2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGases/Ne/package.mo b/SorpLib/Media/IdealGases/Ne/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f9782afe456c54daf658a7988f269d170e6e93de --- /dev/null +++ b/SorpLib/Media/IdealGases/Ne/package.mo @@ -0,0 +1,25 @@ +within SorpLib.Media.IdealGases; +package Ne "SorpLib: Ideal gas Ne from NASA Glenn coefficients" + extends Modelica.Media.IdealGases.SingleGases.Ne( + final reference_T(min=0) = 0, + final reference_p = 1e5, + final reference_X=fill(1/nX, nX)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This medium model calculates fluid property data of Ne. For details, +check the package +<a href=\"Modelica://Modelica.Media.IdealGases.SingleGases.Ne\">Modelica.Media.IdealGases.SingleGases.Ne</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Ne; diff --git a/SorpLib/Media/IdealGases/Ne/package.order b/SorpLib/Media/IdealGases/Ne/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGases/O2/package.mo b/SorpLib/Media/IdealGases/O2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a5a1cfd612a733dee3e817eb3f355d94ca3697aa --- /dev/null +++ b/SorpLib/Media/IdealGases/O2/package.mo @@ -0,0 +1,25 @@ +within SorpLib.Media.IdealGases; +package O2 "SorpLib: Ideal gas O2 from NASA Glenn coefficients" + extends Modelica.Media.IdealGases.SingleGases.O2( + final reference_T(min=0) = 0, + final reference_p = 1e5, + final reference_X=fill(1/nX, nX)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This medium model calculates fluid property data of O<sub>2</sub>. For details, +check the package +<a href=\"Modelica://Modelica.Media.IdealGases.SingleGases.O2\">Modelica.Media.IdealGases.SingleGases.O2</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end O2; diff --git a/SorpLib/Media/IdealGases/O2/package.order b/SorpLib/Media/IdealGases/O2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/IdealGases/Tester/Test_Ar.mo b/SorpLib/Media/IdealGases/Tester/Test_Ar.mo new file mode 100644 index 0000000000000000000000000000000000000000..4a37d5a14889f729c7b5a138bec6f63c825ad2c4 --- /dev/null +++ b/SorpLib/Media/IdealGases/Tester/Test_Ar.mo @@ -0,0 +1,90 @@ +within SorpLib.Media.IdealGases.Tester; +model Test_Ar "Tester for ideal gas Ar" + extends Modelica.Icons.Example; + + // + // Definition of paramters + // + replaceable package Medium = SorpLib.Media.IdealGases.Ar + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p(start=100, fixed=true) + "Pressure"; + Modelica.Units.SI.Temperature T(start=253.15, fixed=true) + "Temperature"; + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + Modelica.Units.SI.SpecificEntropy s + "Specific entropy"; + + Medium.BaseProperties medium_pT + "Base properties calculated with pressure and temperature"; + + + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity"; + Modelica.Units.SI.RelativePressureCoefficient beta + "Isobaric expansion coefficient"; + Modelica.Units.SI.IsothermalCompressibility kappa + "Isothermal compressibility"; + + +equation + // + // Change independent state variables + // + der(p) = (20e5 - 100) / 20 + "Predescribed slope of pressure"; + der(T) = (573.15 - 253.15) / 20 + "Predescribed slope of temperature"; + + // + // Calculate state variables + // + medium_pT.p = p + "Base properties calculated with pressure and temperature"; + medium_pT.T = T + "Base properties calculated with pressure and temperature"; + + // + // Calculate further variables + // + v = 1/medium_pT.d + "Specific volume"; + s = Medium.specificEntropy(state=medium_pT.state) + "Specific entropy"; + + cp = Medium.specificHeatCapacityCp(state=medium_pT.state) + "Specific heat capacity"; + beta = Medium.beta(state=medium_pT.state) + "Isobaric expansion coefficient"; + kappa = Medium.kappa(state=medium_pT.state) + "Isothermal compressibility"; + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal +gas Ar. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_Ar; diff --git a/SorpLib/Media/IdealGases/Tester/Test_CH4.mo b/SorpLib/Media/IdealGases/Tester/Test_CH4.mo new file mode 100644 index 0000000000000000000000000000000000000000..682323bc25db00ac419723a2fc22d0e1fbb26269 --- /dev/null +++ b/SorpLib/Media/IdealGases/Tester/Test_CH4.mo @@ -0,0 +1,26 @@ +within SorpLib.Media.IdealGases.Tester; +model Test_CH4 "Tester for ideal gas CH4" + extends SorpLib.Media.IdealGases.Tester.Test_Ar( + redeclare package Medium = SorpLib.Media.IdealGases.CH4); + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal +gas CH<sub>4</sub>. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_CH4; diff --git a/SorpLib/Media/IdealGases/Tester/Test_CO2.mo b/SorpLib/Media/IdealGases/Tester/Test_CO2.mo new file mode 100644 index 0000000000000000000000000000000000000000..db48d0facba6333bca87a8f361c53adffba74014 --- /dev/null +++ b/SorpLib/Media/IdealGases/Tester/Test_CO2.mo @@ -0,0 +1,26 @@ +within SorpLib.Media.IdealGases.Tester; +model Test_CO2 "Tester for ideal gas CO2" + extends SorpLib.Media.IdealGases.Tester.Test_Ar( + redeclare package Medium = SorpLib.Media.IdealGases.CO2); + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal +gas CO<sub>2</sub>. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_CO2; diff --git a/SorpLib/Media/IdealGases/Tester/Test_H2O.mo b/SorpLib/Media/IdealGases/Tester/Test_H2O.mo new file mode 100644 index 0000000000000000000000000000000000000000..f4abbf5c5a89a182d484868e0504368f38ca22f5 --- /dev/null +++ b/SorpLib/Media/IdealGases/Tester/Test_H2O.mo @@ -0,0 +1,26 @@ +within SorpLib.Media.IdealGases.Tester; +model Test_H2O "Tester for ideal gas H2O" + extends SorpLib.Media.IdealGases.Tester.Test_Ar( + redeclare package Medium = SorpLib.Media.IdealGases.H2O); + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal +gas H<sub>2</sub>O. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_H2O; diff --git a/SorpLib/Media/IdealGases/Tester/Test_He.mo b/SorpLib/Media/IdealGases/Tester/Test_He.mo new file mode 100644 index 0000000000000000000000000000000000000000..e88e334407a66b7747c308d57018b2506f1fbacc --- /dev/null +++ b/SorpLib/Media/IdealGases/Tester/Test_He.mo @@ -0,0 +1,26 @@ +within SorpLib.Media.IdealGases.Tester; +model Test_He "Tester for ideal gas He" + extends SorpLib.Media.IdealGases.Tester.Test_Ar( + redeclare package Medium = SorpLib.Media.IdealGases.He); + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal +gas He. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_He; diff --git a/SorpLib/Media/IdealGases/Tester/Test_N2.mo b/SorpLib/Media/IdealGases/Tester/Test_N2.mo new file mode 100644 index 0000000000000000000000000000000000000000..b95a2955bd34d174bb4a975c463761fe2afb137d --- /dev/null +++ b/SorpLib/Media/IdealGases/Tester/Test_N2.mo @@ -0,0 +1,26 @@ +within SorpLib.Media.IdealGases.Tester; +model Test_N2 "Tester for ideal gas N2" + extends SorpLib.Media.IdealGases.Tester.Test_Ar( + redeclare package Medium = SorpLib.Media.IdealGases.N2); + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal +gas N<sub>2</sub>. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_N2; diff --git a/SorpLib/Media/IdealGases/Tester/Test_Ne.mo b/SorpLib/Media/IdealGases/Tester/Test_Ne.mo new file mode 100644 index 0000000000000000000000000000000000000000..eab1014ca883230270570a2ae17b64804d4234d0 --- /dev/null +++ b/SorpLib/Media/IdealGases/Tester/Test_Ne.mo @@ -0,0 +1,26 @@ +within SorpLib.Media.IdealGases.Tester; +model Test_Ne "Tester for ideal gas Ne" + extends SorpLib.Media.IdealGases.Tester.Test_Ar( + redeclare package Medium = SorpLib.Media.IdealGases.Ne); + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal +gas Ne. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_Ne; diff --git a/SorpLib/Media/IdealGases/Tester/Test_O2.mo b/SorpLib/Media/IdealGases/Tester/Test_O2.mo new file mode 100644 index 0000000000000000000000000000000000000000..c995230a6a15acdb68bc2cecca4873deb4986198 --- /dev/null +++ b/SorpLib/Media/IdealGases/Tester/Test_O2.mo @@ -0,0 +1,26 @@ +within SorpLib.Media.IdealGases.Tester; +model Test_O2 "Tester for ideal gas O2" + extends SorpLib.Media.IdealGases.Tester.Test_Ar( + redeclare package Medium = SorpLib.Media.IdealGases.O2); + + // + // Annotations + // + annotation (experiment(StopTime=20, Tolerance=1e-06), +Documentation(info="<html> +<p> +This model checks the fluid property calculation of the ideal +gas O<sub>2</sub>. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_O2; diff --git a/SorpLib/Media/IdealGases/Tester/package.mo b/SorpLib/Media/IdealGases/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..725830baea2b6adaeec56bca332f6892e60cb4d6 --- /dev/null +++ b/SorpLib/Media/IdealGases/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.IdealGases; +package Tester "Package containing testers to test and varify models calculating fluid property data of ideal gases" + extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented fluid +property models of ideal gases. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Media/IdealGases/Tester/package.order b/SorpLib/Media/IdealGases/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..1dc8d766fb503ed75a051cd7a5518e12c3ec1fbe --- /dev/null +++ b/SorpLib/Media/IdealGases/Tester/package.order @@ -0,0 +1,8 @@ +Test_Ar +Test_CO2 +Test_CH4 +Test_H2O +Test_He +Test_N2 +Test_Ne +Test_O2 diff --git a/SorpLib/Media/IdealGases/package.mo b/SorpLib/Media/IdealGases/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..fabcf48723ae7cc452b0881b3a32213795c13c78 --- /dev/null +++ b/SorpLib/Media/IdealGases/package.mo @@ -0,0 +1,24 @@ +within SorpLib.Media; +package IdealGases "Package containing medium models of ideal gases" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains models of ideal gases. These models are based on the +Modelica Standard Library. Note that the reference temperature must be 0 K +and the reference enthalpy and entropy must be 0 J/kg and 0 J/(Kg.K). Otherwise, +absolute values caloric and entropic properties may not be correctly calculated. +Hence, existing models of ideal gases are implemented in this package again, but +their reference points are correctly set. For details of the ideal gas models, +check the documentation of the package +<a href=\"Modelica://Modelica.Media.IdealGases.Common.SingleGasNasa\">Modelica.Media.IdealGases.Common.SingleGasNasa</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end IdealGases; diff --git a/SorpLib/Media/IdealGases/package.order b/SorpLib/Media/IdealGases/package.order new file mode 100644 index 0000000000000000000000000000000000000000..1e80c1db70d7b8901477f931ba935bccc1537608 --- /dev/null +++ b/SorpLib/Media/IdealGases/package.order @@ -0,0 +1,9 @@ +Ar +CO2 +CH4 +H2O +He +N2 +Ne +O2 +Tester diff --git a/SorpLib/Media/Solids/BaseClasses/PartialSolid.mo b/SorpLib/Media/Solids/BaseClasses/PartialSolid.mo new file mode 100644 index 0000000000000000000000000000000000000000..45ccecd9b2e5ad777e698d8c570a63f88042b400 --- /dev/null +++ b/SorpLib/Media/Solids/BaseClasses/PartialSolid.mo @@ -0,0 +1,844 @@ +within SorpLib.Media.Solids.BaseClasses; +partial model PartialSolid + "Base model for solids" + extends Modelica.Icons.MaterialProperty; + + // + // Definition of parameters regarding calculation setup + // + parameter Boolean calcCaloricProperties = false + "= true, if caloric properties are calculated (i.e., h and u)" + annotation (Dialog(tab="General", group="General"), + choices(checkBox=true), + Evaluate= true); + parameter Boolean calcEntropicProperties = false + "= true, if caloric properties are calculated (i.e., s, g and a)" + annotation (Dialog(tab="General", group="General", + enable = calcCaloricProperties), + choices(checkBox=true), + Evaluate= true); + + // + // Definition of parameters regarding the specific volume + // + parameter SorpLib.Choices.SpecificVolumeSolid approach_v= + SorpLib.Choices.SpecificVolumeSolid.Constant + "Calculation approach for the specific volume" + annotation (Dialog(tab="Specific Volume", group="General"), Evaluate=false); + + parameter Modelica.Units.SI.SpecificVolume v_constant= 1/7919 + "Constant specific volume" + annotation (Dialog(tab="Specific Volume", group="Constant", + enable=(approach_v == SorpLib.Choices.SpecificVolumeSolid.Constant)), + HideResult=true, + Evaluate= false); + + parameter SorpLib.Choices.GeneralizedFunctionApproach approach_v_function= + SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Generalized function used to calculate the specific volume" annotation ( + Dialog( + tab="Specific Volume", + group="Generalized Function", + enable=(approach_v == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + Evaluate=true); + parameter Modelica.Units.SI.Temperature T_ref_v = 293.15 + "Reference temperature for the specific volume" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(approach_v == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real v_ref = 1 + "Reference fluid property data for the specific volume" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(approach_v == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real coefficients_v[:]={v_constant} + "Coefficients of generalized function for the specific volume" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(approach_v == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real exponents_v[size(coefficients_v,1)]={0} + "Exponents of generalized function for the specific volume" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(approach_v == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + + parameter SorpLib.Choices.InterpolationApproach approach_v_interpolation= + SorpLib.Choices.InterpolationApproach.Linear + "Interpolation approach used to calculate the specific volume" annotation ( + Dialog( + tab="Specific Volume", + group="Interpolation", + enable=(approach_v == SorpLib.Choices.SpecificVolumeSolid.Interpolation)), + Evaluate=false); + parameter Real abscissa_v[:]={0, 1000} + "Known abscissa values for the specific volume" + annotation (Dialog(tab="Specific Volume", group="Interpolation", + enable=(approach_v == SorpLib.Choices.SpecificVolumeSolid.Interpolation)), + HideResult=true, + Evaluate= true); + parameter Real ordinate_v[size(abscissa_v,1)]={v_constant, v_constant} + "Known ordinate values for the specific volume" + annotation (Dialog(tab="Specific Volume", group="Interpolation", + enable=(approach_v == SorpLib.Choices.SpecificVolumeSolid.Interpolation)), + HideResult=true, + Evaluate= true); + final parameter Real coefficients_cubicSplines_v[size(abscissa_v,1),4]= + SorpLib.Media.Functions.Utilities.calcCubicSplineCoefficients( + abscissa=abscissa_v, + ordinate=ordinate_v) + "Coefficient a to d for cubic polynomials for the specific volume" + annotation (Dialog(tab="Specific Volume", group="Interpolation", + enable=false), + HideResult=true, + Evaluate= true); + + // + // Definition of parameters regarding the specific heat capacity + // + parameter SorpLib.Choices.SpecificHeatCapacitySolid approach_c= + SorpLib.Choices.SpecificHeatCapacitySolid.Constant + "Calculation approach for the specific heat capacity" annotation (Dialog( + tab="Specific Heat Capacity", group="General"), Evaluate=false); + + parameter Modelica.Units.SI.SpecificHeatCapacity c_constant= 472 + "Constant specific heat capacity" + annotation (Dialog(tab="Specific Heat Capacity", group="Constant", + enable=(approach_c == SorpLib.Choices.SpecificVolumeSolid.Constant)), + HideResult=true, + Evaluate= false); + + parameter SorpLib.Choices.GeneralizedFunctionApproach approach_c_function= + SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Generalized function used to calculate the specific heat capacity" + annotation (Dialog( + tab="Specific Heat Capacity", + group="Generalized Function", + enable=(approach_c == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + Evaluate=true); + parameter Modelica.Units.SI.Temperature T_ref_c = 293.15 + "Reference temperature for the specific heat capacity" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approach_c == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real c_ref = 1 + "Reference fluid property data for the specific heat capacity" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approach_c == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real coefficients_c[:]= {c_constant} + "Coefficients of generalized function for the specific heat capacity" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approach_c == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real exponents_c[size(coefficients_c,1)] = {0} + "Exponents of generalized function for the specific heat capacity" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approach_c == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + + parameter SorpLib.Choices.InterpolationApproach approach_c_interpolation= + SorpLib.Choices.InterpolationApproach.Linear + "Interpolation approach used to calculate the specific heat capacity" + annotation (Dialog( + tab="Specific Heat Capacity", + group="Interpolation", + enable=(approach_c == SorpLib.Choices.SpecificVolumeSolid.Interpolation)), + Evaluate=false); + parameter Real abscissa_c[:]={0, 1000} + "Known abscissa values for the specific heat capacity" + annotation (Dialog(tab="Specific Heat Capacity", group="Interpolation", + enable=(approach_c == SorpLib.Choices.SpecificVolumeSolid.Interpolation)), + HideResult=true, + Evaluate= true); + parameter Real ordinate_c[size(abscissa_c,1)]= {c_constant, c_constant} + "Known ordinate values for the specific heat capacity" + annotation (Dialog(tab="Specific Heat Capacity", group="Interpolation", + enable=(approach_c == SorpLib.Choices.SpecificVolumeSolid.Interpolation)), + HideResult=true, + Evaluate= true); + final parameter Real coefficients_cubicSplines_c[size(abscissa_c,1),4]= + SorpLib.Media.Functions.Utilities.calcCubicSplineCoefficients( + abscissa=abscissa_c, + ordinate=ordinate_c) + "Coefficient a to d for cubic polynomials for the specific heat capacity" + annotation (Dialog(tab="Specific Heat Capacity", group="Interpolation", + enable=false), + HideResult=true, + Evaluate= true); + + // + // Definition of parameters regarding the thermal conductivity + // + parameter SorpLib.Choices.ThermalConductivitySolid approach_lambda= + SorpLib.Choices.ThermalConductivitySolid.Constant + "Calculation approach for the thermal conductivity" annotation (Dialog(tab= + "Thermal Conductivity", group="General"), Evaluate=false); + + parameter Modelica.Units.SI.ThermalConductivity lambda_constant= 14.8 + "Constant thermal conductivity" + annotation (Dialog(tab="Thermal Conductivity", group="Constant", + enable=(approach_lambda == SorpLib.Choices.SpecificVolumeSolid.Constant)), + HideResult=true, + Evaluate= false); + + parameter SorpLib.Choices.GeneralizedFunctionApproach approach_lambda_function= + SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Generalized function used to calculate the thermal conductivity" + annotation (Dialog( + tab="Thermal Conductivity", + group="Generalized Function", + enable=(approach_lambda == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + Evaluate=true); + parameter Modelica.Units.SI.Temperature T_ref_lambda = 293.15 + "Reference temperature for the thermal conductivity" + annotation (Dialog(tab="Thermal Conductivity", group="Generalized Function", + enable=(approach_lambda == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real lambda_ref = 1 + "Reference fluid property data for the thermal conductivity" + annotation (Dialog(tab="Thermal Conductivity", group="Generalized Function", + enable=(approach_lambda == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real coefficients_lambda[:]={lambda_constant} + "Coefficients of generalized function for the thermal conductivity" + annotation (Dialog(tab="Thermal Conductivity", group="Generalized Function", + enable=(approach_lambda == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real exponents_lambda[size(coefficients_lambda,1)]={0} + "Exponents of generalized function for the thermal conductivity" + annotation (Dialog(tab="Thermal Conductivity", group="Generalized Function", + enable=(approach_lambda == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + + parameter SorpLib.Choices.InterpolationApproach approach_lambda_interpolation= + SorpLib.Choices.InterpolationApproach.Linear + "Interpolation approach used to calculate the thermal conductivity" + annotation (Dialog( + tab="Thermal Conductivity", + group="Interpolation", + enable=(approach_lambda == SorpLib.Choices.SpecificVolumeSolid.Interpolation)), + Evaluate=false); + parameter Real abscissa_lambda[:]={0, 1000} + "Known abscissa values for the thermal conductivity" + annotation (Dialog(tab="Thermal Conductivity", group="Interpolation", + enable=(approach_lambda == SorpLib.Choices.SpecificVolumeSolid.Interpolation)), + HideResult=true, + Evaluate= true); + parameter Real ordinate_lambda[size(abscissa_lambda,1)]= {lambda_constant, lambda_constant} + "Known ordinate values for the thermal conductivity" + annotation (Dialog(tab="Thermal Conductivity", group="Interpolation", + enable=(approach_lambda == SorpLib.Choices.SpecificVolumeSolid.Interpolation)), + HideResult=true, + Evaluate= true); + final parameter Real coefficients_cubicSplines_lambda[size(abscissa_lambda,1),4]= + SorpLib.Media.Functions.Utilities.calcCubicSplineCoefficients( + abscissa=abscissa_lambda, + ordinate=ordinate_lambda) + "Coefficient a to d for cubic polynomials for the thermal conductivity" + annotation (Dialog(tab="Thermal Conductivity", group="Interpolation", + enable=false), + HideResult=true, + Evaluate= true); + + // + // Definition of parameters regarding advanced options + // + parameter Modelica.Units.SI.Pressure p_ref = 1e5 + "Reference pressure for caloric and entropic calculations" + annotation (Dialog(tab="Advanced", group="Reference State", + enable=calcCaloricProperties or calcEntropicProperties), + Evaluate= true); + parameter Modelica.Units.SI.Temperature T_ref = 298.15 + "Reference temperature for caloric and entropic calculations" + annotation (Dialog(tab="Advanced", group="Reference State", + enable=calcCaloricProperties or calcEntropicProperties), + Evaluate= true); + + parameter Modelica.Units.SI.SpecificEnthalpy h_ref = 0 + "Specific enthalpy at reference state" + annotation (Dialog(tab="Advanced", group="Reference State", + enable=calcCaloricProperties or calcEntropicProperties), + Evaluate= true); + parameter Modelica.Units.SI.SpecificEntropy s_ref = 0 + "Specific entropy at reference state" + annotation (Dialog(tab="Advanced", group="Reference State", + enable=calcEntropicProperties), + Evaluate= true); + + parameter Real tolerance_int_h = 1e-6 + "Integration tolerance when calculating the specific enthalpy numerically" + annotation (Dialog(tab="Advanced", group="Numerics", + enable=calcCaloricProperties), + HideResult=true, + Evaluate= true); + parameter Real tolerance_int_s = 1e-6 + "Integration tolerance when calculating the specific entropy numerically" + annotation (Dialog(tab="Advanced", group="Numerics", + enable=calcEntropicProperties), + HideResult=true, + Evaluate= true); + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure of solid" + annotation (Dialog(tab="General", group="Inputs", + enable=false)); + input Modelica.Units.SI.Temperature T + "Temperature of solid" + annotation (Dialog(tab="General", group="Inputs", + enable=false)); + + // + // Definition of outputs + // + output SorpLib.Media.Solids.Records.StateVariables state_variables + "Thermodynamic state variables" + annotation (Dialog(tab="General", group="Outputs", + enable=false)); + output SorpLib.Media.Solids.Records.AdditionalVariables additional_variables + "Additional variables" + annotation (Dialog(tab="General", group="Outputs", + enable=false)); + + // + // Definition of functions describing integrands + // +protected + function int_c_dT_generalizedFunction + "Integrand required for calculating the specific enthalpy using the generalized + function" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input Modelica.Units.SI.Temperature T_ref + "Reference temperature for fluid property data"; + input Real z_ref + "Reference fluid property data"; + input Real coefficients[:] + "Coefficients of generalized function"; + input Real exponents[size(coefficients,1)] + "Exponents of generalized function"; + input SorpLib.Choices.GeneralizedFunctionApproach approach + "Function approach"; + algorithm + y := SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=u, + T_ref=T_ref, + z_ref=z_ref, + coefficients=coefficients, + exponents=exponents, + approach=approach) + "Integrand required for calculating the specific enthalpy using the generalized + function"; + end int_c_dT_generalizedFunction; + + function int_c_div_T_dT_generalizedFunction + "Integrand required for calculating the specific entropy using the generalized + function" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input Modelica.Units.SI.Temperature T_ref + "Reference temperature for fluid property data"; + input Real z_ref + "Reference fluid property data"; + input Real coefficients[:] + "Coefficients of generalized function"; + input Real exponents[size(coefficients,1)] + "Exponents of generalized function"; + input SorpLib.Choices.GeneralizedFunctionApproach approach + "Function approach"; + algorithm + y := SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=u, + T_ref=T_ref, + z_ref=z_ref, + coefficients=coefficients, + exponents=exponents, + approach=approach) / u + "Integrand required for calculating the specific entropy using the generalized + function"; + end int_c_div_T_dT_generalizedFunction; + + function int_c_dT_linearInterpolation + "Integrand required for calculating the specific enthalpy using linear + interpolation" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input Real abscissa[:] + "Known abscissa values"; + input Real ordinate[size(abscissa,1)] + "Known ordinate values"; + algorithm + y := SorpLib.Media.Functions.Utilities.linearInterpolation_T( + T=u, + abscissa=abscissa, + ordinate=ordinate) + "Integrand required for calculating the specific enthalpy using linear + interpolation"; + end int_c_dT_linearInterpolation; + + function int_c_div_T_dT_linearInterpolation + "Integrand required for calculating the specific entropy using linear + interpolation" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input Real abscissa[:] + "Known abscissa values"; + input Real ordinate[size(abscissa,1)] + "Known ordinate values"; + algorithm + y := SorpLib.Media.Functions.Utilities.linearInterpolation_T( + T=u, + abscissa=abscissa, + ordinate=ordinate) / u + "Integrand required for calculating the specific entropy using linear + interpolation"; + end int_c_div_T_dT_linearInterpolation; + + function int_c_dT_cubicSplineInterpolation + "Integrand required for calculating the specific enthalpy using cubic spline + interpolation" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input Real abscissa[:] + "Known abscissa values"; + input Real ordinate[size(abscissa,1)] + "Known ordinate values"; + input Real coefficients[size(abscissa,1),4] + "Coefficient a to d for cubic polynomials"; + algorithm + y := SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T( + T=u, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients) + "Integrand required for calculating the specific enthalpy using cubic spline + interpolation"; + end int_c_dT_cubicSplineInterpolation; + + function int_c_div_T_dT_cubicSplineInterpolation + "Integrand required for calculating the specific entropy using cubic spline + interpolation" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + input Real abscissa[:] + "Known abscissa values"; + input Real ordinate[size(abscissa,1)] + "Known ordinate values"; + input Real coefficients[size(abscissa,1),4] + "Coefficient a to d for cubic polynomials"; + algorithm + y := SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T( + T=u, + abscissa=abscissa, + ordinate=ordinate, + coefficients=coefficients) / u + "Integrand required for calculating the specific entropy using cubic spline + interpolation"; + end int_c_div_T_dT_cubicSplineInterpolation; + +equation + // + // Pass input data + // + state_variables.p = p + "Pressure"; + state_variables.T = T + "Pressure"; + + // + // Calculate the density + // + if approach_v == SorpLib.Choices.SpecificVolumeSolid.Constant then + state_variables.v = v_constant + "Specific volume of solid"; + + elseif approach_v == SorpLib.Choices.SpecificVolumeSolid.GeneralizedFunction then + state_variables.v = SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T, + T_ref=T_ref_v, + z_ref=v_ref, + coefficients=coefficients_v, + exponents=exponents_v, + approach=approach_v_function) + "Specific volume of solid"; + + else + if approach_v_interpolation == SorpLib.Choices.InterpolationApproach.Linear then + state_variables.v = SorpLib.Media.Functions.Utilities.linearInterpolation_T( + T=T, + abscissa=abscissa_v, + ordinate=ordinate_v) + "Specific volume of solid"; + + else + state_variables.v = SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T( + T=T, + abscissa=abscissa_v, + ordinate=ordinate_v, + coefficients=coefficients_cubicSplines_v) + "Specific volume of solid"; + + end if; + end if; + + // + // Calculate the specific heat capacity + // + if approach_c == SorpLib.Choices.SpecificHeatCapacitySolid.Constant then + additional_variables.c = c_constant + "Specific heat capacitiy of solid"; + + elseif approach_c == SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction then + additional_variables.c = SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T, + T_ref=T_ref_c, + z_ref=c_ref, + coefficients=coefficients_c, + exponents=exponents_c, + approach=approach_c_function) + "Specific heat capacitiy of solid"; + + else + if approach_c_interpolation == SorpLib.Choices.InterpolationApproach.Linear then + additional_variables.c = SorpLib.Media.Functions.Utilities.linearInterpolation_T( + T=T, + abscissa=abscissa_c, + ordinate=ordinate_c) + "Specific heat capacitiy of solid"; + + else + additional_variables.c = SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T( + T=T, + abscissa=abscissa_c, + ordinate=ordinate_c, + coefficients=coefficients_cubicSplines_c) + "Specific heat capacitiy of solid"; + + end if; + end if; + + // + // Calculate the thermal conductivity + // + if approach_lambda == SorpLib.Choices.ThermalConductivitySolid.Constant then + additional_variables.lambda = lambda_constant + "Thermal conductivity of solid"; + + elseif approach_lambda == SorpLib.Choices.ThermalConductivitySolid.GeneralizedFunction then + additional_variables.lambda = SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T, + T_ref=T_ref_lambda, + z_ref=lambda_ref, + coefficients=coefficients_lambda, + exponents=exponents_lambda, + approach=approach_lambda_function) + "Thermal conductivity of solid"; + + else + if approach_lambda_interpolation == SorpLib.Choices.InterpolationApproach.Linear then + additional_variables.lambda = SorpLib.Media.Functions.Utilities.linearInterpolation_T( + T=T, + abscissa=abscissa_lambda, + ordinate=ordinate_lambda) + "Thermal conductivity of solid"; + + else + additional_variables.lambda = SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T( + T=T, + abscissa=abscissa_lambda, + ordinate=ordinate_lambda, + coefficients=coefficients_cubicSplines_lambda) + "Thermal conductivity of solid"; + + end if; + end if; + + // + // Calculate caloric and entropic properties + // + if calcCaloricProperties then + // + // Specific enthalpy: An analytical integral does not always exist or + // numerical integration is faster + // + if approach_c == SorpLib.Choices.SpecificHeatCapacitySolid.Constant then + state_variables.h = h_ref + additional_variables.c * (T - T_ref) + + state_variables.v * (p - p_ref) + "Specific enthalpy of solid"; + + elseif approach_c == SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction then + state_variables.h = h_ref + state_variables.v * (p - p_ref) + + Modelica.Math.Nonlinear.quadratureLobatto( + f=function int_c_dT_generalizedFunction( + T_ref=T_ref_c, + z_ref=c_ref, + coefficients=coefficients_c, + exponents=exponents_c, + approach=approach_c_function), + a=T_ref, + b=T, + tolerance=tolerance_int_h) + "Specific enthalpy of solid"; + + else + if approach_c_interpolation == SorpLib.Choices.InterpolationApproach.Linear then + state_variables.h = h_ref + state_variables.v * (p - p_ref) + + Modelica.Math.Nonlinear.quadratureLobatto( + f=function int_c_dT_linearInterpolation( + abscissa=abscissa_c, + ordinate=ordinate_c), + a=T_ref, + b=T, + tolerance=tolerance_int_h) + "Specific enthalpy of solid"; + + else + state_variables.h = h_ref + state_variables.v * (p - p_ref) + + Modelica.Math.Nonlinear.quadratureLobatto( + f=function int_c_dT_cubicSplineInterpolation( + abscissa=abscissa_c, + ordinate=ordinate_c, + coefficients=coefficients_cubicSplines_c), + a=T_ref, + b=T, + tolerance=tolerance_int_h) + "Specific enthalpy of solid"; + + end if; + end if; + + state_variables.u = state_variables.h - p * state_variables.v + "Specific internal energy of solid"; + + else + state_variables.h = 0 + "Specific enthalpy of solid"; + state_variables.u = 0 + "Specific internal energy of solid"; + + end if; + + // + // Calculate entropic properties + // + if calcCaloricProperties and calcEntropicProperties then + // + // Specific entropy: An analytical integral does not always exist or + // numerical integration is faster + // + if approach_c == SorpLib.Choices.SpecificHeatCapacitySolid.Constant then + state_variables.s = s_ref + + additional_variables.c * (log(abs(T)) - log(abs(T_ref))) + "Specific entropy of solid"; + + elseif approach_c == SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction then + state_variables.s = s_ref + + Modelica.Math.Nonlinear.quadratureLobatto( + f=function int_c_div_T_dT_generalizedFunction( + T_ref=T_ref_c, + z_ref=c_ref, + coefficients=coefficients_c, + exponents=exponents_c, + approach=approach_c_function), + a=T_ref, + b=T, + tolerance=tolerance_int_s) + "Specific entropy of solid"; + + else + if approach_c_interpolation == SorpLib.Choices.InterpolationApproach.Linear then + state_variables.s = s_ref + + Modelica.Math.Nonlinear.quadratureLobatto( + f=function int_c_div_T_dT_linearInterpolation( + abscissa=abscissa_c, + ordinate=ordinate_c), + a=T_ref, + b=T, + tolerance=tolerance_int_s) + "Specific entropy of solid"; + + else + state_variables.s = s_ref + + Modelica.Math.Nonlinear.quadratureLobatto( + f=function int_c_div_T_dT_cubicSplineInterpolation( + abscissa=abscissa_c, + ordinate=ordinate_c, + coefficients=coefficients_cubicSplines_c), + a=T_ref, + b=T, + tolerance=tolerance_int_s) + "Specific entropy of solid"; + + end if; + end if; + + state_variables.g = state_variables.h - T * state_variables.s + "Specific free enthalpy (i.e., Gibbs free energy) of solid"; + state_variables.a = state_variables.u - T * state_variables.s + "Specific free energy (i.e., Helmholts free energy) of solid"; + + else + state_variables.s = 0 + "Specific entropy of solid"; + state_variables.g = 0 + "Specific free enthalpy (i.e., Gibbs free energy) of solid"; + state_variables.a = 0 + "Specific free energy (i.e., Helmholts free energy) of solid"; + + end if; + + // + // Assertations + // + if calcCaloricProperties or calcEntropicProperties then + if not approach_v == SorpLib.Choices.SpecificVolumeSolid.Constant then + Modelica.Utilities.Streams.print("Warning: The specific volume is not " + + "constant. The caloric model equations assume an incompressible " + + "solid. Thus, the thermodynamic calculation is not consistent."); + end if; + end if; + + if calcEntropicProperties then + if not approach_v == SorpLib.Choices.SpecificVolumeSolid.Constant then + Modelica.Utilities.Streams.print("Warning: The specific volume is not " + + "constant. The caloric model equations assume an incompressible " + + "solid. Thus, the thermodynamic calculation is not consistent."); + end if; + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the base model for calculating thermodynamic properties of solids, +such as sorbents or metals and metal alloys. In the model, fundamental thermodynamic +properties can be calculated: +</p> +<ol> + <li> + Thermal state variables: <i>p</i>, <i>T</i>, and <i>ρ</i>. + </li> + <li> + Caloric state variables: <i>h</i> and <i>u</i>. + </li> + <li> + Entropic state variables: <i>s</i>, <i>g</i>, and <i>a</i>. + </li> +</ol> +<p> +Moreover, the model allows to calculate the specific heat capacity <i>c</i> and thermal +conductivity <i>λ</i>. Models that inherit properties from this partial models have +to selected the correct calculation for the thermodynamic properties and to specify +solid-specific parameters. +</p> + +<h4>Implemented calculation approaches for the thermodyanmic properties <i>h</i> and <i>s</i></h4> +<p> +The calculation methods assume an ideal solid: +</p> +<pre> + h = h<sub>ref</sub>(p<sub>ref</sub>, T<sub>ref</sub>) + ∫_T<sub>ref</sub>^T [c] dT + v * (p - p<sub>ref</sub>); +</pre> +<pre> + s = s<sub>ref</sub>(T<sub>ref</sub>) + ∫_T<sub>ref</sub>^T [c / T] dT +</pre> +<p> +Herein, <i>h<sub>ref</sub></i> and <i>s<sub>ref</sub></i> are the specific enthalpy and +entropy at reference pressure <i>p<sub>ref</sub></i> and temperature <i>T<sub>ref</sub></i>. +</p> + +<h4>Implemented calculation approaches for the thermodyanmic properties <i>ρ</i>, <i>c</i>, and <i>λ</i></h4> +<p> +Three calculation approaches can be selected for each thermodynamic property: +</p> +<ol> + <li> + Constant value. + </li> + <li> + Generalized function. + </li> + <li> + Interpolation. + </li> +</ol> + +<h4>Options regarding the generalized function</h4> +<p> +The +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.generalizedFunction_T\">generalized function</a> +comprises four function types often used for fluid property data calculation: +</p> +<ol> + <li> + For <i>approach = PolynomialFunction_Temperature</i>: + <br> + <pre>z = z<sub>ref</sub> * ∑<sub>i</sub> a<sub>i</sub> * T ^ (b<sub>i</sub>);</pre> + <br> + </li> + <li> + For <i>approach = PolynomialFunction_ReducedTemperature</i>: + <br> + <pre>z = z<sub>ref</sub> * ∑<sub>i</sub> a<sub>i</sub> * (1 - T / T<sub>ref</sub>) ^ (b<sub>i</sub>);</pre> + <br> + </li> + <li> + For <i>approach = ExponentialFunction_Temperature</i>: + <br> + <pre>z = z<sub>ref</sub> * <strong>exp</strong>(∑<sub>i</sub> a<sub>i</sub> * T ^ (b<sub>i</sub>));</pre> + <br> + </li> + <li> + For <i>approach = ExponentialFunction_ReducedTemperature</i>: + <br> + <pre>z = z<sub>ref</sub> * <strong>exp</strong>(∑<sub>i</sub> a<sub>i</sub> * (1 - T / T<sub>ref</sub>) ^ (b<sub>i</sub>));</pre> + <br> + </li> +</ol> +<p> +Herein, <i>z<sub>ref</sub></i> is either a pre-factor for approaches that use the +temperature or the fluid property at reference temperature <i>T<sub>ref</sub></i> +for approaches that use the reduced temperature. The vectors <i>a</i> and <i>b</i> +contain the coefficents and exponents for each summand of the sum. +</p> + +<h4>Options regarding interpolation</h4> +<p> +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.linearInterpolation_T\">Linear</a> +or +<a href=\"Modelica://SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T\">cubic spline interpolation</a> +can be selected. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Currently, the thermodynamic properties <i>ρ</i>, <i>c</i>, and <i>λ</i> do only depend on the temperature and not on the pressrure. + </li> + <li> + When calculating caloric and entropic state properties, the desnity is assumed to be constant (i.e., incompressible solid). + </li> +</ul> +</html>", + revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> + <li> + January 25, 2021, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialSolid; diff --git a/SorpLib/Media/Solids/BaseClasses/PartialTest.mo b/SorpLib/Media/Solids/BaseClasses/PartialTest.mo new file mode 100644 index 0000000000000000000000000000000000000000..8abac464df21318b9fa5133f15a54cbb3de8a727 --- /dev/null +++ b/SorpLib/Media/Solids/BaseClasses/PartialTest.mo @@ -0,0 +1,133 @@ +within SorpLib.Media.Solids.BaseClasses; +partial model PartialTest + "Base model for testers of describing isobaric expansion coefficients of the adsorpt phase for pure component adsorption" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Modelica.Units.SI.Pressure p_start = 1000 + "Start value of pressure" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Temperature T_start = 273.15 + "Start value of temperature" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Real p_der(unit="Pa/s") = (1e5-1000)/20 + "Prescriped sloped of pressure to test solid model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Real T_der(unit="K/s") = 500/20 + "Prescriped sloped of temperature to test solid model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + + replaceable model Solid = + SorpLib.Media.Solids.BaseClasses.PartialSolid + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Solid model" + annotation (Dialog(tab="General",group="Media"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p(start=p_start, fixed=true) + "Pressure"; + Modelica.Units.SI.Temperature T(start=T_start, fixed=true) + "Temperature"; + + // + // Instantiation of models + // + Solid solid_constant( + calcCaloricProperties=true, + calcEntropicProperties=true, + final approach_v=SorpLib.Choices.SpecificVolumeSolid.Constant, + final approach_v_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.Constant, + final approach_c_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final approach_lambda=SorpLib.Choices.ThermalConductivitySolid.Constant, + final approach_lambda_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final p=p, + final T=T) "Solid: Consant properties" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + + Solid solid_generalizedFunction( + calcCaloricProperties=true, + calcEntropicProperties=true, + approach_v=SorpLib.Choices.SpecificVolumeSolid.Constant, + final approach_v_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction, + final approach_c_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final approach_lambda=SorpLib.Choices.ThermalConductivitySolid.GeneralizedFunction, + final approach_lambda_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final p=p, + final T=T) "Solid: Generalized function" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + + Solid solid_linearInterpolation( + calcCaloricProperties=true, + calcEntropicProperties=true, + approach_v=SorpLib.Choices.SpecificVolumeSolid.Constant, + final approach_v_interpolation=SorpLib.Choices.InterpolationApproach.Linear, + final approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.Interpolation, + final approach_c_interpolation=SorpLib.Choices.InterpolationApproach.Linear, + final approach_lambda=SorpLib.Choices.ThermalConductivitySolid.Interpolation, + final approach_lambda_interpolation=SorpLib.Choices.InterpolationApproach.Linear, + final p=p, + final T=T) "Solid: Linear interpolation" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + + Solid solid_cubicSplineInterpolation( + calcCaloricProperties=true, + calcEntropicProperties=true, + approach_v=SorpLib.Choices.SpecificVolumeSolid.Constant, + final approach_v_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.Interpolation, + final approach_c_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final approach_lambda=SorpLib.Choices.ThermalConductivitySolid.Interpolation, + final approach_lambda_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final p=p, + final T=T) "Solid: Cubic spline interpolation" + annotation (Placement(transformation(extent={{60,-10},{80,10}}))); + +equation + // + // Calculation of properties + // + der(p) = p_der + "Predecsriped slope of p to demonstrate the solid model"; + der(T) = T_der + "Predecsriped slope of T to demonstrate the solid model"; + + // + // Annotations + // + annotation ( + Icon(coordinateSystem(preserveAspectRatio=false)), + Diagram(coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the basic model for all testers of solid models. This partial +model defines all relevant parameters, variables, and models to test the solid models. +<br/><br/> +Models that inherit properties from this partial model have to redeclare the model +'Solid' and to define the test setup. +</p> +</html>", revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialTest; diff --git a/SorpLib/Media/Solids/BaseClasses/package.mo b/SorpLib/Media/Solids/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5f852b4b3453db90786450b4a0275dd2fed7036f --- /dev/null +++ b/SorpLib/Media/Solids/BaseClasses/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.Solids; +package BaseClasses "Base classes used to build new solid models" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial functions and models. These partial functions and models +contain fundamental definitions for calculating thermodynamic properties of solids. +The content of this package is only of interest when adding new functions to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Media/Solids/BaseClasses/package.order b/SorpLib/Media/Solids/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..f267fa6c268ae3aacc627030e69182b1a480a56d --- /dev/null +++ b/SorpLib/Media/Solids/BaseClasses/package.order @@ -0,0 +1,2 @@ +PartialSolid +PartialTest diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/Aluminium.mo b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Aluminium.mo new file mode 100644 index 0000000000000000000000000000000000000000..8b9d158c779221b03907513c7b824f233d618b18 --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Aluminium.mo @@ -0,0 +1,75 @@ +within SorpLib.Media.Solids.MetalsAndMetalAlloys; +model Aluminium "Model of aluminium" + extends BaseClasses.PartialSolid( + approach_v=SorpLib.Choices.SpecificVolumeSolid.Constant, + final v_constant=1/2700, + final approach_v_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_v=273.15, + final v_ref=1, + final coefficients_v={2.40565103604828e-17,-3.18909783349765e-14, + 3.05844815369395e-11,9.82750318802462e-09,0.000365560992186206}, + final exponents_v={4,3,2,1,0}, + approach_v_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_v={1.721428571,98.86428571,201.7214286,298.8642857, + 398.8642857,501.7214286,601.7214286,696.0071429,793.15,901.7214286, + 930.2928571}, + final ordinate_v={0.000365578,0.000366803,0.000368566,0.000370705, + 0.000372868,0.000375608,0.000378763,0.000382543,0.000386204,0.000391529, + 0.000393539}, + approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.Interpolation, + final c_constant=837, + final approach_c_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_c=273.15, + final c_ref=1, + final coefficients_c={4.27500975902274e-12,-1.57466005351826e-08, + 2.29069115958695e-05,-0.0160371796818545,5.75972719368390, + 110.779863838808}, + final exponents_c={5,4,3,2,1,0}, + approach_c_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_c={264.1864146,306.7634454,351.5813725,409.8446779, + 474.8306723,566.707423,667.5477591,739.2564426,799.7606443,846.8194678, + 889.3964986}, + final ordinate_c={864.2857143,901.9305019,931.8532819,958.8803089, + 984.9420849,1020.656371,1063.127413,1099.80695,1133.590734,1162.548263, + 1189.57529}, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.Interpolation, + final lambda_constant=236, + final approach_lambda_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_lambda=273.15, + final lambda_ref=1, + final coefficients_lambda={5.93000570062670e-13,-1.92890156664459e-09, + 2.59002630981166e-06,-0.00184669307956919,0.642940781600963, + 154.914872094860}, + final exponents_lambda={5,4,3,2,1,0}, + approach_lambda_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_lambda={275.2664021,298.5468254,351.4568783,400.134127, + 501.7214286,603.3087302,700.6632275,800.134127,899.6050265,933.4674603}, + final ordinate_lambda={235.8518519,236.8888889,238.962963,240,236.3703704, + 231.1851852,224.962963,217.7037037,209.9259259,208.3703704}); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model describes aluminium. +</p> + +<h4>References</h4> +<ul> + <li> + Neubronner, M. and Bodmer, T. and Hübner, C. and Kempa, P.B. and Tsotsas, E. and Eschner, A. and Kasparek, G. and Ochs, F. and Müller-Steinhagen, H. and Werner, H. and Spitzner M. (2010). D6 Properties of Solids and Solid Materials. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_26. + </li> + <li> + Foteinopoulos, P. and Papacharalampopoulos, A. and Stavropoulos, P. (2018). On thermal modeling of Additive Manufacturing processes. CIRP Journal of Manufacturing Science and Technology, 20: 66-83. DOI: https://doi.org/10.1016/j.cirpj.2017.09.007. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Aluminium; diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/Copper.mo b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Copper.mo new file mode 100644 index 0000000000000000000000000000000000000000..d5e61e500f4e6fe135363f8aa538504327c8add2 --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Copper.mo @@ -0,0 +1,67 @@ +within SorpLib.Media.Solids.MetalsAndMetalAlloys; +model Copper "Model of copper" + extends BaseClasses.PartialSolid( + approach_v=SorpLib.Choices.SpecificVolumeSolid.Constant, + final v_constant=1/8960, + final approach_v_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_v=273.15, + final v_ref=1, + final coefficients_v={1.60881016976082e-22,-5.53823537743382e-19, + 7.14670930357768e-16,-4.34191656855154e-13,1.31448861732992e-10,-1.36958086403092e-08, + 0.000111423194172002}, + final exponents_v={6,5,4,3,2,1,0}, + approach_v_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_v={100,150,200,250,300,400,600,800,1000,1200}, + final ordinate_v={0.000111,0.00011121,0.000111445,0.000111719,0.000111982, + 0.000112562,0.000113804,0.000115714,0.000116713,0.000118231}, + approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.Interpolation, + final c_constant=381, + final approach_c_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_c=273.15, + final c_ref=1, + final coefficients_c={-8.07419641469257e-15,3.50215406143622e-11,-5.94904387124967e-08, + 5.02166294598675e-05,-0.0221269700391500,4.96530568724046,-65.8705951309113}, + final exponents_c={6,5,4,3,2,1,0}, + approach_c_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_c={100,150,200,250,300,400,600,800,1000,1200}, + final ordinate_c={254,323,357,377,386,396,431,448,446,480}, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.Interpolation, + final lambda_constant=401, + final approach_lambda_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_lambda=273.15, + final lambda_ref=1, + final coefficients_lambda={1.94540420564950e-15,-8.18944543476065e-12, + 1.37969889556392e-08,-1.18885525980176e-05,0.00552526968168941,-1.38362953925209, + 545.964729052232}, + final exponents_lambda={6,5,4,3,2,1,0}, + approach_lambda_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_lambda={100,150,200,250,300,400,600,800,1000,1200}, + final ordinate_lambda={480,429,413,406,401,393,379,366,352,339}); + + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model describes copper. +</p> + +<h4>References</h4> +<ul> + <li> + Neubronner, M. and Bodmer, T. and Hübner, C. and Kempa, P.B. and Tsotsas, E. and Eschner, A. and Kasparek, G. and Ochs, F. and Müller-Steinhagen, H. and Werner, H. and Spitzner M. (2010). D6 Properties of Solids and Solid Materials. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_26. + </li> + <li> + The Engineering ToolBox (2023). Copper - Density, Specific Heat and Thermal Conductivity vs. Temperature. URL: https://www.engineeringtoolbox.com/copper-density-specific-heat-thermal-conductivity-vs-temperature-d_2223.html. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Copper; diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/StainlessSteel_X5CrNi18_10.mo b/SorpLib/Media/Solids/MetalsAndMetalAlloys/StainlessSteel_X5CrNi18_10.mo new file mode 100644 index 0000000000000000000000000000000000000000..5d19fca3bbfde0cf854419f43656b1e1d625a925 --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/StainlessSteel_X5CrNi18_10.mo @@ -0,0 +1,76 @@ +within SorpLib.Media.Solids.MetalsAndMetalAlloys; +model StainlessSteel_X5CrNi18_10 + "Model of stainless steel (X5CrNi18-10, 1.4301)" + extends BaseClasses.PartialSolid( + approach_v=SorpLib.Choices.SpecificVolumeSolid.Constant, + final v_constant=1/7919, + final approach_v_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_v=293.15, + final v_ref=1, + final coefficients_v={1.417e-12,5.53e-09,0.0001245}, + final exponents_v={2,1,0}, + approach_v_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_v={173.15,223.15,273.15,293.15,323.15,373.15,423.15,473.15, + 523.15,573.15,623.15,673.15,723.15,773.15,823.15,873.15,923.15,973.15, + 1023.15,1073.15,1123.15,1173.15,1223.15,1273.15}, + final ordinate_v={0.000125597,0.000125865,0.000126151,0.000126279, + 0.00012647,0.000126791,0.000127113,0.000127453,0.000127796,0.000128172, + 0.000128535,0.000128899,0.000129266,0.000129651,0.000130056,0.000130446, + 0.000130839,0.000131268,0.000131683,0.0001321,0.000132538,0.000132961, + 0.000133422,0.000133851}, + approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.Interpolation, + final c_constant=472, + final approach_c_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_c=293.15, + final c_ref=1, + final coefficients_c={9.25930531486607e-23,-6.29809836854451e-19, + 1.82815391249959e-15,-2.95540224203995e-12,2.91605553475977e-09,-1.81312388707961e-06, + 0.000709566941044524,-0.169563319957511,23.0970795857625,-957.595934830084}, + final exponents_c={9,8,7,6,5,4,3,2,1,0}, + approach_c_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_c={173.15,223.15,273.15,293.15,323.15,373.15,423.15,473.15, + 523.15,573.15,623.15,673.15,723.15,773.15,823.15,873.15,923.15,973.15, + 1023.15,1073.15,1123.15,1173.15,1223.15,1273.15}, + final ordinate_c={394,437,463,472,484,501,518,525,527,532,544,555,567,582, + 595,604,608,610,610,609,610,615,625,641}, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.Interpolation, + final lambda_constant=14.8, + final approach_lambda_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_lambda=293.15, + final lambda_ref=1, + final coefficients_lambda={-1.08698661001520e-11,3.55842498641231e-08,-4.21979972731494e-05, + 0.0355381893207769,7.17648049527021}, + final exponents_lambda={4,3,2,1,0}, + approach_lambda_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_lambda={173.15,223.15,273.15,293.15,323.15,373.15,423.15, + 473.15,523.15,573.15,623.15,673.15,723.15,773.15,823.15,873.15,923.15, + 973.15,1023.15,1073.15,1123.15,1173.15,1223.15,1273.15}, + final ordinate_lambda={12.2,13.4,14.4,14.8,15.4,16.2,17,17.8,18.5,19.2,19.9, + 20.6,21.3,22,22.7,23.4,24.2,24.8,25.6,26.2,27,27.6,28.3,29}); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model describes the stainless steel 'X5CrNi18-10' (i.e., 1.4301). +</p> + +<h4>References</h4> +<ul> + <li> + Neubronner, M. and Bodmer, T. and Hübner, C. and Kempa, P.B. and Tsotsas, E. and Eschner, A. and Kasparek, G. and Ochs, F. and Müller-Steinhagen, H. and Werner, H. and Spitzner M. (2010). D6 Properties of Solids and Solid Materials. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_26. + </li> + <li> + Richter, F. (2011). The Physical Properties of Steels. „The 100 Steels Programme“. Part I: Tables and Figures. URL: https://www.tugraz.at/fileadmin/user_upload/Institute/IEP/Thermophysics_Group/Files/Staehle-Richter.pdf. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end StainlessSteel_X5CrNi18_10; diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/Steel_35_8.mo b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Steel_35_8.mo new file mode 100644 index 0000000000000000000000000000000000000000..9e1aae7c5fc5258e2c82dfcdf1b43b62787b9129 --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Steel_35_8.mo @@ -0,0 +1,72 @@ +within SorpLib.Media.Solids.MetalsAndMetalAlloys; +model Steel_35_8 "Model of steel (St 35.8, 1.0305)" + extends BaseClasses.PartialSolid( + approach_v=SorpLib.Choices.SpecificVolumeSolid.Constant, + final v_constant=1/7849, + final approach_v_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_v=293.15, + final v_ref=1, + final coefficients_v={-9.24794524189667e-16,3.38530633048595e-12, + 2.82381898383647e-09,0.000126309572458865}, + final exponents_v={3,2,1,0}, + approach_v_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_v={173.15,223.15,273.15,293.15,323.15,373.15,423.15,473.15, + 523.15,573.15,623.15,673.15,723.15,773.15,823.15,873.15,923.15}, + final ordinate_v={0.000126904,0.000127097,0.000127307,0.000127405, + 0.000127551,0.000127779,0.000128041,0.000128304,0.000128584,0.000128866, + 0.000129149,0.000129467,0.000129769,0.00013009,0.000130412,0.000130736, + 0.000131079}, + approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.Interpolation, + final c_constant=461, + final approach_c_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_c=293.15, + final c_ref=1, + final coefficients_c={1.53498822513122e-21,-7.10858683567692e-18, + 1.42358708364266e-14,-1.61700732871324e-11,1.14838006710273e-08,-5.29608834276069e-06, + 0.00159217501494625,-0.303448556797988,34.1990283010557,-1370.20964231408}, + final exponents_c={9,8,7,6,5,4,3,2,1,0}, + approach_c_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_c={173.15,223.15,273.15,293.15,323.15,373.15,423.15,473.15, + 523.15,573.15,623.15,673.15,723.15,773.15,823.15,873.15,923.15}, + final ordinate_c={371,419,451,461,475,496,515,533,550,568,589,611,639,677, + 724,778,880}, + approach_lambda=SorpLib.Choices.ThermalConductivitySolid.Interpolation, + final lambda_constant=47, + final approach_lambda_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final T_ref_lambda=293.15, + final lambda_ref=1, + final coefficients_lambda={-3.94094761029167e-13,1.07417893817399e-09,-9.96940386382202e-07, + 0.000294011493296933,0.0194428803212433,34.2898469544763}, + final exponents_lambda={5,4,3,2,1,0}, + approach_lambda_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_lambda={173.15,223.15,273.15,293.15,323.15,373.15,423.15, + 473.15,523.15,573.15,623.15,673.15,723.15,773.15,823.15,873.15,923.15}, + final ordinate_lambda={42.2,45.1,46.6,47,47.9,48.8,49.1,48.2,47.2,45.7,44.3, + 42.6,40.8,39.3,37.7,35.9,34.4}); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model describes the steel 'St 35.8' (i.e., 1.0305). +</p> + +<h4>References</h4> +<ul> + <li> + Neubronner, M. and Bodmer, T. and Hübner, C. and Kempa, P.B. and Tsotsas, E. and Eschner, A. and Kasparek, G. and Ochs, F. and Müller-Steinhagen, H. and Werner, H. and Spitzner M. (2010). D6 Properties of Solids and Solid Materials. In: VDI Heat Atlas. VDI-Buch. Springer, Berlin, Heidelberg. DOI: https://doi.org/10.1007/978-3-540-77877-6_26. + </li> + <li> + Richter, F. (2011). The Physical Properties of Steels. „The 100 Steels Programme“. Part I: Tables and Figures. URL: https://www.tugraz.at/fileadmin/user_upload/Institute/IEP/Thermophysics_Group/Files/Staehle-Richter.pdf. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Steel_35_8; diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_Aluminium.mo b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_Aluminium.mo new file mode 100644 index 0000000000000000000000000000000000000000..f675f25ed7b5cb499e905623e06a20ffa6667c6b --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_Aluminium.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.Solids.MetalsAndMetalAlloys.Testers; +model Test_Aluminium "Tester for the model 'Aluminium'" + extends SorpLib.Media.Solids.BaseClasses.PartialTest(redeclare final model + Solid = SorpLib.Media.Solids.MetalsAndMetalAlloys.Aluminium); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'Aluminium' model. The main +approaches for calculating thermodynamic property data are demonstrated: +Constant values, generic functions, and interpolation. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Aluminium; diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_Copper.mo b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_Copper.mo new file mode 100644 index 0000000000000000000000000000000000000000..29c242bb31b39eceb084cc7308cd419d503effcb --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_Copper.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.Solids.MetalsAndMetalAlloys.Testers; +model Test_Copper "Tester for the model 'Copper'" + extends SorpLib.Media.Solids.BaseClasses.PartialTest(redeclare final model + Solid = SorpLib.Media.Solids.MetalsAndMetalAlloys.Copper); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'Copper' model. The main +approaches for calculating thermodynamic property data are demonstrated: +Constant values, generic functions, and interpolation. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Copper; diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_StainlessSteel_X5CrNi18_10.mo b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_StainlessSteel_X5CrNi18_10.mo new file mode 100644 index 0000000000000000000000000000000000000000..99bf9fb5b59510ab3f89034bad3cd1d015688e84 --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_StainlessSteel_X5CrNi18_10.mo @@ -0,0 +1,31 @@ +within SorpLib.Media.Solids.MetalsAndMetalAlloys.Testers; +model Test_StainlessSteel_X5CrNi18_10 + "Tester for the model 'StainlessSteel_X5CrNi18_10'" + extends SorpLib.Media.Solids.BaseClasses.PartialTest(redeclare final model + Solid = + SorpLib.Media.Solids.MetalsAndMetalAlloys.StainlessSteel_X5CrNi18_10); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'StainlessSteel_X5CrNi18_10' model. The main +approaches for calculating thermodynamic property data are demonstrated: +Constant values, generic functions, and interpolation. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_StainlessSteel_X5CrNi18_10; diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_Steel_35_8.mo b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_Steel_35_8.mo new file mode 100644 index 0000000000000000000000000000000000000000..05c96f66e881b189675637bec6ef988be7d35d52 --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/Test_Steel_35_8.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.Solids.MetalsAndMetalAlloys.Testers; +model Test_Steel_35_8 "Tester for the model 'Steel_35_8'" + extends SorpLib.Media.Solids.BaseClasses.PartialTest(redeclare final model + Solid = SorpLib.Media.Solids.MetalsAndMetalAlloys.Steel_35_8); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'Steel_35_8' model. The main +approaches for calculating thermodynamic property data are demonstrated: +Constant values, generic functions, and interpolation. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Steel_35_8; diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/package.mo b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..909a8c0c45944bf1076854090a266ff86575c679 --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.Solids.MetalsAndMetalAlloys; +package Testers "Models to test and varify sorbent models" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all models of metals and metal +alloys. The test models check the implementation and demonstrate the models' +general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/package.order b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..1eb11d274aaf01c53552871752c70d7e6d3b8179 --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/Testers/package.order @@ -0,0 +1,4 @@ +Test_Aluminium +Test_Copper +Test_Steel_35_8 +Test_StainlessSteel_X5CrNi18_10 diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/package.mo b/SorpLib/Media/Solids/MetalsAndMetalAlloys/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..48be76731c0b007c17be74510384b1afcdd750a2 --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Solids; +package MetalsAndMetalAlloys "Parametrized models of metals and metal alloys" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrized solid models describing metals and metal alloys. +The models already implemented can be found in the package content. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end MetalsAndMetalAlloys; diff --git a/SorpLib/Media/Solids/MetalsAndMetalAlloys/package.order b/SorpLib/Media/Solids/MetalsAndMetalAlloys/package.order new file mode 100644 index 0000000000000000000000000000000000000000..29a016efc38d65015a7286c03732c3b90e0a3835 --- /dev/null +++ b/SorpLib/Media/Solids/MetalsAndMetalAlloys/package.order @@ -0,0 +1,5 @@ +Aluminium +Copper +Steel_35_8 +StainlessSteel_X5CrNi18_10 +Testers diff --git a/SorpLib/Media/Solids/Records/AdditionalVariables.mo b/SorpLib/Media/Solids/Records/AdditionalVariables.mo new file mode 100644 index 0000000000000000000000000000000000000000..2e92e940a18a7dc8ef6ccfc6d8f20807c1c0b065 --- /dev/null +++ b/SorpLib/Media/Solids/Records/AdditionalVariables.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.Solids.Records; +record AdditionalVariables + "This record contains additional thermodynamic variables" + extends Modelica.Icons.Record; + + // + // Definition of paramters + // + Modelica.Units.SI.SpecificHeatCapacity c + "Specific heat capacitiy"; + Modelica.Units.SI.ThermalConductivity lambda + "Thermal conductivity"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains additional thermodynamic variables. +</p> +</html>", revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdditionalVariables; diff --git a/SorpLib/Media/Solids/Records/StateVariables.mo b/SorpLib/Media/Solids/Records/StateVariables.mo new file mode 100644 index 0000000000000000000000000000000000000000..b0450212fd6352fd807803f2f4a8a86d5804d495 --- /dev/null +++ b/SorpLib/Media/Solids/Records/StateVariables.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.Solids.Records; +record StateVariables + "This record contains thermodynamic state variables" + extends Modelica.Icons.Record; + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p + "Pressure"; + Modelica.Units.SI.Temperature T + "Temperature"; + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy"; + Modelica.Units.SI.SpecificInternalEnergy u + "Specific internal energy"; + Modelica.Units.SI.SpecificEntropy s + "Specific entropy"; + Modelica.Units.SI.SpecificGibbsFreeEnergy g + "Specific free enthalpy (i.e., Gibbs free energy)"; + Modelica.Units.SI.SpecificHelmholtzFreeEnergy a + "Specific free energy (i.e., Helmholts free energy)"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains thermodynamic state variables. +</p> +</html>", revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end StateVariables; diff --git a/SorpLib/Media/Solids/Records/package.mo b/SorpLib/Media/Solids/Records/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..91e1bf540637b395b658c5fad4818f09f5669539 --- /dev/null +++ b/SorpLib/Media/Solids/Records/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Solids; +package Records "Package containing records" + extends Modelica.Icons.RecordsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains definitions of records. These records are used to cluster +variables and tidy up the model output. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Records; diff --git a/SorpLib/Media/Solids/Records/package.order b/SorpLib/Media/Solids/Records/package.order new file mode 100644 index 0000000000000000000000000000000000000000..de273071c1cef644e92ff39657d255d435404183 --- /dev/null +++ b/SorpLib/Media/Solids/Records/package.order @@ -0,0 +1,2 @@ +StateVariables +AdditionalVariables diff --git a/SorpLib/Media/Solids/Sorbents/GenericSorbent.mo b/SorpLib/Media/Solids/Sorbents/GenericSorbent.mo new file mode 100644 index 0000000000000000000000000000000000000000..0393743a6e9181e8c262ffeedf0de79c7a630104 --- /dev/null +++ b/SorpLib/Media/Solids/Sorbents/GenericSorbent.mo @@ -0,0 +1,38 @@ +within SorpLib.Media.Solids.Sorbents; +model GenericSorbent "Model of a generic solid sorbent" + extends BaseClasses.PartialSolid( + v_constant=1/2200, + coefficients_v = {v_constant}, + exponents_v = {0}, + abscissa_v = {0, 1000}, + ordinate_v = {v_constant, v_constant}, + c_constant=1000, + coefficients_c = {c_constant}, + exponents_c = {0}, + abscissa_c = {0, 1000}, + ordinate_c = {c_constant, c_constant}, + lambda_constant=0.12, + coefficients_lambda = {lambda_constant}, + exponents_lambda = {0}, + abscissa_lambda = {0, 1000}, + ordinate_lambda = {lambda_constant, lambda_constant}); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model can be used a generic sorbent model. This model is useful if the exact +thermodynamic properties as a function of temperature are not known or if individual +parameters are determined during parameter estimation. Note that the density +describes the true particle density. +</p> +</html>", revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end GenericSorbent; diff --git a/SorpLib/Media/Solids/Sorbents/RDSilicaGel.mo b/SorpLib/Media/Solids/Sorbents/RDSilicaGel.mo new file mode 100644 index 0000000000000000000000000000000000000000..eba8fb298c6ae049e0515203dedb941e0087a697 --- /dev/null +++ b/SorpLib/Media/Solids/Sorbents/RDSilicaGel.mo @@ -0,0 +1,56 @@ +within SorpLib.Media.Solids.Sorbents; +model RDSilicaGel + "Model of a regular density silica gel (e.g., silica gel 123)" + extends BaseClasses.PartialSolid( + v_constant=1/725, + coefficients_v={v_constant}, + exponents_v={0}, + abscissa_v={0,1000}, + ordinate_v={v_constant,v_constant}, + approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.GeneralizedFunction, + final approach_c_function=SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature, + final c_constant=934, + final T_ref_c=293.15, + final c_ref=1, + final coefficients_c={655.814203422836,1.21401945870847,-7816005.43610635}, + final exponents_c={0,1,-2}, + approach_c_interpolation=SorpLib.Choices.InterpolationApproach.CubicSplines, + final abscissa_c={303.15,308.15,313.15,318.15,323.15,328.15,333.15,338.15, + 343.15,348.15,353.15,358.15,363.15,368.15,373.15}, + final ordinate_c={934,951,958,966,974,982,990,997,1006,1013,1020,1029,1037, + 1045,1055}, + lambda_constant=0.12, + coefficients_lambda={lambda_constant}, + exponents_lambda={0}, + abscissa_lambda={0,1000}, + ordinate_lambda={lambda_constant,lambda_constant}); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model describes regular density silica gel, such as silica gel 123. The properties +density and thermal conductivity are fixed to values given by Schawe (1999). The specific +heat capacity is temperature dependt according to measurements by Islam et al. (2020). Note +that the density describes the true particle density. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe, D. (1999). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD Thesis, Stuttgart. + </li> + <li> + Islam, M.A. and Pal, A. and Saha, B.B. (2020). Experimental study on thermophysical and porous properties of silica gels, International Journal of Refrigeration, 110:277–28. DOI https://doi.org/10.1016/j.ijrefrig.2019.10.027. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end RDSilicaGel; diff --git a/SorpLib/Media/Solids/Sorbents/Testers/Test_GenericSorbent.mo b/SorpLib/Media/Solids/Sorbents/Testers/Test_GenericSorbent.mo new file mode 100644 index 0000000000000000000000000000000000000000..f362fd3dc558bc11935f8c3c6478970b8cd87ba3 --- /dev/null +++ b/SorpLib/Media/Solids/Sorbents/Testers/Test_GenericSorbent.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.Solids.Sorbents.Testers; +model Test_GenericSorbent "Tester for the model 'GenericSorbent'" + extends SorpLib.Media.Solids.BaseClasses.PartialTest( + redeclare final model Solid = SorpLib.Media.Solids.Sorbents.GenericSorbent); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'GenericSorbent' model. The main +approaches for calculating thermodynamic property data are demonstrated: +Constant values, generic functions, and interpolation. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_GenericSorbent; diff --git a/SorpLib/Media/Solids/Sorbents/Testers/Test_RDSilicaGel.mo b/SorpLib/Media/Solids/Sorbents/Testers/Test_RDSilicaGel.mo new file mode 100644 index 0000000000000000000000000000000000000000..0faf6be0070f6adc9e8ac164f37fe36037ba0cf8 --- /dev/null +++ b/SorpLib/Media/Solids/Sorbents/Testers/Test_RDSilicaGel.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.Solids.Sorbents.Testers; +model Test_RDSilicaGel "Tester for the model 'RDSilicaGel'" + extends SorpLib.Media.Solids.BaseClasses.PartialTest( + redeclare final model Solid = SorpLib.Media.Solids.Sorbents.RDSilicaGel); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'RDSilicaGel' model. The main +approaches for calculating thermodynamic property data are demonstrated: +Constant values, generic functions, and interpolation. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_RDSilicaGel; diff --git a/SorpLib/Media/Solids/Sorbents/Testers/package.mo b/SorpLib/Media/Solids/Sorbents/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..fd53900242431670fcac9fdb5793d679b24f72db --- /dev/null +++ b/SorpLib/Media/Solids/Sorbents/Testers/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Solids.Sorbents; +package Testers "Models to test and varify sorbent models" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all sorbent models. The test +models check the implementation and demonstrate the models' general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/Solids/Sorbents/Testers/package.order b/SorpLib/Media/Solids/Sorbents/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..07fd1e15288fdaeb68457deba87df0e0f5767438 --- /dev/null +++ b/SorpLib/Media/Solids/Sorbents/Testers/package.order @@ -0,0 +1,2 @@ +Test_GenericSorbent +Test_RDSilicaGel diff --git a/SorpLib/Media/Solids/Sorbents/package.mo b/SorpLib/Media/Solids/Sorbents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e131aadcebebc6d38a866007668b65f411d292ef --- /dev/null +++ b/SorpLib/Media/Solids/Sorbents/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.Solids; +package Sorbents "Parametrized sorbent models" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrized solid models describing sorbents. The sorbent models +already implemented can be found in the package content. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Sorbents; diff --git a/SorpLib/Media/Solids/Sorbents/package.order b/SorpLib/Media/Solids/Sorbents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..56fbd6f79899c34c49519a4be5246b7678b05a7b --- /dev/null +++ b/SorpLib/Media/Solids/Sorbents/package.order @@ -0,0 +1,3 @@ +GenericSorbent +RDSilicaGel +Testers diff --git a/SorpLib/Media/Solids/package.mo b/SorpLib/Media/Solids/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..027f8ef443685ad70dffe780b62d42971aef9e18 --- /dev/null +++ b/SorpLib/Media/Solids/package.mo @@ -0,0 +1,41 @@ +within SorpLib.Media; +package Solids "Models to calcualte fluid property data of solids" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains models calculating thermodynamic properties of solids, such as +sorbents or metals and metal alloys. Independent state variables are the pressure and +temperature. In the models, fundamental thermodynamic properties can be calculated: +</p> +<ol> + <li> + Thermal state variables: <i>p</i>, <i>T</i>, and <i>ρ</i>. + </li> + <li> + Caloric state variables: <i>h</i> and <i>u</i>. + </li> + <li> + Entropic state variables: <i>s</i>, <i>g</i>, and <i>a</i>. + </li> +</ol> +<p> +Moreover, the model allow to calculate the specific heat capacity <i>c</i> and thermal +conductivity <i>λ</i>. +</p> + +<h4>How to add new solid models</h4> +<p> +To add a new solid model, duplicate an existing solid model in the correct package. Then, +parametrize the model and write the documentation, including references for the thermodynamic +properties. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Solids; diff --git a/SorpLib/Media/Solids/package.order b/SorpLib/Media/Solids/package.order new file mode 100644 index 0000000000000000000000000000000000000000..9f925613a3ec452bf37203b047012e427141098f --- /dev/null +++ b/SorpLib/Media/Solids/package.order @@ -0,0 +1,4 @@ +BaseClasses +Records +Sorbents +MetalsAndMetalAlloys diff --git a/SorpLib/Media/WorkingPairs/BaseClasses/PartialPureCharts.mo b/SorpLib/Media/WorkingPairs/BaseClasses/PartialPureCharts.mo new file mode 100644 index 0000000000000000000000000000000000000000..01fdfeacd527bab552584265f45645aee07e2d3e --- /dev/null +++ b/SorpLib/Media/WorkingPairs/BaseClasses/PartialPureCharts.mo @@ -0,0 +1,251 @@ +within SorpLib.Media.WorkingPairs.BaseClasses; +partial model PartialPureCharts + "Base model that creates an isotherm chart of a pure component working pair" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter SorpLib.Choices.DiagramTypePureComponentWorkingPair diagramType= + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms + "Diagram type: Isotherms, isosters, or isobars" + annotation (Dialog(tab="General", group="Calculation Setup"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Choices.ChangingConstantVariableOfDiagram isoLineType= + SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual + "Changing type of iso-lines: Manual, linearly distributed, or logarithmically + distributed" + annotation (Dialog(tab="General", group="Calculation Setup"), + Evaluate=false, + HideResult=false); + parameter Integer no_isoLines = 10 + "Number of isotherm or isobars" + annotation (Dialog(tab="General", group="Calculation Setup"), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.Pressure p_adsorpt_min = 1000 + "Minimal pressure for diagram of isotherms or isobars" + annotation (Dialog(tab="General", group="Setup Pressure", + enable= + (diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms or + (diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isobars and + isoLineType<> + SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual))), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Pressure p_adsorpt_max = 1e5 + "Maximal pressure for diagram of isotherms or isobars" + annotation (Dialog(tab="General", group="Setup Pressure", + enable= + (diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms or + (diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isobars and + isoLineType<> + SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual))), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Pressure[no_isoLines] p_adsorpt_const= + linspace(p_adsorpt_min, p_adsorpt_max, no_isoLines) + "Constant pressures when using isobars" + annotation (Dialog(tab="General", group="Setup Pressure", + enable= + (diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isobars and + isoLineType== + SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual)), + Evaluate=false, + HideResult=false); + + parameter Modelica.Units.SI.Temperature T_adsorpt_min = 283.15 + "Minimal temperature for diagram of isosters or isotherms" + annotation (Dialog(tab="General", group="Setup Temperature", + enable= + (diagramType<> + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms or + (diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms and + isoLineType<> + SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual))), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Temperature T_adsorpt_max = 373.15 + "Maximal temperature for diagram of isosters or isotherms" + annotation (Dialog(tab="General", group="Setup Temperature", + enable= + (diagramType<> + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms or + (diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms and + isoLineType<> + SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual))), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Temperature[no_isoLines] T_adsorpt_const= + linspace(T_adsorpt_min, T_adsorpt_max, no_isoLines) + "Constant temperatures when using isotherms" + annotation (Dialog(tab="General", group="Setup Temperature", + enable= + (diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms and + isoLineType== + SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual)), + Evaluate=false, + HideResult=false); + + parameter SorpLib.Units.Uptake x_adsorpt_min = 0.05 + "Minimal uptake for diagram of isosters" + annotation (Dialog(tab="General", group="Setup Uptake", + enable= + diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters and + isoLineType<> + SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual), + Evaluate=false, + HideResult=false); + parameter SorpLib.Units.Uptake x_adsorpt_max = 0.2 + "Maximal uptake for diagram of isosters" + annotation (Dialog(tab="General", group="Setup Uptake", + enable= + diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters and + isoLineType<> + SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual), + Evaluate=false, + HideResult=false); + parameter SorpLib.Units.Uptake[no_isoLines] x_adsorpt_const= + linspace(x_adsorpt_min, x_adsorpt_max, no_isoLines) + "Constant uptake when using isosters" + annotation (Dialog(tab="General", group="Setup Uptake", + enable= + (diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters and + isoLineType== + SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual)), + Evaluate=false, + HideResult=false); + + // + // Definition of parameters describing packages and models + // + replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.CO2.ActivatedCarbon_Toth_DantasEtAl2011_Gas + constrainedby + SorpLib.Media.WorkingPairs.BaseClasses.PartialPureWorkingPairs( + final stateVariables=stateVariables, + final calcCaloricProperties=true, + final calcEntropicProperties=true, + final calcDerivativesIsotherm=true, + final calcDerivativesMassEnergyBalance=true, + final calcDerivativesEntropyBalance=true) + "Pure working pair model" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Instanziation of models + // + PureWorkingPairModel[no_isoLines] pureWorkingPair( + final p_adsorpt=p_adsorpt, + final x_adsorpt=x_adsorpt, + final T_adsorpt=T_adsorpt) + "Thermodynamic properties and partial derivatives of a pure working pair"; + + // + // Definition of variables + // + Modelica.Units.SI.Pressure[no_isoLines] p_adsorpt + "Pressure"; + Modelica.Units.SI.Temperature[no_isoLines] T_adsorpt + "Temperature"; + SorpLib.Units.Uptake[no_isoLines] x_adsorpt + "Uptake"; + + // + // Definition of final parameters + // +protected + final parameter Choices.IndependentVariablesPureComponentWorkingPair stateVariables= + if diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters then + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT else + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT + "Independent state variables of the working pair model"; + + // + // Definition of protected variables + // + Modelica.Units.SI.Pressure[no_isoLines] p_adsorpt_const_ + "Constant pressures"; + Modelica.Units.SI.Temperature[no_isoLines] T_adsorpt_const_ + "Constant temperatures"; + SorpLib.Units.Uptake[no_isoLines] x_adsorpt_const_ + "Constant uptakes"; + +equation + // + // Calculate constant variables + // + if isoLineType==SorpLib.Choices.ChangingConstantVariableOfDiagram.Manual then + p_adsorpt_const_=p_adsorpt_const + "Constant pressures"; + T_adsorpt_const_=T_adsorpt_const + "Constant temperatures"; + x_adsorpt_const_=x_adsorpt_const + "Constant uptakes"; + + elseif isoLineType==SorpLib.Choices.ChangingConstantVariableOfDiagram.Linespace then + p_adsorpt_const_=linspace(p_adsorpt_min, p_adsorpt_max, no_isoLines) + "Constant pressures"; + T_adsorpt_const_=linspace(T_adsorpt_min, T_adsorpt_max, no_isoLines) + "Constant temperatures"; + x_adsorpt_const_=linspace(x_adsorpt_min, x_adsorpt_max, no_isoLines) + "Constant uptakes"; + + else + p_adsorpt_const_= + {exp(log(p_adsorpt_min) + (log(p_adsorpt_max) - log(p_adsorpt_min)) * + (i - 1) / (no_isoLines - 1)) for i in 1:no_isoLines} + "Constant pressures"; + T_adsorpt_const_= + {exp(log(T_adsorpt_min) + (log(T_adsorpt_max) - log(T_adsorpt_min)) * + (i - 1) / (no_isoLines - 1)) for i in 1:no_isoLines} + "Constant temperatures"; + x_adsorpt_const_= + {exp(log(x_adsorpt_min) + (log(x_adsorpt_max) - log(x_adsorpt_min)) * + (i - 1) / (no_isoLines - 1)) for i in 1:no_isoLines} + "Constant uptakes"; + + end if; + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06),Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the basic model for all models creating fluid propertey diagrams +for working pair models describing adsorption of pure components. +<br/><br/> +Models that inherit properties from this partial model have to specify the working pair +model <i>PureWorkingPairModel</i> and the test setup. Furthermore, equations must be +added to calculate the inputs <i>p_adsorpt</i>, <i>T_adsorpt</i>, and <i>x_adsorpt</i> +depending on the diagram type (i.e., just two inputs are needed in each case). +</p> +</html>", revisions="<html> +<ul> + <li> + November 23, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureCharts; diff --git a/SorpLib/Media/WorkingPairs/BaseClasses/PartialPureTest.mo b/SorpLib/Media/WorkingPairs/BaseClasses/PartialPureTest.mo new file mode 100644 index 0000000000000000000000000000000000000000..2aeaf08d921013f6d97e8b321160c55ea93e3404 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/BaseClasses/PartialPureTest.mo @@ -0,0 +1,143 @@ +within SorpLib.Media.WorkingPairs.BaseClasses; +partial model PartialPureTest + "Base model for all testers of pure working pair models" + extends Modelica.Icons.Example; + + // + // Definition of parameters describing the test setup + // + parameter Modelica.Units.SI.Pressure p_adsorpt_start = 700 + "Start value of pressure" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter SorpLib.Units.Uptake x_adsorpt_start = 0.10 + "Start value of uptake" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Modelica.Units.SI.Temperature T_adsorpt_start = 303.15 + "Start value of temperature" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + + parameter Real p_adsorpt_der(unit="Pa/s") = (0.4e5-700)/20 + "Prescriped sloped of pressure to test working pair model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Real x_adsorpt_der(unit="kg/(kg.s)") = 0.15/20 + "Prescriped sloped of uptake to test working pair model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + parameter Real T_adsorpt_der(unit="K/s") = 70/20 + "Prescriped sloped of temperature to working pair model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=false, + HideResult=false); + + parameter Choices.IndependentVariablesPureComponentWorkingPair stateVariables= + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT + "Independent state variables of the working pair model" + annotation (Dialog(tab="General", group="Test setup"), + Evaluate=true, + HideResult=true); + + // + // Definition of parameters describing packages and models + // + replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.CO2.ActivatedCarbon_Toth_DantasEtAl2011_Gas + constrainedby + SorpLib.Media.WorkingPairs.BaseClasses.PartialPureWorkingPairs( + final stateVariables=stateVariables, + final p_adsorpt=p_adsorpt, + final x_adsorpt=x_adsorpt, + final T_adsorpt=T_adsorpt, + calcAdsorptAdsorbateState=false, + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron, + x_adsorpt_lb=1e-2) + "Pure working pair model" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Instanziation of models + // + PureWorkingPairModel pureWorkingPair + "Thermodynamic properties and partial derivatives of a pure working pair"; + + // + // Definition of variables + // + Modelica.Units.SI.Pressure p_adsorpt + "Pressure"; + Modelica.Units.SI.Temperature T_adsorpt + "Temperature"; + SorpLib.Units.Uptake x_adsorpt + "Uptake"; + SorpLib.Units.MolarUptake x_adsorpt_m= + x_adsorpt / pureWorkingPair.medium_adsorpt.M_adsorpt + "Molar uptake"; + +initial equation + // + // Definition of start values + // + if stateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT then + p_adsorpt = p_adsorpt_start + "Pressure"; + T_adsorpt = T_adsorpt_start + "Temperature"; + + else + x_adsorpt = x_adsorpt_start + "Uptake"; + T_adsorpt = T_adsorpt_start + "Temperature"; + + end if; + +equation + // + // Definition of slopes + // + if stateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT then + der(p_adsorpt) = p_adsorpt_der + "Predecsriped slope of p_adsorpt"; + der(T_adsorpt) = T_adsorpt_der + "Predescriped slope of T_adsorpt"; + else + der(x_adsorpt) = x_adsorpt_der + "Predecsriped slope of x_adsorpt"; + der(T_adsorpt) = T_adsorpt_der + "Predescriped slope of T_adsorpt"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial model is the basic model for all testers of working pair models describing +adsorption of pure components. +<br/><br/> +Models that inherit properties from this partial model have to specify the working pair +model <i>PureWorkingPairModel</i> and the test setup. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureTest; diff --git a/SorpLib/Media/WorkingPairs/BaseClasses/PartialPureWorkingPairs.mo b/SorpLib/Media/WorkingPairs/BaseClasses/PartialPureWorkingPairs.mo new file mode 100644 index 0000000000000000000000000000000000000000..82b89ef5d0012a1dd4d0f0182055884e06507918 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/BaseClasses/PartialPureWorkingPairs.mo @@ -0,0 +1,1463 @@ +within SorpLib.Media.WorkingPairs.BaseClasses; +partial model PartialPureWorkingPairs + "Base model for pure component working pairs" + extends Modelica.Icons.MaterialProperty; + + // + // Definition of parameters regarding the working pair and medium + // + replaceable package WorkingPair = + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization + constrainedby + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization( + redeclare final model Sorbent = Sorbent) + "Parametrized working pair model" + annotation (Dialog(tab = "General", group = "Working Pair and Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid( + final calcCaloricProperties=calcCaloricProperties, + final calcEntropicProperties=calcEntropicProperties, + final p=p_adsorpt_, + final T=T_adsorpt, + final approach_v=SorpLib.Choices.SpecificVolumeSolid.Constant, + final p_ref=p_sorbent_ref, + final T_ref=T_sorbent_ref, + final h_ref=h_sorbent_ref, + final s_ref=s_sorbent_ref, + final tolerance_int_h=tolerance_sorbent_int_h, + final tolerance_int_s=tolerance_sorbent_int_s) + "Calculates the thermodynamic properties of the sorbent" + annotation (Dialog(tab = "General", group = "Working Pair and Medium"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + // + // Definition of parameters regarding the calculation approach + // + parameter SorpLib.Choices.IndependentVariablesPureComponentWorkingPair + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT + "Independent state variables of the working pair model" + annotation (Dialog(tab="General", group="Calculation Setup"), + choicesAllMatching=true, + Evaluate=true, + HideResult=true); + + parameter Boolean calcCaloricProperties = true + "= true, if caloric properties are calculated (i.e., h, u, h_ads, and cp)" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcEntropicProperties = true + "= true, if caloric properties are calculated (i.e., s, g, a, and s_ads)" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean calcAdsorptAdsorbateState = false + "= true, if state properties of average adsorpt phase and adosrbate phase are + calculated (i.e., requires numerical integration)" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean calcDerivativesIsotherm = true + "= true, if partial derivatives of isotherms required for mass, energy, and + entropy balance of working paur volumes are calculated" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcDerivativesMassEnergyBalance = true + "= true, if partial derivatives required for mass and energy balance of + working pair volumes are calculated" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcDerivativesIsotherm and calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcDerivativesEntropyBalance = true + "= true, if partial derivatives required for entropy balance of working + pair volumes are calculated" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcDerivativesIsotherm and + calcDerivativesMassEnergyBalance and calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean adsorptiveAtDewPoint = false + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = WorkingPair.twoPhaseAdsorptive), + Evaluate=true, + choices(checkBox=true)); + + // + // Definition of parameters regarding sorption enthalpy + // + parameter SorpLib.Choices.SorptionEnthalpy approachSorptionEnthalpy= + SorpLib.Choices.SorptionEnthalpy.Constant + "Calculation approach for the sorption enthalpy" + annotation (Dialog(tab="Sorption Enthalpy", group="General"), + Evaluate=false, + choicesAllMatching=true); + + parameter Modelica.Units.SI.SpecificEnthalpy h_ads_constant= 2750e3 + "Constant specific enthalpy of adsorption" + annotation (Dialog(tab="Sorption Enthalpy", group="Constant", + enable=(approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Constant)), + HideResult=true, + Evaluate= false); + + // + // Definition of parameters regarding adsorpt phase's specific heat capacity + // + parameter SorpLib.Choices.SpecificHeatCapacityAdsorpt + approachSpecificHeatCapacity= + SorpLib.Choices.SpecificHeatCapacityAdsorpt.Constant + "Calculation approach for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="General"), + Evaluate=false, + choicesAllMatching=true); + + parameter Modelica.Units.SI.SpecificHeatCapacity cp_adsorpt_constant= 4e3 + "Constant specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Constant", + enable=(approachSpecificHeatCapacity == + SorpLib.Choices.SpecificVolumeAdsorpt.Constant)), + HideResult=true, + Evaluate= false); + + parameter SorpLib.Choices.GeneralizedFunctionApproach cp_adsorpt_function= + SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Generalized function used to calculate the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", + group="Generalized Function", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + Evaluate=true); + parameter Modelica.Units.SI.Temperature T_ref_cp_adsorpt = 293.15 + "Reference temperature for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Modelica.Units.SI.SpecificHeatCapacity cp_adsorpt_ref = 1 + "Reference fluid property data for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real coefficients_cp_adsorpt[:]={cp_adsorpt_constant} + "Coefficients of generalized function for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real exponents_cp_adsorpt[size(coefficients_cp_adsorpt,1)]={0} + "Exponents of generalized function for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + + parameter SorpLib.Choices.InterpolationApproach cp_adsorpt_interpolation= + SorpLib.Choices.InterpolationApproach.Linear + "Interpolation approach used to calculate the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", + group="Interpolation", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.Interpolation)), + Evaluate=false); + parameter Real abscissa_cp_adsorpt[:]={0, 1000} + "Known abscissa values for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Interpolation", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.Interpolation)), + HideResult=true, + Evaluate= true); + parameter Real ordinate_cp_adsorpt[size(abscissa_cp_adsorpt,1)]= + {cp_adsorpt_constant, cp_adsorpt_constant} + "Known ordinate values for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Interpolation", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificHeatCapacityAdsorpt.Interpolation)), + HideResult=true, + Evaluate= true); + final parameter Real coefficients_cubicSplines_cp_adsorpt[size(abscissa_cp_adsorpt,1),4]= + SorpLib.Media.Functions.Utilities.calcCubicSplineCoefficients( + abscissa=abscissa_cp_adsorpt, + ordinate=ordinate_cp_adsorpt) + "Coefficient a to d for cubic polynomials for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Interpolation", + enable=false), + HideResult=true, + Evaluate= true); + + // + // Definition of parameters regarding adsorpt phase's specific volume + // + parameter Boolean neglectSpecifcVolume = false + "= true, if specific volume of the adsorpt is neglected (i.e., v_adsorpt = 0 + -> u_adsorpt = h_adsorpt and g_adsorpt = a_adsorpt)" + annotation (Dialog(tab = "Specific Volume", group = "General"), + choices(checkBox=true), + Evaluate= false); + parameter SorpLib.Choices.SpecificVolumeAdsorpt approachSpecificVolume= + SorpLib.Choices.SpecificVolumeAdsorpt.Constant + "Calculation approach for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="General", + enable=not neglectSpecifcVolume), + Evaluate=false, + choicesAllMatching=true); + + parameter Modelica.Units.SI.SpecificVolume v_adsorpt_constant= 1e-3 + "Constant specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Constant", + enable=(not neglectSpecifcVolume and approachSpecificVolume== + SorpLib.Choices.SpecificVolumeAdsorpt.Constant)), + HideResult=true, + Evaluate= false); + + parameter SorpLib.Choices.GeneralizedFunctionApproach v_adsorpt_function= + SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Generalized function used to calculate the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(not neglectSpecifcVolume and approachSpecificVolume== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + Evaluate=true); + parameter Modelica.Units.SI.Temperature T_ref_v_adsorpt = 293.15 + "Reference temperature for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(not neglectSpecifcVolume and approachSpecificVolume== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Modelica.Units.SI.SpecificVolume v_adsorpt_ref = 1 + "Reference fluid property data for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(not neglectSpecifcVolume and approachSpecificVolume== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real coefficients_v_adsorpt[:]={v_adsorpt_constant} + "Coefficients of generalized function for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real exponents_v_adsorpt[size(coefficients_v_adsorpt,1)]={0} + "Exponents of generalized function for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + + parameter SorpLib.Choices.InterpolationApproach v_adsorpt_interpolation= + SorpLib.Choices.InterpolationApproach.Linear + "Interpolation approach used to calculate the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume",group="Interpolation", + enable=(not neglectSpecifcVolume and approachSpecificVolume== + SorpLib.Choices.SpecificVolumeAdsorpt.Interpolation)), + Evaluate=false); + parameter Real abscissa_v_adsorpt[:]={0, 1000} + "Known abscissa values for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Interpolation", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.Interpolation)), + HideResult=true, + Evaluate= true); + parameter Real ordinate_v_adsorpt[size(abscissa_v_adsorpt,1)]= + {v_adsorpt_constant, v_adsorpt_constant} + "Known ordinate values for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Interpolation", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.Interpolation)), + HideResult=true, + Evaluate= true); + final parameter Real coefficients_cubicSplines_v_adsorpt[size(abscissa_v_adsorpt,1),4]= + SorpLib.Media.Functions.Utilities.calcCubicSplineCoefficients( + abscissa=abscissa_v_adsorpt, + ordinate=ordinate_v_adsorpt) + "Coefficient a to d for cubic polynomials for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Interpolation", + enable=false), + HideResult=true, + Evaluate= true); + + // + // Definition of parameters regarding advanced options + // + parameter Boolean avoidEvents = false + "= true, if events are avoided using the noEvent()-operator" + annotation (Dialog(tab = "Advanced", group = "General"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean limitLowerPressure = false + "= true, if pressure p_adsorpt is limited to p_adsorpt_min" + annotation (Dialog(tab = "Advanced", group = "Limiter"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean limitLowerPressureAdsorptive = false + "= true, if pressure p_adsorpt is limited to p_adsorpt_min only for property + calculation (i.e., properties of the adsorptive)" + annotation (Dialog(tab = "Advanced", group = "Limiter", + enable=not limitLowerPressure), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Pressure p_adsorpt_min = 615 + "Lower limit for the pressure p_adsorpt" + annotation (Dialog(tab = "Advanced", group = "Limiter", + enable=limitLowerPressure or limitLowerPressureAdsorptive), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.Pressure p_adsorpt_lb_start = 1e3 + "Lower bound if function p_adsorpt(x_adsorpt, T_adsorpt) is calculated numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Inverses"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Pressure p_adsorpt_ub_start = 1e4 + "Upper bound if function p_adsorpt(x_adsorpt, T_adsorpt) is calculated numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Inverses"), + Evaluate=true, + HideResult=true); + parameter Real tolerance_p_adsorpt = 100*Modelica.Constants.eps + "Tolerance if function p_adsorpt(x_adsorpt, T_adsorpt) is calculated numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Inverses"), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference used when calculating partial derivatives numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Derivatives"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used when calculating partial derivatives numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Derivatives"), + Evaluate=true, + HideResult=true); + parameter SorpLib.Units.Uptake dx = 1e-3 + "Uptake difference used when calculating partial derivatives numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Derivatives"), + Evaluate=true, + HideResult=true); + + parameter Real tolerance_sorbent_int_h = 1e-2 + "Integration tolerance when calculating the specific enthalpy of the sorbent + numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Integrals", + enable=calcCaloricProperties), + Evaluate=true, + HideResult=true); + parameter Real tolerance_sorbent_int_s = 1e-2 + "Integration tolerance when calculating the specific entropy of the sorbent + numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Integrals", + enable=calcEntropicProperties), + Evaluate=true, + HideResult=true); + parameter Real tolerance_adsorpt_int_h = 1e-2 + "Integration tolerance when calculating the specific average enthalpy of the + adsorpt numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Integrals", + enable=calcAdsorptAdsorbateState and calcCaloricProperties), + Evaluate=true, + HideResult=true); + parameter Real tolerance_adsorpt_int_s = 1e-2 + "Integration tolerance when calculating the specific average entropy of the + adsorpt numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Integrals", + enable=calcAdsorptAdsorbateState and calcEntropicProperties), + Evaluate=true, + HideResult=true); + parameter Real tolerance_adsorpt_int_cp = 1e-2 + "Integration tolerance when calculating the specific heat capacity of the + adsorpt numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Integrals", + enable=calcCaloricProperties and ( + approachSpecificHeatCapacity== + SorpLib.Choices.SpecificHeatCapacityAdsorpt.WaltonLeVan or + approachSpecificHeatCapacity== + SorpLib.Choices.SpecificHeatCapacityAdsorpt.SchwambergerSchmidt)), + Evaluate=true, + HideResult=true); + parameter SorpLib.Units.Uptake x_adsorpt_lb = 0 + "Lower limit for integral when calculating the specific heat capacity of the + adsorpt or uptake-averaged porperties of the adsorpt numerically (i.e., + should be zero)" + annotation (Dialog(tab="Advanced", group="Numerics - Integrals", + enable=calcCaloricProperties and ( + calcAdsorptAdsorbateState or + approachSpecificHeatCapacity== + SorpLib.Choices.SpecificHeatCapacityAdsorpt.WaltonLeVan or + approachSpecificHeatCapacity== + SorpLib.Choices.SpecificHeatCapacityAdsorpt.SchwambergerSchmidt)), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.Pressure p_sorbent_ref = 1e5 + "Reference pressure for caloric and entropic calculations (i.e., per mass + sorbent)" + annotation (Dialog(tab="Advanced", group="Reference State - Sorbent", + enable=calcCaloricProperties or calcEntropicProperties), + Evaluate=true); + parameter Modelica.Units.SI.Temperature T_sorbent_ref = 298.15 + "Reference temperature for caloric and entropic calculations (i.e., per mass + sorbent)" + annotation (Dialog(tab="Advanced", group="Reference State - Sorbent", + enable=calcCaloricProperties or calcEntropicProperties), + Evaluate=true); + parameter Modelica.Units.SI.SpecificEnthalpy h_sorbent_ref= + WorkingPair.MediumSpecificFunctions.h_pT( + p=p_sorbent_ref, + T=T_sorbent_ref, + p_lb=p_adsorpt_min, + h_ref=0, + p_ref=p_sorbent_ref, + T_ref=T_sorbent_ref) + "Specific enthalpy of adsorptive at reference state (i.e., per mass sorbent)" + annotation (Dialog(tab="Advanced", group="Reference State - Sorbent", + enable=calcCaloricProperties or calcEntropicProperties), + Evaluate=true); + parameter Modelica.Units.SI.SpecificEntropy s_sorbent_ref= + WorkingPair.MediumSpecificFunctions.s_pT( + p=p_sorbent_ref, + T=T_sorbent_ref, + p_lb=p_adsorpt_min, + s_ref=0, + p_ref=p_sorbent_ref, + T_ref=T_sorbent_ref) + "Specific entropy of adsorptive at reference state (i.e., per mass sorbent)" + annotation (Dialog(tab="Advanced", group="Reference State - Sorbent", + enable=calcEntropicProperties), + Evaluate=true); + + // + // Definition of inputs + // + input SorpLib.Units.Uptake x_adsorpt + "Equilibrium uptake" + annotation (Dialog(tab = "General", group = "Inputs", + enable=false)); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature" + annotation (Dialog(tab = "General", group = "Inputs", + enable=false)); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure" + annotation (Dialog(tab = "General", group = "Outputs", enable = false)); + + output SorpLib.Media.WorkingPairs.Records.StateVariables state_sorbent + "State properties of the sorbent (i.e., per sorbent mass)" + annotation (Dialog(tab = "General", group = "Outputs", enable = false)); + output SorpLib.Media.WorkingPairs.Records.StateVariables state_lastAdsorbedMolecule + "State properties of the last adsorbed molecule (i.e., per adsorptive/adsorpt + mass)" + annotation (Dialog(tab = "General", group = "Outputs", enable = false)); + output SorpLib.Media.WorkingPairs.Records.StateVariables state_averageAdsorpt + "State properties of the uptake-averaged adsorpt (i.e., per adsorptive/ + adsorpt mass)" + annotation (Dialog(tab = "General", group = "Outputs", enable = false)); + output SorpLib.Media.WorkingPairs.Records.StateVariables state_averageAdsorbate + "State properties of the adsorbate (i.e., per sorbent mass)" + annotation (Dialog(tab = "General", group = "Outputs", enable = false)); + output SorpLib.Media.WorkingPairs.Records.StateVariables state_adsorptive + "State properties of the vapor/gas (i.e., per adsorptive/adsorpt mass)" + annotation (Dialog(tab = "General", group = "Outputs", enable = false)); + + output SorpLib.Media.WorkingPairs.Records.DerivativesPureIsothermModel + derivatives_isotherm "Partial derivatives of the isotherm model" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + output SorpLib.Media.WorkingPairs.Records.DerivativesPureMassEnergyBalances + derivatives_massEnergy + "Partial derivatives regarding mass and energy balances" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + output SorpLib.Media.WorkingPairs.Records.DerivativesPureEntropyBalance + derivatives_entropy "Partial derivatives regarding entropy balances" + annotation (Dialog( + tab="General", + group="Outputs", + enable=false)); + + // + // Definition of variables + // + Modelica.Units.SI.SpecificEnthalpy h_ads(displayUnit="kJ/kg") + "Specific enthalpy of adsorption"; + Modelica.Units.SI.SpecificEntropy s_ads(displayUnit="kJ/(kg.K)") + "Specific entropy of adsorption"; + + Modelica.Units.SI.SpecificHeatCapacity cp_adsorpt + "Specific heat capacity of the adsorpt"; + + // + // Instantiation of models + // + WorkingPair.Sorbent medium_sorbent + "State properties of the sorbent"; + + WorkingPair.AdsorptProperties medium_adsorpt( + final stateVariables=stateVariables, + final calcCaloricProperties=calcCaloricProperties, + final calcEntropicProperties=calcEntropicProperties, + final calcAdsorptAdsorbateState=calcAdsorptAdsorbateState, + final calcDerivativesIsotherm=calcDerivativesIsotherm, + final calcDerivativesMassEnergyBalance=calcDerivativesMassEnergyBalance, + final calcDerivativesEntropyBalance=calcDerivativesEntropyBalance, + final adsorptiveAtDewPoint=adsorptiveAtDewPoint, + final c=isothermCoefficients.c, + final dc_dT_adsorpt=isothermCoefficients.dc_dT, + final ddc_dT_adsorpt_dT_adsorpt=isothermCoefficients.ddc_dT_dT, + final p_adsorpt=p_adsorpt_, + final T_adsorpt=T_adsorpt, + final x_adsorpt=x_adsorpt, + final properties_adsorptive=medium_adsorptive.properties, + final approachSorptionEnthalpy=approachSorptionEnthalpy, + final h_ads_constant=h_ads_constant, + final approachSpecificHeatCapacity = approachSpecificHeatCapacity, + final cp_adsorpt_constant = cp_adsorpt_constant, + final cp_adsorpt_function = cp_adsorpt_function, + final T_ref_cp_adsorpt = T_ref_cp_adsorpt, + final cp_adsorpt_ref = cp_adsorpt_ref, + final coefficients_cp_adsorpt = coefficients_cp_adsorpt, + final exponents_cp_adsorpt = exponents_cp_adsorpt, + final cp_adsorpt_interpolation = cp_adsorpt_interpolation, + final abscissa_cp_adsorpt = abscissa_cp_adsorpt, + final ordinate_cp_adsorpt = ordinate_cp_adsorpt, + final coefficients_cubicSplines_cp_adsorpt = coefficients_cubicSplines_cp_adsorpt, + final neglectSpecifcVolume=neglectSpecifcVolume, + final approachSpecificVolume=approachSpecificVolume, + final v_adsorpt_constant=v_adsorpt_constant, + final v_adsorpt_function=v_adsorpt_function, + final T_ref_v_adsorpt=T_ref_v_adsorpt, + final v_adsorpt_ref=v_adsorpt_ref, + final coefficients_v_adsorpt=coefficients_v_adsorpt, + final exponents_v_adsorpt=exponents_v_adsorpt, + final v_adsorpt_interpolation=v_adsorpt_interpolation, + final abscissa_v_adsorpt=abscissa_v_adsorpt, + final ordinate_v_adsorpt=ordinate_v_adsorpt, + final coefficients_cubicSplines_v_adsorpt=coefficients_cubicSplines_v_adsorpt, + final p_adsorpt_min=p_adsorpt_min, + final dp=dp, + final dT=dT, + final tolerance_adsorpt_int_h=tolerance_adsorpt_int_h, + final tolerance_adsorpt_int_s=tolerance_adsorpt_int_s, + final tolerance_adsorpt_int_cp=tolerance_adsorpt_int_cp, + final x_adsorpt_lb=x_adsorpt_lb) + "Properties of the adsorptive required for calculation: These properties are + calculated at once to save computational costs"; + + WorkingPair.MediumSpecificFunctions.AdsorptiveProperties medium_adsorptive( + final calcCaloricProperties=calcCaloricProperties, + final calcEntropicProperties=calcEntropicProperties, + final calcAdsorptAdsorbateState=calcAdsorptAdsorbateState, + final calcDerivativesIsotherm=calcDerivativesIsotherm, + final calcDerivativesMassEnergyBalance=calcDerivativesMassEnergyBalance, + final calcDerivativesEntropyBalance=calcDerivativesEntropyBalance, + final adsorptiveAtDewPoint=adsorptiveAtDewPoint, + final neglectSpecifcVolume=neglectSpecifcVolume, + final approachSpecificVolume=approachSpecificVolume, + final approachSpecificHeatCapacity=approachSpecificHeatCapacity, + final approachSorptionEnthalpy=approachSorptionEnthalpy, + final dp=dp, + final dT=dT, + final p=if limitLowerPressure then p_adsorpt_ elseif + limitLowerPressureAdsorptive then max(p_adsorpt_min, p_adsorpt_) else + p_adsorpt_, + final T=T_adsorpt) + "Properties of the adsorptive required for calculation: These properties are + calculated at once to save computational costs"; + + WorkingPair.IsothermCoefficients isothermCoefficients( + final T_adsorpt=T_adsorpt, + final dT=dT) + "Temperature-dependent isotherm coefficients"; + + // + // Booleans indicating which variables msut be calculated + // +protected + parameter Boolean require_derivativesMassEnergyBalances_pT= + (calcCaloricProperties and calcDerivativesIsotherm and + calcDerivativesMassEnergyBalance) + "= true, if partial derivatives of mass and energy balances w.r.t. pressure + and temperature are required"; + parameter Boolean require_derivativesMassEnergyBalances_xT= + (require_derivativesMassEnergyBalances_pT and stateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT) + "= true, if partial derivatives of mass and energy balances w.r.t. uptake + and temperature are required"; + + parameter Boolean require_derivativesEntropyBalances_pT= + (require_derivativesMassEnergyBalances_pT and calcDerivativesEntropyBalance) + "= true, if partial derivatives of the entropy balance w.r.t. pressure and + temperature are required"; + parameter Boolean require_derivativesEntropyBalances_xT= + (require_derivativesEntropyBalances_pT and stateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT) + "= true, if partial derivatives of the entropy balance w.r.t. uptake and + temperature are required"; + + // + // Auxillary variables + // + Modelica.Units.SI.Pressure p_adsorpt_ + "Equilibrium pressure that might be limited"; + +equation + // + // Pass state properties of the sorbent (per sorbent mass) + // + state_sorbent = medium_sorbent.state_variables + "State properties of the sorbent (i.e., per sorbent mass)"; + + // + // Calculate thermal state properties of the last adsorbed molecule + // (per adsorptive/adsorpt mass) + // + if stateVariables == + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT then + p_adsorpt_ = if limitLowerPressure then + max(p_adsorpt_min, WorkingPair.IsothermModel.p_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=isothermCoefficients.c, + p_adsorpt_lb_start=p_adsorpt_lb_start, + p_adsorpt_ub_start=p_adsorpt_ub_start, + tolerance=tolerance_p_adsorpt)) else + WorkingPair.IsothermModel.p_xT( + x_adsorpt=x_adsorpt, + T_adsorpt=T_adsorpt, + c=isothermCoefficients.c, + p_adsorpt_lb_start=p_adsorpt_lb_start, + p_adsorpt_ub_start=p_adsorpt_ub_start, + tolerance=tolerance_p_adsorpt) + "Equilibrium pressure that might be limited"; + + p_adsorpt = p_adsorpt_ + "Equilibrium pressure"; + + else + p_adsorpt_ = if limitLowerPressure + then max(p_adsorpt_min, p_adsorpt) else p_adsorpt + "Equilibrium pressure that might be limited"; + + x_adsorpt = WorkingPair.IsothermModel.x_pT( + p_adsorpt= p_adsorpt_, + T_adsorpt=T_adsorpt, + c=isothermCoefficients.c, + p_adsorpt_lb_start=p_adsorpt_lb_start, + p_adsorpt_ub_start=p_adsorpt_ub_start, + tolerance=tolerance_p_adsorpt) + "Equilibrium uptake"; + + end if; + + state_lastAdsorbedMolecule.p = p_adsorpt_ + "Equilibrium pressure"; + state_lastAdsorbedMolecule.T = T_adsorpt + "Equilibrium temperautre"; + + state_lastAdsorbedMolecule.v = if neglectSpecifcVolume then 0 else + medium_adsorpt.properties.v + "Specific volume of the adsorpt"; + + // + // Calculate caloric state properties of the last adsorbed molecule + // (per adsorptive/adsorpt mass) + // + state_lastAdsorbedMolecule.h = + if not calcCaloricProperties then 0 else + medium_adsorptive.properties.state.h - h_ads + "Specific enthalpy of the adsorpt"; + state_lastAdsorbedMolecule.u = + if not calcCaloricProperties then 0 else + state_lastAdsorbedMolecule.h - state_lastAdsorbedMolecule.p * + state_lastAdsorbedMolecule.v + "Specific internal energy of the adsorpt"; + + // + // Calculate entropic state properties of the last adsorbed molecule + // (per adsorptive/adsorpt mass) + // + state_lastAdsorbedMolecule.s = + if not (calcCaloricProperties and calcEntropicProperties) then 0 else + medium_adsorptive.properties.state.s - s_ads + "Specific entropy of the adsorpt"; + state_lastAdsorbedMolecule.g = + if not (calcCaloricProperties and calcEntropicProperties) then 0 else + state_lastAdsorbedMolecule.h - T_adsorpt * state_lastAdsorbedMolecule.s + "Free enthalpy (i.e., Gibbs free energy) of the adsorpt"; + state_lastAdsorbedMolecule.a = + if not (calcCaloricProperties and calcEntropicProperties) then 0 else + state_lastAdsorbedMolecule.u - T_adsorpt * state_lastAdsorbedMolecule.s + "Free energy (i.e., Helmholts free energy) of the adsorpt"; + + // + // Pass state properties of the uptake-averaged adsorpt + // (per adsorptive/adsorpt mass) + // + state_averageAdsorpt.p = medium_adsorpt.properties.state.p + "Equilibrium pressure"; + state_averageAdsorpt.T = medium_adsorpt.properties.state.T + "Equilibrium temperature"; + state_averageAdsorpt.v = medium_adsorpt.properties.state.v + "Uptake-averaged specific volume of the adsorpt"; + + state_averageAdsorpt.h = medium_adsorpt.properties.state.h + "Uptake-averaged specific enthalpy of the adsorpt"; + state_averageAdsorpt.u = medium_adsorpt.properties.state.u + "Uptake-averaged specific internal energy of the adsorpt"; + + state_averageAdsorpt.s = medium_adsorpt.properties.state.s + "Uptake-averaged specific entropy of the adsorpt"; + state_averageAdsorpt.g = medium_adsorpt.properties.state.g + "Uptake-averaged specific free enthalpy (i.e., Gibbs free energy) of the + adsorpt"; + state_averageAdsorpt.a = medium_adsorpt.properties.state.a + "Uptake-averaged specific free energy (i.e., Helmholts free energy) of the + adsorpt"; + + // + // Pass state properties of the uptake-averaged adsorbate (per sorbent mass) + // + state_averageAdsorbate.p = if not calcAdsorptAdsorbateState then 0 else + state_averageAdsorpt.p + "Equilibrium pressure"; + state_averageAdsorbate.T = if not calcAdsorptAdsorbateState then 0 else + state_averageAdsorpt.T + "Equilibrium temperature"; + state_averageAdsorbate.v = if not calcAdsorptAdsorbateState then 0 else + state_sorbent.v + x_adsorpt * state_averageAdsorpt.v + "Uptake-averaged specific volume of the adsorbate"; + + state_averageAdsorbate.h = if not calcAdsorptAdsorbateState then 0 else + state_sorbent.h + x_adsorpt * state_averageAdsorpt.h + "Uptake-averaged specific enthalpy of the adsorbate"; + state_averageAdsorbate.u = if not calcAdsorptAdsorbateState then 0 else + state_sorbent.u + x_adsorpt * state_averageAdsorpt.u + "Uptake-averaged specific internal energy of the adsorbate"; + + state_averageAdsorbate.s = if not calcAdsorptAdsorbateState then 0 else + state_sorbent.s + x_adsorpt * state_averageAdsorpt.s + "Uptake-averaged specific entropy of the adsorbate"; + state_averageAdsorbate.g = if not calcAdsorptAdsorbateState then 0 else + state_sorbent.g + x_adsorpt * state_averageAdsorpt.g + "Uptake-averaged specific free enthalpy (i.e., Gibbs free energy) of the + adsorbate"; + state_averageAdsorbate.a = if not calcAdsorptAdsorbateState then 0 else + state_sorbent.a + x_adsorpt * state_averageAdsorpt.a + "Uptake-averaged specific free energy (i.e., Helmholts free energy) of the + adsorbate"; + + // + // Pass state properties of the adsorptive (per adsorptive/adsorpt mass) + // + state_adsorptive = medium_adsorptive.properties.state + "State properties of the adsorptive at vapor/gas phase"; + + // + // Pass and calculate additional properties + // + h_ads = medium_adsorpt.properties.h_ads + "Specific enthalpy of adsorption"; + s_ads = + if not (calcCaloricProperties and calcEntropicProperties) then 0 else + h_ads / T_adsorpt + "Specific entropy of adsorption"; + + cp_adsorpt = medium_adsorpt.properties.cp + "Specific heat capacity of the adsorpt"; + + // + // Pass partial derivatives of the isotherm model + // + derivatives_isotherm.dx_dp_T = + medium_adsorpt.properties.derivatives_isotherm.dx_dp_T + "Partial derivative of the uptake w.r.t. pressure at constant temperature"; + derivatives_isotherm.dx_dT_p = + medium_adsorpt.properties.derivatives_isotherm.dx_dT_p + "Partial derivative of the uptake w.r.t. temperature at constant pressure"; + + derivatives_isotherm.dp_dx_T = + medium_adsorpt.properties.derivatives_isotherm.dp_dx_T + "Partial derivative of the uptake w.r.t. uptake at constant temperature"; + derivatives_isotherm.dp_dT_x = + medium_adsorpt.properties.derivatives_isotherm.dp_dT_x + "Partial derivative of the uptake w.r.t. temperature at constant uptake"; + + // + // Pass and calculate partial derivatives regarding the mass and energy balance + // + derivatives_massEnergy.dv_sorbent_dp_T = + if not require_derivativesMassEnergyBalances_pT then 0 else 0 + "Partial derivative of the specific volume of the sorbent w.r.t. pressure at + constant temperature (i.e., ideal solid: v_solid = const.)"; + derivatives_massEnergy.dv_sorbent_dT_p = + if not require_derivativesMassEnergyBalances_pT then 0 else 0 + "Partial derivative of the specific volume of the sorbent w.r.t. temperature + at constant pressure (i.e., ideal solid: v_solid = const."; + derivatives_massEnergy.dv_sorbent_dx_T = + if not require_derivativesMassEnergyBalances_xT then 0 else + derivatives_massEnergy.dv_sorbent_dp_T * derivatives_isotherm.dp_dx_T + "Partial derivative of the specific volume of the sorbent w.r.t. uptake at + constant temperature"; + derivatives_massEnergy.dv_sorbent_dT_x = + if not require_derivativesMassEnergyBalances_xT then 0 else + derivatives_massEnergy.dv_sorbent_dT_p + + derivatives_massEnergy.dv_sorbent_dp_T * derivatives_isotherm.dp_dT_x + "Partial derivative of the specific volume of the sorbent w.r.t. temperature + at constant uptake"; + + derivatives_massEnergy.dh_sorbent_dp_T = + if not require_derivativesMassEnergyBalances_pT then 0 else + state_sorbent.v + "Partial derivative of the specific enthalpy of the sorbent w.r.t. pressure + at constant temperature (i.e., beta_sorbent = 0)"; + derivatives_massEnergy.dh_sorbent_dT_p = + if not require_derivativesMassEnergyBalances_pT then 0 else + medium_sorbent.additional_variables.c + "Partial derivative of the specific enthalpy of the sorbent w.r.t. temperature + at constant pressure"; + derivatives_massEnergy.dh_sorbent_dx_T = + if not require_derivativesMassEnergyBalances_xT then 0 else + derivatives_massEnergy.dh_sorbent_dp_T * derivatives_isotherm.dp_dx_T + "Partial derivative of the specific enthalpy of the sorbent w.r.t. uptake + at constant temperature"; + derivatives_massEnergy.dh_sorbent_dT_x = + if not require_derivativesMassEnergyBalances_xT then 0 else + derivatives_massEnergy.dh_sorbent_dT_p + + derivatives_massEnergy.dh_sorbent_dp_T * derivatives_isotherm.dp_dT_x + "Partial derivative of the specific enthalpy of the sorbent w.r.t. temperature + at constant uptake"; + + derivatives_massEnergy.dxv_avg_adsorpt_dp_T = + if not require_derivativesMassEnergyBalances_pT then 0 else + medium_adsorpt.properties.dxv_avg_dp_T + "Partial derivative of the uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. pressure at constant temperature"; + derivatives_massEnergy.dxv_avg_adsorpt_dT_p = + if not require_derivativesMassEnergyBalances_pT then 0 else + medium_adsorpt.properties.dxv_avg_dT_p + "Partial derivative of the uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. temperature at constant pressure"; + derivatives_massEnergy.dxv_avg_adsorpt_dx_T = + if not require_derivativesMassEnergyBalances_xT then 0 else + derivatives_massEnergy.dxv_avg_adsorpt_dp_T * derivatives_isotherm.dp_dx_T + "Partial derivative of the uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. uptake at constant temperature"; + derivatives_massEnergy.dxv_avg_adsorpt_dT_x = + if not require_derivativesMassEnergyBalances_xT then 0 else + derivatives_massEnergy.dxv_avg_adsorpt_dT_p + + derivatives_massEnergy.dxv_avg_adsorpt_dp_T * derivatives_isotherm.dp_dT_x + "Partial derivative of the uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. temperature at constant uptake"; + + derivatives_massEnergy.dxh_avg_adsorpt_dp_T = + if not require_derivativesMassEnergyBalances_pT then 0 else + medium_adsorpt.properties.dxh_avg_dp_T + "Partial derivative of the uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. pressure at constant temperature"; + derivatives_massEnergy.dxh_avg_adsorpt_dT_p = + if not require_derivativesMassEnergyBalances_pT then 0 else + medium_adsorpt.properties.dxh_avg_dT_p + "Partial derivative of the uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. temperature at constant pressure"; + derivatives_massEnergy.dxh_avg_adsorpt_dx_T = + if not require_derivativesMassEnergyBalances_xT then 0 else + medium_adsorpt.properties.dxh_avg_dx_T + "Partial derivative of the uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. uptake at constant temperature"; + derivatives_massEnergy.dxh_avg_adsorpt_dT_x = + if not require_derivativesMassEnergyBalances_xT then 0 else + medium_adsorpt.properties.dxh_avg_dT_x + "Partial derivative of the uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. temperature at constant uptake"; + + // + // Pass and calculate partial derivatives regarding the entropy balance + // + derivatives_entropy.ds_sorbent_dp_T = + if not require_derivativesEntropyBalances_pT then 0 else 0 + "Partial derivative of the specific entropy of the sorbent w.r.t. pressure + at constant temperature (i.e., ideal solid: v_solid = const.)"; + derivatives_entropy.ds_sorbent_dT_p = + if not require_derivativesEntropyBalances_pT then 0 else + medium_sorbent.additional_variables.c / T_adsorpt + "Partial derivative of the specific entropy of the sorbent w.r.t. temperature + at constant pressure"; + derivatives_entropy.ds_sorbent_dx_T = + if not require_derivativesEntropyBalances_xT then 0 else + derivatives_entropy.ds_sorbent_dp_T * derivatives_isotherm.dp_dx_T + "Partial derivative of the specific entropy of the sorbent w.r.t. uptake + at constant temperature"; + derivatives_entropy.ds_sorbent_dT_x = + if not require_derivativesEntropyBalances_xT then 0 else + derivatives_entropy.ds_sorbent_dT_p + + derivatives_entropy.ds_sorbent_dp_T * derivatives_isotherm.dp_dT_x + "Partial derivative of the specific entropy of the sorbent w.r.t. temperature + at constant uptake"; + + derivatives_entropy.dxs_avg_adsorpt_dp_T = + if not require_derivativesEntropyBalances_pT then 0 else + medium_adsorpt.properties.dxs_avg_dp_T + "Partial derivative of the uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. pressure at constant temperature"; + derivatives_entropy.dxs_avg_adsorpt_dT_p = + if not require_derivativesEntropyBalances_pT then 0 else + medium_adsorpt.properties.dxs_avg_dT_p + "Partial derivative of the uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. temperature at constant pressure"; + derivatives_entropy.dxs_avg_adsorpt_dx_T = + if not require_derivativesEntropyBalances_xT then 0 else + medium_adsorpt.properties.dxs_avg_dx_T + "Partial derivative of the uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. uptake at constant temperature"; + derivatives_entropy.dxs_avg_adsorpt_dT_x = + if not require_derivativesEntropyBalances_xT then 0 else + medium_adsorpt.properties.dxs_avg_dT_x + "Partial derivative of the uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. temperature at constant uptake"; + + // + // Assertations + // + if adsorptiveAtDewPoint then + assert(WorkingPair.twoPhaseAdsorptive, + "Selected adsorptive medium model does not have a two-phase regime. " + + "Cannot calculate state properties of dew point at T_adsorpt.", + level = AssertionLevel.error); + end if; + + if approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve then + assert(WorkingPair.twoPhaseAdsorptive, + "Selected adsorptive medium model does not have a two-phase regime. " + + "Cannot calculate specific volume of the adsorpt at the bubble point.", + level = AssertionLevel.error); + end if; + + if approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.BoilingCurve then + assert(WorkingPair.twoPhaseAdsorptive, + "Selected adsorptive medium model does not have a two-phase regime. " + + "Cannot calculate specific heat capacity of the adsorpt at the bubble point.", + level = AssertionLevel.error); + end if; + + if approachSorptionEnthalpy == SorpLib.Choices.SorptionEnthalpy.Dubinin then + assert(WorkingPair.modelOfDubinin, + "You cannot calculate the specific enthaly of adsorption using the model " + + "of Dubinin if the isotherm model is not the model of Dubinin.", + level = AssertionLevel.error); + + assert(WorkingPair.twoPhaseAdsorptive, + "Selected adsorptive medium model does not have a two-phase regime. " + + "Cannot calculate specific enthalpy of adsorption according to Dubinin.", + level = AssertionLevel.error); + end if; + + if calcAdsorptAdsorbateState then + assert(calcCaloricProperties, + "You cannot calculate uptake-averaged adsorpt and adsorbate properties if " + + "you do not calculate at least caloric properties.", + level = AssertionLevel.error); + end if; + + if calcEntropicProperties then + assert(calcCaloricProperties, + "You cannot calculate entropic properties if you do not calculate caloric " + + "properties.", + level = AssertionLevel.error); + end if; + + if calcDerivativesEntropyBalance then + assert(calcCaloricProperties, + "You cannot calculate partial derivatives for the mass and energy balances " + + "if you do not calculate caloric properties.", + level = AssertionLevel.error); + + assert(calcDerivativesIsotherm, + "You cannot calculate partial derivatives for the mass and energy balances " + + "if you do not calculate partial derivatives of the isotherm models.", + level = AssertionLevel.error); + end if; + + if calcDerivativesEntropyBalance then + assert(calcCaloricProperties, + "You cannot calculate partial derivatives for the entropy balance if you " + + "do not calculate caloric properties.", + level = AssertionLevel.error); + + assert(calcDerivativesIsotherm, + "You cannot calculate partial derivatives for the entropy balance if you " + + "do not calculate partial derivatives of the isotherm models.", + level = AssertionLevel.error); + + assert(calcDerivativesMassEnergyBalance, + "You cannot calculate partial derivatives for the entropy balance if you " + + "do not calculate partial derivatives of the mass and energy balances.", + level = AssertionLevel.error); + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the thermodynamic properties of a working pair. +Specifically, the properties of the sorbent, the adsorpt (i.e. only +the adsorbed molecules), the adsorbate (i.e. sorbent and adsorpt) and +the adsorptive (i.e. gas/vapor phase) are calculated. Depending on +the model settings, only common state variables such as pressure, +temperature, loading, and specific enthalpy are calculated. Note that +adsorption is very heterogeous, so the adsorpt phase is not homogenous. +Therefore, macroscopic averaging can be applied using the loading for +averaging. As this averaging requires solving integrals numerically, it +should only be done if required. In addition to the phase properties, +partial derivatives can also be calculated, which are required for +dynamic mass, energy, and entropy balances in a working pair volume. +</p> + +<h4>Main equations for the last adsorbed molecule</h4> +<p> +The adsorption equilibrium is calculated via an isotherm model, thus +connecting the uptake, pressure, and temperature: +</p> +<pre> + x<sub>adsorpt</sub>(p<sub>adsorpt</sub>, T<sub>adsorpt</sub>); +</pre> +<p> +For details on available isotherm models, check the package +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEquilibria\">SorpLib.Media.Functions.SorptionEquilibria</a>. +</p> + +<p> +The specific average enthalpy of the last adsorbed molecule +<i>h<sub>adsorpt</sub></i> is calculated as +</p> +<pre> + h<sub>adsorpt</sub> = h<sub>adsorptive</sub> - Δh<sub>ads</sub>; +</pre> +<p> +and the specific entropy of the last adsorpbed molecule +<i>s<sub>adsorpt</sub></i> is calculated as +</p> +<pre> + s<sub>adsorpt</sub> = s<sub>adsorptive</sub> - Δh<sub>ads</sub> / T<sub>adsorpt</sub>; +</pre> +<p> +Herein, <i>h<sub>adsorptive</sub></i>/<i>s<sub>adsorptive</sub></i> is +the specific enthalpy/entropy of the adsorptive and <i>Δh<sub>ads</sub></i> +is the specific enthalpy of adsorption. For the specific enthalpy of +adsorption, different calculation approaches are implemented. For details, +check the package +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEnthalpies\">SorpLib.Media.Functions.SorptionEnthalpies</a>. +</p> + +<p> +Knowing the specific enthalpy of the adsorpt, the specific internal +energy ofthe last adsorbed molecule <i>u<sub>adsorpt</sub></i> is +calculated as +</p> +<pre> + u<sub>adsorpt</sub> = h<sub>adsorpt</sub> - p<sub>adsorpt</sub> * v<sub>adsorpt</sub>; +</pre> +<p> +Herein, <i>v<sub>adsorpt</sub></i> is the specific volume of the +adsorpt, which can be calculated using different approaches. For +details, check the enumeration +<a href=\"Modelica://SorpLib.Choices.SpecificVolumeAdsorpt\">SorpLib.Choices.SpecificVolumeAdsorpt</a>. +</p> + +<h4>Main equations for the uptake-averaged adsorpt (i.e., macroscopic properties)</h4> +<p> +The adsorption phenomenon is very heterogeneous, so the adsorpt +phase is typically not homogeneous. Therefore, macroscopic +averaging is performed using the loading <i>x<sub>adsorpt</sub></i> +to obtain average, homogeneous fluid properties +<i><SPAN STYLE=\"text-decoration:overline\">z</SPAN><sub>adsorpt</sub></i>: +</p> +<pre> + <SPAN STYLE=\"text-decoration:overline\">z</SPAN><sub>adsorpt</sub> = 1/x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:underline\">z</SPAN><sub>adsorpt</sub> = 1/x<sub>adsorpt</sub> * ∫_0^x<sub>adsorpt</sub> [z(x',T<sub>adsorpt</sub>)] dx'; +</pre> +<p> +Herein, loading <i>x<sub>adsorpt</sub></i> and temperature <i>T<sub>adsorpt</sub></i> +are assumed to independent state properties. This averaging must be +performed for all fluid quantities except for pressure <i>p<sub>adsorpt</sub></i> +(mechanical equilibrium), temperature <i>T<sub>adsorpt</sub></i> (thermal +equilibrium), and, consequently, loading <i>x<sub>adsorpt</sub></i>. +Since the specific volume of the adsorpt phase <i>v<sub>adsorpt</sub></i> +depends only on temperature (see assumptions), it already is a macroscopic +property and no averaging is necessary. +</p> + +<h4>Main equations for uptake-averaged adsorbate</h4> +Sstate properties <i>z</i> of the adsorbate are calculated as +</p> +<pre> + z<sub>adsorbate</sub> = z<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">z</SPAN><sub>adsorpt</sub>; +</pre> +<p> +and, thus, are given per unit sorbent mass. +</p> + +<h4>Main equations for partial derivatives required for mass, energy, and entropy balances</h4> +<p> +Transient governing equations are used in finite volume models under +<a href=\"Modelica://SorpLib.Basics.Volumes.Adsorbates.\">SorpLib.Basics.Volumes.Adsorbates</a>. +This requires partial differential equations, which have to be calculated +partially for the uptake-averaged properties. The required partial +derivatives vary with the selected independent differential states, which +can be either pressure <i>p<sub>adsorpt</sub></i> and temperature +<i>T<sub>adsorpt</sub></i> or loading <i>x<sub>adsorpt</sub></i> and +temperature <i>T<sub>adsorpt</sub></i>. +</p> + +<p> +For all conservation equations, partial derivatives of the isotherm +model are provided to switch between the independent differential states: +</p> +<ul> + <li> + <i>(∂x/∂p)<sub>T</sub></i>: + Partial derivative of the loading w.r.t. to pressure at + constant temperature. + </li> + <li> + <i>(∂x/∂T)<sub>p</sub></i>: + Partial derivative of the loading w.r.t. to temperature at + constant pressure. + </li> + <li> + <i>(∂p/∂x)<sub>T</sub> = 1 / (∂x/∂p)<sub>T</sub></i>: + Partial derivative of the pressure w.r.t. to loading at + constant temperature. + </li> + <li> + <i>(∂p/∂T)<sub>x</sub> = -(∂x/∂T)<sub>p</sub> / (∂x/∂p)<sub>T</sub></i>: + Partial derivative of the pressure w.r.t. to temperature at + constant loading. + </li> +</ul> + +<p> +The specific volume of the sorbent <i>v<sub>sor</sub></i> is constant +(see assumptions), so the mass of the sorbent <i>m<sub>sor</sub></i> +does not change with the properties of the substance. The mass balance +of the adsorpt is expressed directly in terms of the loading +<i>x<sub>adsorpt</sub></i>, so no partial derivatives of the density +are required either. +</p> + +<p> +The energy balance of an adsorbate volume can be derived from the +definition of the internal energy of the adsorbate volume +<i>U<sub>adsorbate</sub></i>: +</p> +<pre> + U<sub>adsorbate</sub> = m<sub>sor</sub> * u<sub>sor</sub> + m<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub> = m<sub>sor</sub> * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>]; +</pre> +<p> +Thus, the total differential of the internal energy of the adsorbate +volume <i>dU<sub>adsorbate</sub></i> is: +</p> +<pre> + dU<sub>adsorbate</sub> = dm<sub>sor</sub> * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [du<sub>sor</sub> + d(x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>)] = dm<sub>sor</sub> * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [du<sub>sor</sub> + d<SPAN STYLE=\"text-decoration:underline\">u</SPAN><sub>adsorpt</sub>]; +</pre> +<p> +The total differential <i>dU<sub>adsorbate</sub></i> can be further +simplified if the definition of the specific internal energy +<i>u = h - p * v</i> is used and then the macroscopic quantities of +the adsorpt (pressure <i>p = p<sub>adsorpt</sub></i>, temperature +<i>T = T<sub>adsorpt</sub></i>, and specific volume <i>v<sub>adsorpt</sub></i>) +are taken into account: +</p> +<pre> + dU<sub>adsorbate</sub> = dm<sub>sor</sub> * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [dh<sub>sor</sub> - p * dv<sub>sor</sub> - v<sub>sor</sub> * dp + d<SPAN STYLE=\"text-decoration:underline\">h</SPAN><sub>adsorpt</sub> - d(x<sub>adsorpt</sub> * v<sub>adsorpt</sub> * p)] = dm<sub>sor</sub> * [u<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">u</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [dh<sub>sor</sub> - p * dv<sub>sor</sub> - v<sub>sor</sub> * dp + d<SPAN STYLE=\"text-decoration:underline\">h</SPAN><sub>adsorpt</sub> - d(x<sub>adsorpt</sub> * v<sub>adsorpt</sub>) * p - x<sub>adsorpt</sub> * v<sub>adsorpt</sub> * dp]; +</pre> + +<p> +Thus, the following partial derivatives are provided for the sorbent: +</p> +<ul> + <li> + <i>(∂h<sub>sor</sub>/∂p)<sub>T</sub> = v<sub>sor</sub> * (1 - T * β<sub>sor</sub>)</i>: + Partial derivative of the specific enthaly w.r.t. to pressure at + constant temperature. + </li> + <li> + <i>(∂h<sub>sor</sub>/∂T)<sub>p</sub> = c<sub>sor</sub></i>: + Partial derivative of the specific enthaly w.r.t. to temperature at + constant pressure. + </li> + <li> + <i>(∂h<sub>sor</sub>/∂x)<sub>T</sub></i>: + Partial derivative of the specific enthaly w.r.t. to loading at + constant temperature. + </li> + <li> + <i>(∂h<sub>sor</sub>/∂T)<sub>x</sub></i>: + Partial derivative of the specific enthaly w.r.t. to temperature at + constant loading. + </li> + <li> + <i>(∂v<sub>sor</sub>/∂p)<sub>T</sub> = 0</i>: + Partial derivative of the specific volume w.r.t. to pressure at + constant temperature. + </li> + <li> + <i>(∂v<sub>sor</sub>/∂T)<sub>p</sub> = 0</i>: + Partial derivative of the specific volume w.r.t. to temperature at + constant pressure. + </li> + <li> + <i>(∂v<sub>sor</sub>/∂x)<sub>T</sub> = 0</i>: + Partial derivative of the specific volume w.r.t. to loading at + constant temperature. + </li> + <li> + <i>(∂v<sub>sor</sub>/∂T)<sub>x</sub> = 0</i>: + Partial derivative of the specific volume w.r.t. to temperature at + constant loading. + </li> +</ul> +<p> +Accordingly, the following partial derivatives are provided for the +adsorpt: +</p> +<ul> + <li> + <i>(∂<SPAN STYLE=\"text-decoration:underline\">h</SPAN><sub>adsorpt</sub>/∂p)<sub>T</sub></i>: + Partial derivative of the specific enthaly w.r.t. to pressure at + constant temperature. + </li> + <li> + <i>(∂<SPAN STYLE=\"text-decoration:underline\">h</SPAN><sub>adsorpt</sub>/∂T)<sub>p</sub></i>: + Partial derivative of the specific enthaly w.r.t. to temperature at + constant pressure. + </li> + <li> + <i>(∂<SPAN STYLE=\"text-decoration:underline\">h</SPAN><sub>adsorpt</sub>/∂x)<sub>T</sub> = h<sub>adsorpt</sub></i>: + Partial derivative of the specific enthaly w.r.t. to loading at + constant temperature. + </li> + <li> + <i>(∂<SPAN STYLE=\"text-decoration:underline\">h</SPAN><sub>adsorpt</sub>/∂T)<sub>x</sub> = c<sub>adsorpt</sub> * x<sub>adsorpt</sub></i>: + Partial derivative of the specific enthaly w.r.t. to temperature at + constant loading. It was assumed that the specific heat capacity is + either independent of the loading or directly corresponds to the + uptake-averaged specific heat capacity (see assumptions). + </li> + <li> + <i>(∂(x<sub>adsorpt</sub> * v<sub>adsorpt</sub>)/∂p)<sub>T</sub> = x<sub>adsorpt</sub> * (∂(v<sub>adsorpt</sub>)/∂p)<sub>T</sub> + (∂(x<sub>adsorpt</sub>)/∂p)<sub>T</sub> * v<sub>adsorpt</sub></i>: + Partial derivative of the product of specific volume and uptake w.r.t. + to pressure at constant temperature. + </li> + <li> + <i>(∂(x<sub>adsorpt</sub> * v<sub>adsorpt</sub>)/∂T)<sub>p</sub> = x<sub>adsorpt</sub> * (∂(v<sub>adsorpt</sub>)/∂T)<sub>p</sub> + (∂(x<sub>adsorpt</sub>)/∂T)<sub>p</sub> * v<sub>adsorpt</sub></i></i>: + Partial derivative of the product of specific volume and uptake w.r.t. + to temperature at constant pressure. + </li> + <li> + <i>(∂v(x<sub>adsorpt</sub> * v<sub>adsorpt</sub>)∂x)<sub>T</sub></i>: + Partial derivative of the product of specific volume and uptake w.r.t. + to loading at constant temperature. + </li> + <li> + <i>(∂(x<sub>adsorpt</sub> * v<sub>adsorpt</sub>)/∂T)<sub>x</sub></i>: + Partial derivative of the product of specific volume and uptake w.r.t. + to temperature at constant loading. + </li> +</ul> + +<p> +The partial derivatives required for the entropy balance can be +determined in the same way as for the energy balance. The total +entropy of the adsorbate volume <i>S<sub>adsorbate</sub></i> is: +</p> +<pre> + S<sub>adsorbate</sub> = m<sub>sor</sub> * [s<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">s</SPAN><sub>adsorpt</sub>]; +</pre> +<p> +Thus, when applying all assumptions, the total differential of the +entropy of the adsorbate volume <i>dS<sub>adsorbate</sub></i> is: +</p> +<pre> + dS<sub>adsorbate</sub> = dm<sub>sor</sub> * [s<sub>sor</sub> + x<sub>adsorpt</sub> * <SPAN STYLE=\"text-decoration:overline\">s</SPAN><sub>adsorpt</sub>] + m<sub>sor</sub> * [ds<sub>sor</sub> + d<SPAN STYLE=\"text-decoration:underline\">s</SPAN><sub>adsorpt</sub>]; +</pre> +<p> +Consequently, the following partial derivatives are provided for the +sorbent and adsorpt: +</p> +<ul> + <li> + <i>(∂s<sub>sor</sub>/∂p)<sub>T</sub> = v<sub>sor</sub> * β<sub>sor</sub></i>: + Partial derivative of the specific entropy w.r.t. to pressure at + constant temperature. + </li> + <li> + <i>(∂s<sub>sor</sub>/∂T)<sub>p</sub> = c<sub>sor</sub> / T</i>: + Partial derivative of the specific entropy w.r.t. to temperature at + constant pressure. + </li> + <li> + <i>(∂s<sub>sor</sub>/∂x)<sub>T</sub></i>: + Partial derivative of the specific entropy w.r.t. to loading at + constant temperature. + </li> + <li> + <i>(∂s<sub>sor</sub>/∂T)<sub>x</sub></i>: + Partial derivative of the specific entropy w.r.t. to temperature at + constant loading. + </li> + <li> + <i>(∂<SPAN STYLE=\"text-decoration:underline\">s</SPAN><sub>adsorpt</sub>/∂p)<sub>T</sub></i>: + Partial derivative of the specific entropy w.r.t. to pressure at + constant temperature. + </li> + <li> + <i>(∂<SPAN STYLE=\"text-decoration:underline\">s</SPAN><sub>adsorpt</sub>/∂T)<sub>p</sub></i>: + Partial derivative of the specific entropy w.r.t. to temperature at + constant pressure. + </li> + <li> + <i>(∂<SPAN STYLE=\"text-decoration:underline\">s</SPAN><sub>adsorpt</sub>/∂x)<sub>T</sub> = s<sub>adsorpt</sub></i>: + Partial derivative of the specific entropy w.r.t. to loading at + constant temperature. + </li> + <li> + <i>(∂<SPAN STYLE=\"text-decoration:underline\">s</SPAN><sub>adsorpt</sub>/∂T)<sub>x</sub> = c<sub>adsorpt</sub> / T * x<sub>adsorpt</sub></i>: + Partial derivative of the specific entropy w.r.t. to temperature at + constant loading. It was assumed that the specific heat capacity is + either independent of the loading or directly corresponds to the + uptake-averaged specific heat capacity (see assumptions). + </li> + <li> +</ul> + +<p> +Partial derivatives that are not fully specified can be calculated +using the fundamental laws of analysis and the specified partial +derivatives as well as the partial derivatives of the isotherm model. +</p> + +<h4>Assumptions and limitations</h4> +<ul> + <li> + Adsorption equilibrium with all adsorptive beeing adsorbed and in adsorpt + phase (i.e., chemical equilibrium). + </li> + <li> + The sorbent and adsorpt have the same pressure (i.e., mechanical equilibrium). + </li> + <li> + The sorbent and adsorpt have the same temperature (i.e., thermal equilibrium). + </li> + <li> + Specific volume of the adsorpt may only depend on the temperature and is thus + a macroscopic property without averaging. + </li> + <li> + Specific heat capacity of the adsorpt may only depend on the temperature or is + assumed to already be an uptake-averaged specific heat capacity. + </li> + <li> + Ideal and inert sorbent with constant specific volume. + </li> +</ul> + +<h4>Typical use</h4> +<p> +This model is mainly used to calculate thermodynamic properties of an adsorbate +volume. +</p> + +<h4>Important parameters and options</h4> +<ul> + <li> + All parameters of the calculation setup: Define which variables are calculated. + </li> + <li> + <i>adsorptiveAtDewPoint = true</i>: Assume thermodynamic state of the adsorptive + to correspond to the dew point at given temperature. + </li> + <li> + <i>neglectSpecifcVolume = true</i>: Neglect the specific volume of the adsorpt. + This options can significantly simplify the calculation procedure and is often + a good assumption. + </li> + <li> + <i>approachSpecificVolume</i>: Choose the calculation approach for the specific + volume of the adsorpt. + </li> + <li> + <i>approachSpecificHeatCapacity</i>: Choose the calculation approach for the + specific heat capacity of the adsorpt. + </li> + <li> + <i>approachSorptionEnthalpy</i>: Choose the calculation approach for the + specific enthalpy of adsorption. + </li> +</ul> + +<h4>Dynamics</h4> +<p> +Dynamic states are either the pressure and temperature or the uptake and +temperature. To change the dynamic states, use the parameter <i>stateVariables</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + Major adaptations and extensions (e.g. partial derivatives for mass, + energy, and entropy balances or properties of the sorbent). + </li> + <li> + December 14, 2020, by Mirko Engelpracht:<br/> + Major reivisions (e.g., object-oriented approach, functionaliy) due + to restructuring of the library. + </li> + <li> + November 17, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of + library. + </li> +</ul> +</html>")); +end PartialPureWorkingPairs; diff --git a/SorpLib/Media/WorkingPairs/BaseClasses/Partial_ddz_dT_dT.mo b/SorpLib/Media/WorkingPairs/BaseClasses/Partial_ddz_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..5bc5ab2ad82e694405d772bf879a2e4b04567426 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/BaseClasses/Partial_ddz_dT_dT.mo @@ -0,0 +1,44 @@ +within SorpLib.Media.WorkingPairs.BaseClasses; +partial function Partial_ddz_dT_dT + "Base function for calculating the second-order partial derivative of coefficients w.r.t. temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real ddz_dT_dT + "Second-order partial derivative of coefficient w.r.t. temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for calculating the second-order +partial derivative of a coefficient with respect to temperature as function of +temperature. +<br/><br/> +This partial function defines the temperature <i>T</i> as input and the second- +order partial derivative of the coefficient with respect to temperature <i>ddz_dT_dT</i> +as output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_ddz_dT_dT; diff --git a/SorpLib/Media/WorkingPairs/BaseClasses/Partial_dz_dT.mo b/SorpLib/Media/WorkingPairs/BaseClasses/Partial_dz_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..73d6c186d369c8e8c02c6158a628c7c5da1daeeb --- /dev/null +++ b/SorpLib/Media/WorkingPairs/BaseClasses/Partial_dz_dT.mo @@ -0,0 +1,42 @@ +within SorpLib.Media.WorkingPairs.BaseClasses; +partial function Partial_dz_dT + "Base function for calculating the partial derivative of coefficients w.r.t. temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real dz_dT + "Partial derivative of coefficient w.r.t. temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for calculating the partial derivative +of a coefficient with respect to temperature as function of temperature. +<br/><br/> +This partial function defines the temperature <i>T</i> as input and the partial +derivative of the coefficient with respect to temperature <i>dz_dT</i> as output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_dz_dT; diff --git a/SorpLib/Media/WorkingPairs/BaseClasses/Partial_z_T.mo b/SorpLib/Media/WorkingPairs/BaseClasses/Partial_z_T.mo new file mode 100644 index 0000000000000000000000000000000000000000..694301f9729108e1f7424d2f51507a8de8f1b43b --- /dev/null +++ b/SorpLib/Media/WorkingPairs/BaseClasses/Partial_z_T.mo @@ -0,0 +1,42 @@ +within SorpLib.Media.WorkingPairs.BaseClasses; +partial function Partial_z_T + "Base function for calculating a coefficient as function of temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real z + "Coefficient" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial function is the basic function for calculating a coefficient as +function of temperature. +<br/><br/> +This partial function defines the temperature <i>T</i> as input and the abitrary +coefficient <i>c</i> as output. +<br/><br/> +Functions that inherit properties from this partial function may have to add +furhter inputs, outputs, and the function algorithm. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Partial_z_T; diff --git a/SorpLib/Media/WorkingPairs/BaseClasses/package.mo b/SorpLib/Media/WorkingPairs/BaseClasses/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5578536f77dc48e97d9730c61ca589b4d7338226 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/BaseClasses/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Media.WorkingPairs; +package BaseClasses "Base classes used to build new working pair models" + extends Modelica.Icons.BasesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains partial basic functions and models. These partial functions +and models contain fundamental definitions of all working pair models and corresponding +test models, covering pure and multi-component adsorption. The content of this package +is only of interest when adding new working pair models to the library. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end BaseClasses; diff --git a/SorpLib/Media/WorkingPairs/BaseClasses/package.order b/SorpLib/Media/WorkingPairs/BaseClasses/package.order new file mode 100644 index 0000000000000000000000000000000000000000..1bcf8b28efb262c18765fbd6d4730939aab48c9f --- /dev/null +++ b/SorpLib/Media/WorkingPairs/BaseClasses/package.order @@ -0,0 +1,6 @@ +Partial_z_T +Partial_dz_dT +Partial_ddz_dT_dT +PartialPureWorkingPairs +PartialPureTest +PartialPureCharts diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/ChartWorkingPairDubinin.mo b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/ChartWorkingPairDubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..71198526ff2fbd78129e5586302656b026678839 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/ChartWorkingPairDubinin.mo @@ -0,0 +1,250 @@ +within SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents; +model ChartWorkingPairDubinin + "Model that creates a fluid property diagram of a pure component working pair using the MSL for fluid property data calculation of a real fluid with a two-phase regime" + extends SorpLib.Media.WorkingPairs.BaseClasses.PartialPureCharts( + redeclare replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare package Medium=Medium)); + + // + // Definition of replaceable medium + // + replaceable package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017 + constrainedby + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( redeclare final package Medium = Medium)) + "Parametrized working pair model" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.Pressure p_adsorpt_lowerLimit = 612 + "Lower limit for the pressure to calculate fluod property data" + annotation (Dialog(tab = "Advanced", group = "Limiter"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Temperature T_adsorpt_lowerLimit = 273.17 + "Lower limit for the temperature to calculate fluod property data" + annotation (Dialog(tab = "Advanced", group = "Limiter"), + Evaluate=true, + HideResult=true); + final parameter Modelica.Units.SI.Pressure p_sat_T_adsorpt_lowerLimit= + if diagramType<> + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters then 0 else + Medium.saturationPressure(T=T_adsorpt_lowerLimit) + "Saturation pressure at T_adsorpt_lowerLimit" + annotation (Dialog(tab = "Advanced", group = "Limiter"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + SorpLib.Units.Uptake x_sat_isotherms + "Saturation uptake as function of changing pressure (i.e., required for + diagram of isotherms)"; + Modelica.Units.SI.Pressure p_sat_isosters + "Saturation pressure as function of changing temperature (i.e., required for + diagram of isosteres)"; + SorpLib.Units.Uptake x_sat_isobars + "Saturation uptake as function of changing temperature (i.e., required for + diagram of isobars)"; + + Real x_axis_isotherm + "X-axis for isotherm diagram: Pressure p_adsorpt"; + Real x_axis_isosters + "X-axis for isosters diagram: Negative reciproce temperature -1/T_adsorpt"; + Real x_axis_isobars + "X-axis for isobars diagram: Temperature T_adsorpt"; + + // + // Definition of protected variables + // +protected + Modelica.Units.SI.Pressure + p_adsorpt_(start=max(p_adsorpt_min, p_adsorpt_lowerLimit), fixed=true) + "Changing pressure"; + Modelica.Units.SI.Temperature + T_adsorpt_(start=max(T_adsorpt_min, T_adsorpt_lowerLimit), fixed=true) + "Changing temperature"; + + Modelica.Units.SI.Pressure p_sat_T_adsorpt + "Saturation pressure as function of changing temperature (i.e., required + for diagram of isosteres or isobars)"; + Modelica.Units.SI.Temperature T_sat_p_adsorpt + "Saturation temperature as function of changing pressure (i.e., required + for diagram of isotherms)"; + + SorpLib.Units.Uptake x_sat_T_adsorpt_lowerLimit + "Saturation uptake at p_sat(T_adsorpt_lowerLimit) and T_adsorpt_lowerLimit"; + SorpLib.Units.Uptake x_sat_T_adsorpt + "Saturation uptake at p_sat(T_adsorpt) and T_adsorpt"; + + // + // Instantiation of final models + // + WorkingPair.IsothermCoefficients isothermCoefficients( + final T_adsorpt=if diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms then + T_sat_p_adsorpt else T_adsorpt_) + "Temperature-dependent isotherm coefficients"; + +equation + // + // Calculate upper limits for different diagrams types + // + T_sat_p_adsorpt = if diagramType<> + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms then 0 else + Medium.saturationTemperature(p=p_adsorpt_) + "Saturation pressure as function of changing temperature (i.e., required + for diagram of isotherms)"; + p_sat_T_adsorpt = if diagramType== + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms then 0 else + Medium.saturationPressure(T=T_adsorpt_) + "Saturation pressure as function of changing temperature (i.e., required + for diagram of isosteres)"; + + x_sat_T_adsorpt_lowerLimit = if diagramType<> + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters then 0 else + WorkingPair.IsothermModel.x_pT( + p_adsorpt= p_sat_T_adsorpt_lowerLimit, + T_adsorpt=max(T_adsorpt_, T_adsorpt_lowerLimit), + c=isothermCoefficients.c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Saturation uptake at p_sat(T_adsorpt_lowerLimit) and T_adsorpt_lowerLimit"; + x_sat_T_adsorpt = if diagramType<> + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters then 0 else + WorkingPair.IsothermModel.x_pT( + p_adsorpt= p_sat_T_adsorpt, + T_adsorpt=T_adsorpt_, + c=isothermCoefficients.c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Saturation uptake at p_sat(T_adsorpt) and T_adsorpt"; + + // + // Calculate correct inputs + // + der(p_adsorpt_) = (p_adsorpt_max-max(p_adsorpt_min, p_adsorpt_lowerLimit)) / 20 + "Predescriped slope"; + der(T_adsorpt_) = (T_adsorpt_max-max(T_adsorpt_min, T_adsorpt_lowerLimit)) / 20 + "Changing temperature"; + + if diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms then + p_adsorpt = fill(p_adsorpt_, no_isoLines) + "Pressure"; + T_adsorpt = {max(T_adsorpt_const_[i], T_sat_p_adsorpt) for i in 1:no_isoLines} + "Temperature"; + + elseif diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters then + x_adsorpt = {max(min(x_adsorpt_const_[i], x_sat_T_adsorpt), + x_sat_T_adsorpt_lowerLimit) for i in 1:no_isoLines} + "Uptake: Limited to its lower and upper limit"; + T_adsorpt = fill(T_adsorpt_, no_isoLines) + "Temperature: Limitied to its lower limit"; + + else + p_adsorpt = {min(p_adsorpt_const_[i], p_sat_T_adsorpt) for i in 1:no_isoLines} + "Pressure"; + T_adsorpt = fill(T_adsorpt_, no_isoLines) + "Temperature"; + + end if; + + // + // Caclulate variables for plotting + // + x_sat_isotherms = if diagramType<> + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms then 0 else + WorkingPair.IsothermModel.x_pT( + p_adsorpt=p_adsorpt_, + T_adsorpt=T_sat_p_adsorpt, + c=isothermCoefficients.c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Saturation uptake as function of changing pressure (i.e., required for + diagram of isotherms)"; + p_sat_isosters = if diagramType<> + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters then 0 else + p_sat_T_adsorpt + "Saturation pressure as function of changing temperature (i.e., required for + diagram of isosteres)"; + x_sat_isobars = if diagramType<> + SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isobars then 0 else + WorkingPair.IsothermModel.x_pT( + p_adsorpt=p_sat_T_adsorpt, + T_adsorpt=T_adsorpt_, + c=isothermCoefficients.c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Saturation uptake as function of changing temperature (i.e., required for + diagram of isobars)"; + + x_axis_isotherm = p_adsorpt_ + "X-axis for isotherm diagram: Pressure p_adsorpt"; + x_axis_isosters = -1/T_adsorpt_ + "X-axis for isosters diagram: Negative reciproce temperature -1/T_adsorpt"; + x_axis_isobars = T_adsorpt_ + "X-axis for isobars diagram: Temperature T_adsorpt"; + + // + // Asserations + // + if diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms then + assert(min(T_adsorpt_const_) > T_adsorpt_lowerLimit, + "Minimum isotherm temperature (" + String(min(T_adsorpt_const_)) + + ") is below the minimum temperature (" + String(T_adsorpt_lowerLimit) + + "). Thus, fluid property data calculation is impossible.", + level = AssertionLevel.error); + + elseif diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isobars then + assert(min(p_adsorpt_const_) > p_adsorpt_lowerLimit, + "Minimum isotherm pressure (" + String(min(p_adsorpt_const_)) + + ") is below the minimum pressure (" + String(p_adsorpt_lowerLimit) + + "). Thus, fluid property data calculation is impossible.", + level = AssertionLevel.error); + + end if; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the basic model for all models creating fluid propertey diagrams +for working pair models describing adsorption of pure components. These working paur models +use a isotherm model based on the model of Dubinin and a medium model of a rel fluid with +a two-regime based on the Modelica Standard Library. Note that the isotherms, isosters, and +isobars are limited to lower and upper bounds if necessary to perform calculations within a +feasble range. +</p> +</html>", revisions="<html> +<ul> + <li> + November 23, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ChartWorkingPairDubinin; diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/ChartWorkingPairGas.mo b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/ChartWorkingPairGas.mo new file mode 100644 index 0000000000000000000000000000000000000000..84bb15be1d0cc589e7a01fc1a1b51a7c1e789cda --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/ChartWorkingPairGas.mo @@ -0,0 +1,97 @@ +within SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents; +model ChartWorkingPairGas + "Model that creates a fluid property diagram of a pure component working pair using the MSL for fluid property data calculation of a fluid with just one-regime (i.e., gas/vapor)" + extends SorpLib.Media.WorkingPairs.BaseClasses.PartialPureCharts( + redeclare replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.CO2.ActivatedCarbon_Toth_DantasEtAl2011_Gas + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare package Medium=Medium)); + + // + // Definition of replaceable medium + // + replaceable package Medium = SorpLib.Media.IdealGases.CO2 + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true); + + // + // Definition of variables + // + Real x_axis_isotherm + "X-axis for isotherm diagram: Pressure p_adsorpt"; + Real x_axis_isosters + "X-axis for isosters diagram: Negative reciproce temperature -1/T_adsorpt"; + Real x_axis_isobars + "X-axis for isobars diagram: Temperature T_adsorpt"; + + // + // Definition of final parameters + // +protected + Modelica.Units.SI.Pressure p_adsorpt_(start=p_adsorpt_min, fixed=true) + "Changing pressure"; + Modelica.Units.SI.Temperature T_adsorpt_(start=T_adsorpt_min, fixed=true) + "Changing temperature"; + +equation + // + // Calculate correct inputs + // + der(p_adsorpt_) = (p_adsorpt_max-p_adsorpt_min) / 20 + "Predescriped slope"; + der(T_adsorpt_) = (T_adsorpt_max-T_adsorpt_min) / 20 + "Changing temperature"; + + if diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms then + p_adsorpt = fill(p_adsorpt_, no_isoLines) + "Pressure"; + T_adsorpt = T_adsorpt_const_ + "Temperature"; + + elseif diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters then + x_adsorpt = x_adsorpt_const_ + "Uptake"; + T_adsorpt = fill(T_adsorpt_, no_isoLines) + "Temperature"; + + else + p_adsorpt = p_adsorpt_const_ + "Pressure"; + T_adsorpt = fill(T_adsorpt_, no_isoLines) + "Temperature"; + + end if; + + // + // Caclulate variables for plotting + // + x_axis_isotherm = p_adsorpt_ + "X-axis for isotherm diagram: Pressure p_adsorpt"; + x_axis_isosters = -1/T_adsorpt_ + "X-axis for isosters diagram: Negative reciproce temperature -1/T_adsorpt"; + x_axis_isobars = T_adsorpt_ + "X-axis for isobars diagram: Temperature T_adsorpt"; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the basic model for all models creating fluid propertey diagrams +for working pair models describing adsorption of pure components and using a medium +model of a fluid with just one regime (i.e., gas/vapor) based on the Modelica Standard +Library. +</p> +</html>", revisions="<html> +<ul> + <li> + November 23, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ChartWorkingPairGas; diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/ChartWorkingPairVLE.mo b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/ChartWorkingPairVLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..e5ecc6b339c8dd1c9f6cd18b7bc00ad2ea5b44f7 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/ChartWorkingPairVLE.mo @@ -0,0 +1,135 @@ +within SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents; +model ChartWorkingPairVLE + "Model that creates a fluid property diagram of a pure component working pair using the MSL for fluid property data calculation of a real fluid with a two-phase regime" + extends SorpLib.Media.WorkingPairs.BaseClasses.PartialPureCharts( + redeclare replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare package Medium=Medium, + limitLowerPressure=true, + p_adsorpt_min=p_adsorpt_lowerLimit)); + + // + // Definition of replaceable medium + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true); + + // + // Definition of parameters + // + parameter Modelica.Units.SI.Pressure p_adsorpt_lowerLimit = 612 + "Lower limit for the pressure to calculate fluod property data" + annotation (Dialog(tab = "Advanced", group = "Limiter"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Temperature T_adsorpt_lowerLimit = 273.17 + "Lower limit for the temperature to calculate fluod property data" + annotation (Dialog(tab = "Advanced", group = "Limiter"), + Evaluate=true, + HideResult=true); + + // + // Definition of variables + // + Real x_axis_isotherm + "X-axis for isotherm diagram: Pressure p_adsorpt"; + Real x_axis_isosters + "X-axis for isosters diagram: Negative reciproce temperature -1/T_adsorpt"; + Real x_axis_isobars + "X-axis for isobars diagram: Temperature T_adsorpt"; + + // + // Definition of final parameters + // +protected + Modelica.Units.SI.Pressure + p_adsorpt_(start=max(p_adsorpt_min, p_adsorpt_lowerLimit), fixed=true) + "Changing pressure"; + Modelica.Units.SI.Temperature + T_adsorpt_(start=max(T_adsorpt_min, T_adsorpt_lowerLimit), fixed=true) + "Changing temperature"; + +equation + // + // Calculate correct inputs + // + der(p_adsorpt_) = (p_adsorpt_max-max(p_adsorpt_min, p_adsorpt_lowerLimit)) / 20 + "Predescriped slope"; + der(T_adsorpt_) = (T_adsorpt_max-max(T_adsorpt_min, T_adsorpt_lowerLimit)) / 20 + "Changing temperature"; + + if diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms then + p_adsorpt = fill(p_adsorpt_, no_isoLines) + "Pressure"; + T_adsorpt = {max(T_adsorpt_const_[i], T_adsorpt_lowerLimit) for i in 1:no_isoLines} + "Temperature"; + + elseif diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters then + x_adsorpt = x_adsorpt_const_ + "Uptake"; + T_adsorpt = fill(T_adsorpt_, no_isoLines) + "Temperature"; + + else + p_adsorpt = {max(p_adsorpt_const_[i], p_adsorpt_lowerLimit) for i in 1:no_isoLines} + "Pressure"; + T_adsorpt = fill(T_adsorpt_, no_isoLines) + "Temperature"; + + end if; + + // + // Caclulate variables for plotting + // + x_axis_isotherm = p_adsorpt_ + "X-axis for isotherm diagram: Pressure p_adsorpt"; + x_axis_isosters = -1/T_adsorpt_ + "X-axis for isosters diagram: Negative reciproce temperature -1/T_adsorpt"; + x_axis_isobars = T_adsorpt_ + "X-axis for isobars diagram: Temperature T_adsorpt"; + + // + // Asserations + // + if diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms then + assert(min(T_adsorpt_const_) > T_adsorpt_lowerLimit, + "Minimum isotherm temperature (" + String(min(T_adsorpt_const_)) + + ") is below the minimum temperature (" + String(T_adsorpt_lowerLimit) + + "). Thus, fluid property data calculation is impossible.", + level = AssertionLevel.error); + + elseif diagramType==SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isobars then + assert(min(p_adsorpt_const_) > p_adsorpt_lowerLimit, + "Minimum isotherm pressure (" + String(min(p_adsorpt_const_)) + + ") is below the minimum pressure (" + String(p_adsorpt_lowerLimit) + + "). Thus, fluid property data calculation is impossible.", + level = AssertionLevel.error); + + end if; + + // + // Annotations + // + annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info="<html> +<p> +This partial model is the basic model for all models creating fluid propertey diagrams +for working pair models describing adsorption of pure components and using a medium +model of a real fluid with a two-phase regime based on the Modelica Standard Library. +Note that the pressure and temperature are limited if necessary to stay within +a feasble range. +</p> +</html>", revisions="<html> +<ul> + <li> + November 23, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ChartWorkingPairVLE; diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/Test_ChartWorkingPairDubinin.mo b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/Test_ChartWorkingPairDubinin.mo new file mode 100644 index 0000000000000000000000000000000000000000..5fd5318b98164018e59662577221f436df112a1b --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/Test_ChartWorkingPairDubinin.mo @@ -0,0 +1,96 @@ +within SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.Tester; +model Test_ChartWorkingPairDubinin + "Tester for the fluid property diagram model using the model of Dubinin and the MSL for fluid property data calculation of a real fluid with a two-phase regime" + extends Modelica.Icons.Example; + + // + // Definition of parameters describing packages and models + // + replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE + "Pure working pair model" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable package WorkingPair = + Parametrizations.PureComponents.H2O.SilicaGel123_DubininLorentzianCumulative_Schawe2000 + constrainedby + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin + "Parametrized working pair model" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true); + + // + // Instantiation of models + // + SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.ChartWorkingPairDubinin + diagramIsotherms( + redeclare final package Medium = Medium, + redeclare final model PureWorkingPairModel = PureWorkingPairModel, + redeclare final package WorkingPair = WorkingPair, + final diagramType=SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms, + isoLineType=SorpLib.Choices.ChangingConstantVariableOfDiagram.Linespace, + p_adsorpt_min=615, + p_adsorpt_max=5e5, + T_adsorpt_min=273.2, + T_adsorpt_max=423.15) "Diagram of isotherms" + annotation (Placement(transformation(extent={{-60,-12},{-40,8}}))); + + SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.ChartWorkingPairDubinin + diagramIsosters( + redeclare final package Medium = Medium, + redeclare final model PureWorkingPairModel = PureWorkingPairModel, + redeclare final package WorkingPair = WorkingPair, + final diagramType=SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters, + isoLineType=SorpLib.Choices.ChangingConstantVariableOfDiagram.Linespace, + T_adsorpt_min=273.2, + T_adsorpt_max=423.15, + x_adsorpt_min=0.05, + x_adsorpt_max=0.45) "Diagram of isosters" + annotation (Placement(transformation(extent={{-10,-12},{10,8}}))); + + SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.ChartWorkingPairDubinin + diagramIsobars( + redeclare final package Medium = Medium, + redeclare final model PureWorkingPairModel = PureWorkingPairModel, + redeclare final package WorkingPair = WorkingPair, + final diagramType=SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isobars, + isoLineType=SorpLib.Choices.ChangingConstantVariableOfDiagram.Linespace, + p_adsorpt_min=615, + p_adsorpt_max=5e5, + T_adsorpt_min=273.2, + T_adsorpt_max=423.15) "Diagram of isobars" + annotation (Placement(transformation(extent={{40,-12},{60,8}}))); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This models demonstrates how to create a diagram of isotherms, isosters, +or isobars for a working pair model using a real fluid with a two-regime +and the model of Dubinin. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 23, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), experiment(StopTime=20, Tolerance=1e-06)); +end Test_ChartWorkingPairDubinin; diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/Test_ChartWorkingPairGas.mo b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/Test_ChartWorkingPairGas.mo new file mode 100644 index 0000000000000000000000000000000000000000..b7274597e3249d1ec05061027aaa3881249fede6 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/Test_ChartWorkingPairGas.mo @@ -0,0 +1,87 @@ +within SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.Tester; +model Test_ChartWorkingPairGas + "Tester for the fluid property diagram model using the MSL for fluid property data calculation of a fluid with just one-regime (i.e., gas/vapor)" + extends Modelica.Icons.Example; + + // + // Definition of parameters describing packages and models + // + replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.CO2.ActivatedCarbon_Toth_DantasEtAl2011_Gas + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas + "Pure working pair model" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable package Medium = SorpLib.Media.IdealGases.CO2 + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true); + + // + // Instantiation of models + // + SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.ChartWorkingPairGas + diagramIsotherms( + redeclare final package Medium = Medium, + redeclare final model PureWorkingPairModel = PureWorkingPairModel, + final diagramType=SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms, + isoLineType=SorpLib.Choices.ChangingConstantVariableOfDiagram.Linespace, + p_adsorpt_min=1000, + p_adsorpt_max=1000000, + T_adsorpt_min=283.15, + T_adsorpt_max=423.15) + "Diagram of isotherms" + annotation (Placement(transformation(extent={{-60,-12},{-40,8}}))); + + SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.ChartWorkingPairGas + diagramIsosters( + redeclare final package Medium = Medium, + redeclare final model PureWorkingPairModel = PureWorkingPairModel, + final diagramType=SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters, + isoLineType=SorpLib.Choices.ChangingConstantVariableOfDiagram.Linespace, + p_adsorpt_max=1000000, + T_adsorpt_min=283.15, + T_adsorpt_max=423.15, + x_adsorpt_min=0.05, + x_adsorpt_max=0.25) + "Diagram of isosters" + annotation (Placement(transformation(extent={{-10,-12},{10,8}}))); + + SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.ChartWorkingPairGas + diagramIsobars( + redeclare final package Medium = Medium, + redeclare final model PureWorkingPairModel = PureWorkingPairModel, + final diagramType=SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isobars, + isoLineType=SorpLib.Choices.ChangingConstantVariableOfDiagram.Linespace, + p_adsorpt_min=1000, + p_adsorpt_max=1000000, + T_adsorpt_min=283.15, + T_adsorpt_max=423.15) + "Diagram of isobars" + annotation (Placement(transformation(extent={{40,-12},{60,8}}))); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This models demonstrates how to create a diagram of isotherms, isosters, +or isobars for a working pair model using a fluid with just one regime +(i.e., gas/vapor). +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 23, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), experiment(StopTime=20, Tolerance=1e-06)); +end Test_ChartWorkingPairGas; diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/Test_ChartWorkingPairVLE.mo b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/Test_ChartWorkingPairVLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..d417307cb969146141507725e74441cf7165c149 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/Test_ChartWorkingPairVLE.mo @@ -0,0 +1,86 @@ +within SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.Tester; +model Test_ChartWorkingPairVLE + "Tester for the fluid property diagram model using the MSL for fluid property data calculation of a real fluid with a two-regime" + extends Modelica.Icons.Example; + + // + // Definition of parameters describing packages and models + // + replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Zeolith13X_Toth_WangDouglasLeVan2010_VLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE + "Pure working pair model" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true, + Evaluate=true, + HideResult=true); + + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Models and Media"), + choicesAllMatching = true); + + // + // Instantiation of models + // + SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.ChartWorkingPairVLE + diagramIsotherms( + redeclare final package Medium = Medium, + redeclare final model PureWorkingPairModel = PureWorkingPairModel, + final diagramType=SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isotherms, + isoLineType=SorpLib.Choices.ChangingConstantVariableOfDiagram.Linespace, + p_adsorpt_min=1000, + p_adsorpt_max=1000000, + T_adsorpt_min=283.15, + T_adsorpt_max=423.15) + "Diagram of isotherms" + annotation (Placement(transformation(extent={{-60,-12},{-40,8}}))); + + SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.ChartWorkingPairVLE + diagramIsosters( + redeclare final package Medium = Medium, + redeclare final model PureWorkingPairModel = PureWorkingPairModel, + final diagramType=SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isosters, + isoLineType=SorpLib.Choices.ChangingConstantVariableOfDiagram.Linespace, + p_adsorpt_max=1000000, + T_adsorpt_min=283.15, + T_adsorpt_max=423.15, + x_adsorpt_min=0.05, + x_adsorpt_max=0.25) + "Diagram of isosters" + annotation (Placement(transformation(extent={{-10,-12},{10,8}}))); + + SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents.ChartWorkingPairVLE + diagramIsobars( + redeclare final package Medium = Medium, + redeclare final model PureWorkingPairModel = PureWorkingPairModel, + final diagramType=SorpLib.Choices.DiagramTypePureComponentWorkingPair.Isobars, + isoLineType=SorpLib.Choices.ChangingConstantVariableOfDiagram.Linespace, + p_adsorpt_min=1000, + p_adsorpt_max=1000000, + T_adsorpt_min=283.15, + T_adsorpt_max=423.15) + "Diagram of isobars" + annotation (Placement(transformation(extent={{40,-12},{60,8}}))); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This models demonstrates how to create a diagram of isotherms, isosters, +or isobars for a working pair model using a real fluid with a two-phase regime. +<br/><br/> +To see the model behavior, plot the variables of the models over the +time. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>", revisions="<html> +<ul> + <li> + November 23, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>"), experiment(StopTime=20, Tolerance=1e-06)); +end Test_ChartWorkingPairVLE; diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/package.mo b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d06af8c19625fb5bdf4ccb21415fa1c92b7351c2 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs.FluidPropertyDiagrams.PureComponents; +package Tester "Package containing testers to test and varify models of fluid property diagrams for pure component working pairs" + extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented models of fluid property +diagrams. +</p> +</html>", revisions="<html> +<ul> + <li> + November 23, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Tester; diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/package.order b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/package.order new file mode 100644 index 0000000000000000000000000000000000000000..3be6fbcb2937defba9f33865601f982650f96183 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/Tester/package.order @@ -0,0 +1,3 @@ +Test_ChartWorkingPairGas +Test_ChartWorkingPairVLE +Test_ChartWorkingPairDubinin diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/package.mo b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..86ad1c59b0c6ca5dc52016fe73769c23e145427f --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.WorkingPairs.FluidPropertyDiagrams; +package PureComponents "Package containing diagram models of pure component working pairs" +extends Modelica.Icons.VariantsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains models to generate fluid property diagrams for +pure component working pairs. The implemented diagram types include +isotherms, isosterics, and isobars. +</p> +</html>", revisions="<html> +<ul> + <li> + November 23, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PureComponents; diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/package.order b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..4f967aca01acab5456cdda81ad8b3a69f06cb116 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/PureComponents/package.order @@ -0,0 +1,4 @@ +ChartWorkingPairGas +ChartWorkingPairVLE +ChartWorkingPairDubinin +Tester diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/package.mo b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..aaf5a8d09d7c1aa3b545fc93082fa9bc1019c63b --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs; +package FluidPropertyDiagrams "Package containing models to create fluid property diagrams" +extends Icons.MediaPackage; + +annotation (Documentation(info="<html> +<p> +This package contains models to generate fluid property diagrams. The +implemented diagram types include isotherms, isosterics, and isobars. +</p> +</html>", revisions="<html> +<ul> + <li> + November 23, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end FluidPropertyDiagrams; diff --git a/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/package.order b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/package.order new file mode 100644 index 0000000000000000000000000000000000000000..185a1a81fa36193673ce51fbedae4201c676e59a --- /dev/null +++ b/SorpLib/Media/WorkingPairs/FluidPropertyDiagrams/package.order @@ -0,0 +1 @@ +PureComponents diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureMediumSpecificFunctions/package.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureMediumSpecificFunctions/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..0e5655d9be7182f70c9c77d4c5771aaef86d4a2f --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureMediumSpecificFunctions/package.mo @@ -0,0 +1,839 @@ +within SorpLib.Media.WorkingPairs.Interfaces; +partial package PartialPureMediumSpecificFunctions "Base package defining medium specific functions for pure component adsorption" + extends Modelica.Icons.FunctionsPackage; + + // + // Definition of models + // + replaceable partial model AdsorptiveProperties + "Calculates all properties of the adsorptive at gas/vapor phase required for the working pair model at once" + extends Modelica.Icons.MaterialProperty; + + // + // Definition of parameters + // + parameter Boolean calcCaloricProperties = true + "= true, if caloric properties are calculated (i.e., h, u, h_ads, and cp)" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcEntropicProperties = false + "= true, if caloric properties are calculated (i.e., s, g, a, and s_ads)" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean calcAdsorptAdsorbateState = false + "= true, if state properties of average adsorpt phase and adosrbate phase are + calculated (i.e., requires numerical integration)" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean calcDerivativesIsotherm = true + "= true, if partial derivatives of isotherms required for mass, energy, and + entropy balance of working paur volumes are calculated" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcDerivativesMassEnergyBalance = true + "= true, if partial derivatives required for mass and energy balance of + working pair volumes are calculated" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcDerivativesIsotherm and calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcDerivativesEntropyBalance = false + "= true, if partial derivatives required for entropy balance of working + pair volumes are calculated" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcDerivativesIsotherm and + calcDerivativesMassEnergyBalance and calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean adsorptiveAtDewPoint = false + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + Evaluate=true, + HideResult=true, + choices(checkBox=true)); + + parameter Boolean neglectSpecifcVolume = false + "= true, if specific volume of the adsorpt is neglected (i.e., v_adsorpt = 0 + -> u_adsorpt = h_adsorpt and g_adsorpt = a_adsorpt)" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + choices(checkBox=true), + Evaluate= false, + HideResult=true); + parameter SorpLib.Choices.SpecificVolumeAdsorpt approachSpecificVolume= + SorpLib.Choices.SpecificVolumeAdsorpt.Constant + "Calculation approach for the specific volume of the adsorpt" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable=not neglectSpecifcVolume), + Evaluate=false, + HideResult=true, + choicesAllMatching=true); + parameter SorpLib.Choices.SpecificHeatCapacityAdsorpt + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.Constant + "Calculation approach for the specific heat capacity of the adsorpt" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + Evaluate=false, + HideResult=true, + choicesAllMatching=true); + parameter SorpLib.Choices.SorptionEnthalpy approachSorptionEnthalpy= + SorpLib.Choices.SorptionEnthalpy.Constant + "Calculation approach for the sorption enthalpy" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + Evaluate=false, + HideResult=true, + choicesAllMatching=true); + + parameter Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference if derivative is calculated numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Derivatives"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference if derivative is calculated numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Derivatives"), + Evaluate=true, + HideResult=true); + + // + // Definition of general inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Media.WorkingPairs.Records.PropertiesPureAdsorptive properties= + SorpLib.Media.WorkingPairs.Records.PropertiesPureAdsorptive( + state = SorpLib.Media.WorkingPairs.Records.StateVariables( + p=p, + T=T, + v=v, + h=h, + u=u, + s=s, + g=g, + a=a), + cp=cp, + p_sat=p_sat, + v_satLiq=v_satLiq, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + cp_satLiq=cp_satLiq, + dv_dp_T=dv_dp_T, + dv_dT_p=dv_dT_p, + dp_sat_dT=dp_sat_dT, + dv_satLiq_dT=dv_satLiq_dT, + ddv_satLiq_dT_dT=ddv_satLiq_dT_dT, + dh_adsorptiveToLiquid_dp_T=dh_adsorptiveToLiquid_dp_T, + dh_adsorptiveToLiquid_dT_p=dh_adsorptiveToLiquid_dT_p) + "Record containing all required properties of the adsorptive" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Parameters indicating which parameters must be calculated + // +protected + parameter Boolean require_caloricAdsorptAdsorbateState= + (calcCaloricProperties and calcAdsorptAdsorbateState) + "= true, if uptake-averaged thermal and caloric properties of the adsorpt and + adsorbate phase are required"; + parameter Boolean require_entropicAdsorptAdsorbateState= + (require_caloricAdsorptAdsorbateState and calcEntropicProperties) + "= true, if uptake-averaged entropic properties of the adsorpt and adsorbate + phase are required"; + + parameter Boolean require_massEnergyBalances= + (calcCaloricProperties and calcDerivativesIsotherm and + calcDerivativesMassEnergyBalance) + "= true, if properties for mass and energy balance are required"; + parameter Boolean require_entropyBalance= + (require_massEnergyBalances and calcDerivativesEntropyBalance) + "= true, if properties for entropy balance are required"; + + parameter Boolean require_dxv_avg_dp_T= + (require_massEnergyBalances) + "= true, if partial derivative of uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. pressure at constant temperature is required"; + parameter Boolean require_dxv_avg_dT_p= + (require_massEnergyBalances) + "= true, if partial derivative of uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. temperature at constant pressure is required"; + + parameter Boolean require_h_ads_Formal= + (calcCaloricProperties and approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Formal) + "= true, if properties for the specific enthalpy of adsorption are required"; + parameter Boolean require_h_ads_CC= + (calcCaloricProperties and approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron) + "= true, if properties for the specific enthalpy of adsorption according to + Clausius Clapeyron are required"; + parameter Boolean require_h_ads_Dubinin= + (calcCaloricProperties and approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Dubinin) + "= true, if properties for the specific enthalpy of adsorption according to + Dubinin are required"; + + parameter Boolean require_cp_adsorpt_ChakrabortyElAl= + (require_h_ads_Formal and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl) + "= true, if properties for the specific heat capacity according to Chakraborty + et al. are required"; + parameter Boolean require_cp_adsorpt_ChakrabortyElAl_CC= + (require_h_ads_CC and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl) + "= true, if properties for the specific heat capacity according to Chakraborty + et al. with the adsorption enthalpy according to Clausius Clapeyron are required"; + parameter Boolean require_cp_adsorpt_ChakrabortyElAl_Dubinin= + (require_h_ads_Dubinin and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl) + "= true, if properties for the specific heat capacity according to Chakraborty + et al. with the adsorption enthalpy according to Dubinin are required"; + + parameter Boolean require_cp_adsorpt_WaltonLeVan= + (require_h_ads_Formal and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.WaltonLeVan) + "= true, if properties for the specific heat capacity according to Walton and + Le Van are required"; + parameter Boolean require_cp_adsorpt_WaltonLeVan_CC= + (require_h_ads_CC and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.WaltonLeVan) + "= true, if properties for the specific heat capacity according to Walton and + Le Van with the adsorption enthalpy according to Clausius Clapeyron are required"; + parameter Boolean require_cp_adsorpt_WaltonLeVan_Dubinin= + (require_h_ads_Dubinin and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.WaltonLeVan) + "= true, if properties for the specific heat capacity according to Walton and + Le Van with the adsorption enthalpy according to Dubinin are required"; + + parameter Boolean require_cp_adsorpt_SchwambergerSchmidt= + (require_h_ads_Formal and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.SchwambergerSchmidt) + "= true, if properties for the specific heat capacity according to Schwamberger + and Schmidt are required"; + parameter Boolean require_cp_adsorpt_SchwambergerSchmidt_CC= + (require_h_ads_CC and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.SchwambergerSchmidt) + "= true, if properties for the specific heat capacity according to Schwamberger + and Schmidt with the adsorption enthalpy according to Clausius Clapeyron are required"; + parameter Boolean require_cp_adsorpt_SchwambergerSchmidt_Dubinin= + (require_h_ads_Dubinin and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.SchwambergerSchmidt) + "= true, if properties for the specific heat capacity according to Schwamberger + and Schmidt with the adsorption enthalpy according to Dubinin are required"; + + parameter Boolean require_v_adsorpt= + not neglectSpecifcVolume or + not neglectSpecifcVolume and + ((require_dxv_avg_dp_T) or + (require_dxv_avg_dT_p) or + (require_caloricAdsorptAdsorbateState and require_h_ads_Formal) or + (require_entropicAdsorptAdsorbateState and require_h_ads_Formal) or + (require_h_ads_Formal) or + (require_cp_adsorpt_ChakrabortyElAl) or + (require_cp_adsorpt_ChakrabortyElAl_CC) or + (require_cp_adsorpt_WaltonLeVan) or + (require_cp_adsorpt_SchwambergerSchmidt)) or + (require_h_ads_Dubinin) or + (require_caloricAdsorptAdsorbateState and require_h_ads_Dubinin) or + (require_entropicAdsorptAdsorbateState and require_h_ads_Dubinin) or + (require_cp_adsorpt_ChakrabortyElAl_Dubinin) or + (require_cp_adsorpt_WaltonLeVan_Dubinin) or + (require_cp_adsorpt_SchwambergerSchmidt_Dubinin) + "= true, if specific volume of the adsorpt is required"; + parameter Boolean require_dv_adsorpt_dp_T= + not neglectSpecifcVolume and + ((require_dxv_avg_dp_T) or + (require_cp_adsorpt_ChakrabortyElAl) or + (require_cp_adsorpt_WaltonLeVan) or + (require_cp_adsorpt_SchwambergerSchmidt)) or + (require_cp_adsorpt_ChakrabortyElAl_Dubinin) or + (require_cp_adsorpt_WaltonLeVan_Dubinin) or + (require_cp_adsorpt_SchwambergerSchmidt_Dubinin) + "= true, if the partial derivative of the specific volume of the adsorpt w.r.t. + pressure at constant temperature is required"; + parameter Boolean require_dv_adsorpt_dT_p= + (require_dv_adsorpt_dp_T) or + not neglectSpecifcVolume and + ((require_dxv_avg_dT_p) or + (require_cp_adsorpt_ChakrabortyElAl) or + (require_cp_adsorpt_ChakrabortyElAl_CC) or + (require_cp_adsorpt_WaltonLeVan) or + (require_cp_adsorpt_SchwambergerSchmidt)) or + (require_h_ads_Dubinin) or + (require_cp_adsorpt_ChakrabortyElAl_Dubinin) or + (require_cp_adsorpt_WaltonLeVan_Dubinin) or + (require_cp_adsorpt_SchwambergerSchmidt_Dubinin) + "= true, if the partial derivative of the specific volume of the adsorpt w.r.t. + temperature at pressure temperature is required"; + parameter Boolean require_ddv_adsorpt_dT_dT_p= + (require_cp_adsorpt_ChakrabortyElAl_Dubinin) or + (require_cp_adsorpt_WaltonLeVan_Dubinin) or + (require_cp_adsorpt_SchwambergerSchmidt) + "= true, if the second-order partial derivative of the specific volume of the + adsorpt w.r.t. temperature at pressure temperature is required"; + + parameter Boolean require_dv_adsorptive_dp_T= + (require_h_ads_Formal and require_massEnergyBalances) or + (require_h_ads_Formal and require_entropyBalance) or + (require_cp_adsorpt_ChakrabortyElAl) + "= true, if the partial derivative of the specific volume of the adsorptive + w.r.t. pressure at constant temperature is required"; + parameter Boolean require_dv_adsorptive_dT_p= + (require_dv_adsorptive_dp_T) or + (require_cp_adsorpt_ChakrabortyElAl) or + (require_cp_adsorpt_ChakrabortyElAl_CC) or + (require_cp_adsorpt_ChakrabortyElAl_Dubinin) + "= true, if the partial derivative of the specific volume of the adsorptive + w.r.t. temperature at pressure temperature is required"; + + parameter Boolean require_cp_adsorptive= + (require_massEnergyBalances) or + (require_entropyBalance) or + (require_cp_adsorpt_ChakrabortyElAl) or + (require_cp_adsorpt_ChakrabortyElAl_CC) or + (require_cp_adsorpt_ChakrabortyElAl_Dubinin) or + (require_cp_adsorpt_WaltonLeVan) or + (require_cp_adsorpt_WaltonLeVan_CC) or + (require_cp_adsorpt_WaltonLeVan_Dubinin) + "= true, if the specific heat capacity of the adsorptive is required"; + + parameter Boolean require_p_sat= + (require_v_adsorpt and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve) or + (require_h_ads_Dubinin) or + (require_cp_adsorpt_ChakrabortyElAl_Dubinin) or + (require_cp_adsorpt_WaltonLeVan_Dubinin) or + (require_cp_adsorpt_SchwambergerSchmidt_Dubinin) + "= true, if the vapor pressure is required"; + parameter Boolean require_dp_sat_dT= + (require_massEnergyBalances and + approachSpecificVolume == SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve) or + (require_massEnergyBalances and require_h_ads_Dubinin) or + (require_entropyBalance and require_h_ads_Dubinin) or + (require_cp_adsorpt_ChakrabortyElAl_Dubinin) or + (require_cp_adsorpt_WaltonLeVan_Dubinin) or + (require_cp_adsorpt_SchwambergerSchmidt_Dubinin) + "= true, if the partial derivative of the vapor pressure w.r.. temperature is + required"; + + parameter Boolean require_rho_satLiq_T= + (require_v_adsorpt and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve) + "= true, if the bubble point density at given temperature is required"; + parameter Boolean require_drho_satLiq_dT= + (require_dv_adsorpt_dT_p and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve) + "= true, if the partial derivative of the bubble point density at given + temperature w.r.t. tempreature is required"; + parameter Boolean require_ddrho_satLiq_dT_dT= + (require_ddv_adsorpt_dT_dT_p and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve) + "= true, if the second-order partial derivative of the bubble point density + at given temperature w.r.t. tempreature is required"; + + parameter Boolean require_h_adsorptiveToLiquid= + (require_h_ads_Dubinin) or + (require_cp_adsorpt_ChakrabortyElAl_Dubinin) or + (require_cp_adsorpt_WaltonLeVan_Dubinin) or + (require_cp_adsorpt_SchwambergerSchmidt_Dubinin) + "= true, if the specific enthalpy of vaporization is required"; + parameter Boolean require_dh_adsorptiveToLiquid_dp_T= + (require_h_ads_Dubinin and require_massEnergyBalances) or + (require_h_ads_Dubinin and require_entropyBalance) or + (require_cp_adsorpt_ChakrabortyElAl_Dubinin) or + (require_cp_adsorpt_WaltonLeVan_Dubinin) or + (require_cp_adsorpt_SchwambergerSchmidt_Dubinin) + "= true, if the partial derivatieve of the specific enthalpy of vaporization + w.r.t. pressure and constant temperature is required"; + parameter Boolean require_dh_adsorptiveToLiquid_dT_p= + (require_dh_adsorptiveToLiquid_dp_T) + "= true, if the partial derivatieve of the specific enthalpy of vaporization + w.r.t. temperature and constant pressure is required"; + + parameter Boolean require_cp_satLiq_T= + (calcCaloricProperties and approachSpecificHeatCapacity== + SorpLib.Choices.SpecificHeatCapacityAdsorpt.BoilingCurve) + "= true, if the specific heat capacity of the bubble point at given temperature + is required"; + + // + // State variables + // + Modelica.Units.SI.SpecificVolume v + "Specific volume"; + Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy"; + Modelica.Units.SI.SpecificInternalEnergy u + "Specific internal energy"; + Modelica.Units.SI.SpecificEntropy s + "Specific entropy"; + Modelica.Units.SI.SpecificGibbsFreeEnergy g + "Specific free enthalpy (i.e., Gibbs free energy)"; + Modelica.Units.SI.SpecificHelmholtzFreeEnergy a + "Specific free energy (i.e., Helmholts free energy)"; + + // + // Additional properties of the one-phase regime + // + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity"; + + // + // Additional properties of the two-phase regime + // + Modelica.Units.SI.Pressure p_sat + "Saturated vapor pressure"; + Modelica.Units.SI.SpecificVolume v_satLiq + "Specific volume at the bubble point at given temperature"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + + Modelica.Units.SI.SpecificHeatCapacity cp_satLiq + "Specific heat capacaity at the bubble point at given temperature"; + + // + // Partial derivatives + // + SorpLib.Units.DerSpecificVolumeByPressure dv_dp_T + "Partial derivative of the specific volume w.r.t. pressure at constant + temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_dT_p + "Partial derivative of the specific volume w.r.t. temperature at constant + pressure"; + + Modelica.Media.Common.DerPressureByTemperature dp_sat_dT + "Partial derivative of saturated vapor pressure w.r.t. temperature"; + + SorpLib.Units.DerSpecificVolumeByTemperature dv_satLiq_dT + "Partial derivative of the specific volume at the bubble point at given + temperature w.r.t. temperature"; + SorpLib.Units.DerSpecificVolumeByTemperatureTemperature ddv_satLiq_dT_dT + "Second-order partial derivative of the specific volume at the bubble point + at given temperature w.r.t. temperature"; + + SorpLib.Units.DerSpecificEnthalpyByPressure dh_adsorptiveToLiquid_dp_T + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptiveToLiquid_dT_p + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This model calculates all properties of the adsorptive required for the working +pair model at once. Thus, computational costs are reduced because redundant +calculations of the same properties are avoided. +</p> +</html>")); + end AdsorptiveProperties; + // + // Functions of the two-phase regime + // + replaceable partial function p_sat_T + "Calculates the vapor pressure as function of temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Saturated vapor temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_sat + "Saturated vapor pressure" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates the vapor pressure at the bubble point and its first- +and second-order partial derivatives w.r.t. temperature as function of temperaure. +</p> +</html>")); + end p_sat_T; + + replaceable partial function rho_satLiq_T + "Calculates the density at the bubble point as function of temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Saturated vapor temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Density rho_satLiq + "Density at bubble point" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates the specific volume at the bubble point and its first- +and second-order partial derivatives w.r.t. temperature as function of temperaure. +</p> +</html>")); + end rho_satLiq_T; + + replaceable partial function pRho_satLiq + "Calculates the vapor pressure, density at the bubble point, and their first- and second-order partial derivatives w.r.t. temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T + "Saturated vapor temperature" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference if derivative is calculated numerically" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.Pressure p_sat + "Saturated vapor pressure" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + output Modelica.Units.SI.DerPressureByTemperature dp_sat_dT + "Partial derivative of the vapor pressure w.r.t. temperature" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + output SorpLib.Units.DerPressureByTemperatureTemperature ddp_sat_dT_dT + "Calculates the second-order partial derivative of the vapor pressure w.r.t. + temperature" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + + + output Modelica.Units.SI.Density rho_satLiq + "Density at bubble point" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + output SorpLib.Units.DerDensityByTemperature drho_satLiq_dT + "Calculates the partial derivative of the density at the bubble point w.r.t. + temperature" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + output SorpLib.Units.DerDensityByTemperatureTemperature ddrho_satLiq_dT_dT + "Calculates the second-order partial derivative of the density at the bubble + point w.r.t. temperature" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates the vapor pressure and the specific volume at the +bubble point as function of temperature. For both properties, this function +also calculates the first- and second-order partial derivatives w.r.t. temperature. +</p> +</html>")); + end pRho_satLiq; + // + // Functions of the one-phase regime + // + replaceable partial function h_pT + "Calculates the specific enthalpy of the adsorptive as function of pressure + and temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + + input Modelica.Units.SI.Pressure p_lb + "Lower bound of pressure (i.e., if gas state and p < p_lb, assume ideal gas)" + annotation (Dialog(tab="General",group="Inputs")); + + input Modelica.Units.SI.SpecificEnthalpy h_ref + "Specific enthalpy at reference pressure and temperature" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Pressure p_ref + "Reference pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T_ref + "Reference temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates the specific enthalpy as function of pressure and temperature. +If the pressure is below its lower bound <i>p_lb</i>, the specific enthalpy is calculated +assuming an ideal gas using the reference point and the specific heat capacity evaluated +at <i>p_lb</i> and <i>T</i>. +</p> +</html>")); + end h_pT; + + replaceable partial function s_pT + "Calculates the specific entropy of the adsorptive as function of pressure + and temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + + input Modelica.Units.SI.Pressure p_lb + "Lower bound of pressure (i.e., if gas state and p < p_lb, assume ideal gas)" + annotation (Dialog(tab="General",group="Inputs")); + + input Modelica.Units.SI.SpecificEntropy s_ref + "Specific entropy at reference pressure and temperature" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Pressure p_ref + "Reference pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T_ref + "Reference temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEntropy s + "Specific entropy" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates the specific entropy as function of pressure and temperature. +If the pressure is below its lower bound <i>p_lb</i>, the specific entropy is calculated +assuming an ideal gas using the reference point and the specific heat capacity evaluated +at <i>p_lb</i> and <i>T</i>. +</p> +</html>")); + end s_pT; + // + // Functions calculating properties required for calculating the specific heat + // capacity of the adsorpt + // + replaceable partial function calc_properties + "Calculates all properties of the adsorptive at gas/vapor phase required for the working pair model at once" + extends Modelica.Icons.Function; + + input Modelica.Units.SI.Pressure p + "Pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T + "Temperature" + annotation (Dialog(tab="General",group="Inputs")); + + input Modelica.Units.SI.PressureDifference dp + "Pressure difference if derivative is calculated numerically" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference if derivative is calculated numerically" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Pressure p_min + "Minimal pressure at which fluid properties can be calculated (i.e., assumption + ideal gas at lower pressure)" + annotation (Dialog(tab="General",group="Inputs")); + + input Boolean require_v_adsorptive + "= true, if the specific volume of the adsorptive and its partial derivatives + are required" + annotation (Dialog(tab="General",group="Inputs")); + input Boolean require_h_adsorptive + "= true, if the specific enthalpy of the adsorptive is required" + annotation (Dialog(tab="General",group="Inputs")); + input Boolean require_s_adsorptive + "= true, if the specific entropy of the adsorptive is required" + annotation (Dialog(tab="General",group="Inputs")); + input Boolean require_dh_adsorptive_dT_dp + "= true, if the partial derivative of the specific enthalpy w.r.t. temperature + at constant pressure is required" + annotation (Dialog(tab="General",group="Inputs")); + input Boolean require_h_adsorptiveToLiquid + "= true, if specific enthalpy difference between adsorptive phase and saturated + liquid phase is required" + annotation (Dialog(tab="General",group="Inputs")); + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificVolume v + "Specific volume" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.DerSpecificVolumeByPressure dv_dp_T + "Partial derivative of the specific volume w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.DerSpecificVolumeByTemperature dv_dT_p + "Partial derivative of the specific volume w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.SpecificEnthalpy h + "Specific enthalpy" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.SpecificEntropy s + "Specific enropy" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.SpecificHeatCapacity dh_dT_p + "Partial derivative of the specific enthalpy w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.SpecificEnthalpy h_atl + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output SorpLib.Units.DerSpecificEnthalpyByPressure dh_atl_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + output Modelica.Units.SI.SpecificHeatCapacity dh_atl_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates all properties of the adsorptive required for calculating +the specific heat capacity of the adsorpt or uptake-averaged properties of the adsorpt +and their partial derivatives. Thus, computational costs are reduced because redundant +calculations of the same properties are avoided. +</p> +</html>")); + end calc_properties; + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This partial package defines basic models and functions that are required to calculate all thermodynamic +properties of a pure component working pair. These basic models and functions are media-specific models +and functions, thus depending on the selected media model. Packages that inherit properties from this +partial package must redeclare all partial models and functions. It may be that a partial model or function +cannot be calculated with the selected media model. An example is the saturated vapor pressure as a function +of temperature when the media model is an ideal gas. Such functions will not be accessed if the working pair +is parameterized correctly. Therefore, these functions shall just return a dummy value when redeclaring. +</p> +</html>")); +end PartialPureMediumSpecificFunctions; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureMediumSpecificFunctions/package.order b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureMediumSpecificFunctions/package.order new file mode 100644 index 0000000000000000000000000000000000000000..41b0ed180dc12d65f46ae0fadcfaa3379946373d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureMediumSpecificFunctions/package.order @@ -0,0 +1,7 @@ +AdsorptiveProperties +p_sat_T +rho_satLiq_T +pRho_satLiq +h_pT +s_pT +calc_properties diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/AdsorptProperties.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/AdsorptProperties.mo new file mode 100644 index 0000000000000000000000000000000000000000..8272bc988f14ee80b15df6191163f806e3e890fa --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/AdsorptProperties.mo @@ -0,0 +1,1656 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +model AdsorptProperties + "Calculates all properties of the adsorpt required for the working pair model at once" + extends Modelica.Icons.MaterialProperty; + + // + // Definition of parameters regarding the calculation approach + // + parameter SorpLib.Choices.IndependentVariablesPureComponentWorkingPair + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT + "Independent state variables of the working pair model" + annotation (Dialog(tab="General", group="Calculation Setup"), + choicesAllMatching=true, + Evaluate=true, + HideResult=true); + + parameter Boolean calcCaloricProperties = true + "= true, if caloric properties are calculated (i.e., h, u, h_ads, and cp)" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcEntropicProperties = false + "= true, if caloric properties are calculated (i.e., s, g, a, and s_ads)" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean calcAdsorptAdsorbateState = false + "= true, if state properties of average adsorpt phase and adosrbate phase are + calculated (i.e., requires numerical integration)" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean calcDerivativesIsotherm = true + "= true, if partial derivatives of isotherms required for mass, energy, and + entropy balance of working paur volumes are calculated" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcDerivativesMassEnergyBalance = true + "= true, if partial derivatives required for mass and energy balance of + working pair volumes are calculated" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcDerivativesIsotherm and calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + parameter Boolean calcDerivativesEntropyBalance = false + "= true, if partial derivatives required for entropy balance of working + pair volumes are calculated" + annotation (Dialog(tab = "General", group = "Calculation Setup", + enable = calcDerivativesIsotherm and + calcDerivativesMassEnergyBalance and calcCaloricProperties), + choices(checkBox=true), + Evaluate=true, + HideResult=true); + + parameter Boolean adsorptiveAtDewPoint = false + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab = "General", group = "Calculation Setup"), + Evaluate=true, + HideResult=true, + choices(checkBox=true)); + + // + // Definition of parameters regarding sorption enthalpy + // + parameter SorpLib.Choices.SorptionEnthalpy approachSorptionEnthalpy= + SorpLib.Choices.SorptionEnthalpy.Constant + "Calculation approach for the sorption enthalpy" + annotation (Dialog(tab="Sorption Enthalpy", group="General"), + Evaluate=false, + HideResult=true, + choicesAllMatching=true); + + parameter Modelica.Units.SI.SpecificEnthalpy h_ads_constant= 3000e3 + "Constant specific enthalpy of adsorption" + annotation (Dialog(tab="Sorption Enthalpy", group="Constant", + enable=(approachSorptionEnthalpy== + SorpLib.Choices.SorptionEnthalpy.Constant)), + HideResult=true, + Evaluate= false); + + // + // Definition of parameters regarding adsorpt phase's specific heat capacity + // + parameter SorpLib.Choices.SpecificHeatCapacityAdsorpt + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.Constant + "Calculation approach for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="General"), + Evaluate=false, + HideResult=true, + choicesAllMatching=true); + + parameter Modelica.Units.SI.SpecificHeatCapacity cp_adsorpt_constant= 4e3 + "Constant specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Constant", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.Constant)), + HideResult=true, + Evaluate= false); + + parameter SorpLib.Choices.GeneralizedFunctionApproach cp_adsorpt_function= + SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Generalized function used to calculate the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approachSpecificHeatCapacity == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Temperature T_ref_cp_adsorpt = 293.15 + "Reference temperature for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Modelica.Units.SI.SpecificHeatCapacity cp_adsorpt_ref = 1 + "Reference fluid property data for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real coefficients_cp_adsorpt[:]={cp_adsorpt_constant} + "Coefficients of generalized function for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real exponents_cp_adsorpt[size(coefficients_cp_adsorpt,1)]={0} + "Exponents of generalized function for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Generalized Function", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + + parameter SorpLib.Choices.InterpolationApproach cp_adsorpt_interpolation= + SorpLib.Choices.InterpolationApproach.Linear + "Interpolation approach used to calculate the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Interpolation", + enable=(approachSpecificHeatCapacity == + SorpLib.Choices.SpecificVolumeAdsorpt.Interpolation)), + Evaluate=false, + HideResult=true); + parameter Real abscissa_cp_adsorpt[:]={0, 1000} + "Known abscissa values for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Interpolation", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificVolumeAdsorpt.Interpolation)), + HideResult=true, + Evaluate= true); + parameter Real ordinate_cp_adsorpt[size(abscissa_cp_adsorpt,1)]= + {cp_adsorpt_constant, cp_adsorpt_constant} + "Known ordinate values for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Interpolation", + enable=(approachSpecificHeatCapacity== + SorpLib.Choices.SpecificHeatCapacityAdsorpt.Interpolation)), + HideResult=true, + Evaluate= true); + parameter Real coefficients_cubicSplines_cp_adsorpt[size(abscissa_cp_adsorpt,1),4]= + SorpLib.Media.Functions.Utilities.calcCubicSplineCoefficients( + abscissa=abscissa_cp_adsorpt, + ordinate=ordinate_cp_adsorpt) + "Coefficient a to d for cubic polynomials for the specific heat capacity of the adsorpt" + annotation (Dialog(tab="Specific Heat Capacity", group="Interpolation", + enable=false), + HideResult=true, + Evaluate= true); + + // + // Definition of parameters regarding adsorpt phase's specific volume + // + parameter Boolean neglectSpecifcVolume = false + "= true, if specific volume of the adsorpt is neglected (i.e., v_adsorpt = 0 + -> u_adsorpt = h_adsorpt and g_adsorpt = a_adsorpt)" + annotation (Dialog(tab = "Specific Volume", group = "General"), + choices(checkBox=true), + Evaluate= false, + HideResult=true); + parameter SorpLib.Choices.SpecificVolumeAdsorpt approachSpecificVolume= + SorpLib.Choices.SpecificVolumeAdsorpt.Constant + "Calculation approach for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="General", + enable=not neglectSpecifcVolume), + Evaluate=false, + HideResult=true, + choicesAllMatching=true); + + parameter Modelica.Units.SI.SpecificVolume v_adsorpt_constant= 1e-3 + "Constant specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Constant", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.Constant)), + HideResult=true, + Evaluate= false); + + parameter SorpLib.Choices.GeneralizedFunctionApproach v_adsorpt_function= + SorpLib.Choices.GeneralizedFunctionApproach.PolynomialFunctionTemperature + "Generalized function used to calculate the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.Temperature T_ref_v_adsorpt = 293.15 + "Reference temperature for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Modelica.Units.SI.SpecificVolume v_adsorpt_ref = 1 + "Reference fluid property data for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real coefficients_v_adsorpt[:]={v_adsorpt_constant} + "Coefficients of generalized function for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + parameter Real exponents_v_adsorpt[size(coefficients_v_adsorpt,1)]={0} + "Exponents of generalized function for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Generalized Function", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction)), + HideResult=true, + Evaluate= true); + + parameter SorpLib.Choices.InterpolationApproach v_adsorpt_interpolation= + SorpLib.Choices.InterpolationApproach.Linear + "Interpolation approach used to calculate the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Interpolation", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.Interpolation)), + Evaluate=false, + HideResult=true); + parameter Real abscissa_v_adsorpt[:]={0, 1000} + "Known abscissa values for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Interpolation", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.Interpolation)), + HideResult=true, + Evaluate= true); + parameter Real ordinate_v_adsorpt[size(abscissa_v_adsorpt,1)]= + {v_adsorpt_constant, v_adsorpt_constant} + "Known ordinate values for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Interpolation", + enable=(not neglectSpecifcVolume and approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.Interpolation)), + HideResult=true, + Evaluate= true); + parameter Real coefficients_cubicSplines_v_adsorpt[size(abscissa_v_adsorpt,1),4]= + SorpLib.Media.Functions.Utilities.calcCubicSplineCoefficients( + abscissa=abscissa_v_adsorpt, + ordinate=ordinate_v_adsorpt) + "Coefficient a to d for cubic polynomials for the specific volume of the adsorpt" + annotation (Dialog(tab="Specific Volume", group="Interpolation", + enable=false), + HideResult=true, + Evaluate= true); + + // + // Definition of parameters regarding advanced options + // + parameter Modelica.Units.SI.Pressure p_adsorpt_min = 615 + "Lower limit for the pressure p_adsorpt" + annotation (Dialog(tab = "Advanced", group = "Limiter"), + Evaluate=true, + HideResult=true); + + parameter Modelica.Units.SI.PressureDifference dp = 1e-3 + "Pressure difference used when calculating partial derivatives numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Derivatives"), + Evaluate=true, + HideResult=true); + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used when calculating partial derivatives numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Derivatives"), + Evaluate=true, + HideResult=true); + parameter Real tolerance_adsorpt_int_h = 1e-6 + "Integration tolerance when calculating the specific average enthalpy of the + adsorpt numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Integrals", + enable=calcAdsorptAdsorbateState and calcCaloricProperties), + Evaluate=true, + HideResult=true); + parameter Real tolerance_adsorpt_int_s = 1e-6 + "Integration tolerance when calculating the specific average entropy of the + adsorpt numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Integrals", + enable=calcAdsorptAdsorbateState and calcEntropicProperties), + Evaluate=true, + HideResult=true); + parameter Real tolerance_adsorpt_int_cp = 1e-2 + "Integration tolerance when calculating the specific heat capacity numerically" + annotation (Dialog(tab="Advanced", group="Numerics - Integrals", + enable=calcCaloricProperties), + Evaluate=true, + HideResult=true); + parameter SorpLib.Units.Uptake x_adsorpt_lb = 0 + "Lower limit for integral when calculating the specific heat capacity of the + adsorpt or uptake-averaged porperties of the adsorpt numerically (i.e., + should be zero)" + annotation (Dialog(tab="Advanced", group="Numerics - Integrals", + enable=calcCaloricProperties), + Evaluate=true, + HideResult=true); + + // + // Definition of general inputs + // + input Real[no_coefficients] c + "Isotherm coefficients" + annotation (Dialog(tab="General",group="Inputs")); + input Real[no_coefficients] dc_dT_adsorpt + "Partial derivatives of the isotherm coefficients w.r.t. temperature" + annotation (Dialog(tab="General",group="Inputs")); + input Real[no_coefficients] ddc_dT_adsorpt_dT_adsorpt + "Second-prder partial derivatives of the isotherm coefficients w.r.t. + temperature" + annotation (Dialog(tab="General",group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.Uptake x_adsorpt + "Equilibrium uptake" + annotation (Dialog(tab="General", group="Inputs")); + + input + SorpLib.Media.WorkingPairs.Records.PropertiesPureAdsorptive properties_adsorptive + "Record containing all properties of the adsorptive required for the working + pair model" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Media.WorkingPairs.Records.PropertiesPureAdsorpt properties= + SorpLib.Media.WorkingPairs.Records.PropertiesPureAdsorpt( + state = SorpLib.Media.WorkingPairs.Records.StateVariables( + p=p_avg, + T=T_avg, + v=v_avg, + h=h_avg, + u=u_avg, + s=s_avg, + g=g_avg, + a=a_avg), + v=v, + h_ads=h_ads, + cp=cp, + derivatives_isotherm= + SorpLib.Media.WorkingPairs.Records.DerivativesPureIsothermModel( + dx_dp_T=dx_dp_T, + dx_dT_p=dx_dT_p, + dp_dx_T=dp_dx_T, + dp_dT_x=dp_dT_x), + dxv_avg_dp_T=dxv_avg_dp_T, + dxv_avg_dT_p=dxv_avg_dT_p, + dxh_avg_dp_T=dxh_avg_dp_T, + dxh_avg_dT_p=dxh_avg_dT_p, + dxh_avg_dx_T=dxh_avg_dx_T, + dxh_avg_dT_x=dxh_avg_dT_x, + dxs_avg_dp_T=dxs_avg_dp_T, + dxs_avg_dT_p=dxs_avg_dT_p, + dxs_avg_dx_T=dxs_avg_dx_T, + dxs_avg_dT_x=dxs_avg_dT_x) + "Record containing all required properties of the adsorpt" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of constants + // + constant Modelica.Units.SI.MolarMass M_adsorpt = M_adsorptive + "Molar mass of the adsorpt/adsorptive"; + + // + // Booleans indicating which variables must be calculated + // +protected + parameter Boolean require_caloricAdsorptAdsorbateState= + (calcCaloricProperties and calcAdsorptAdsorbateState) + "= true, if uptake-averaged thermal and caloric properties of the adsorpt and + adsorbate phase are required"; + parameter Boolean require_entropicAdsorptAdsorbateState= + (require_caloricAdsorptAdsorbateState and calcEntropicProperties) + "= true, if uptake-averaged entropic properties of the adsorpt and adsorbate + phase are required"; + + parameter Boolean require_massEnergyBalances= + (calcCaloricProperties and calcDerivativesIsotherm and + calcDerivativesMassEnergyBalance) + "= true, if properties for mass and energy balance are required"; + parameter Boolean require_entropyBalance= + (require_massEnergyBalances and calcDerivativesEntropyBalance) + "= true, if properties for entropy balance are required"; + + parameter Boolean require_dxv_avg_dp_T= + (require_massEnergyBalances) + "= true, if partial derivative of uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. pressure at constant temperature is required"; + parameter Boolean require_dxv_avg_dT_p= + (require_massEnergyBalances) + "= true, if partial derivative of uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. temperature at constant pressure is required"; + + parameter Boolean require_dxh_avg_dp_T= + (require_massEnergyBalances and stateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT) + "= true, if partial derivative of uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. pressure at constant temperature is required"; + parameter Boolean require_dxh_avg_dT_p= + (require_massEnergyBalances and stateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT) + "= true, if partial derivative of uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. temperature at constant pressure is required"; + parameter Boolean require_dxh_avg_dx_T= + (require_massEnergyBalances) + "= true, if partial derivative of uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. uptake at constant temperature is required"; + parameter Boolean require_dxh_avg_dT_x= + (require_massEnergyBalances) + "= true, if partial derivative of uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. temperature at constant uptake is required"; + + parameter Boolean require_dxs_avg_dp_T= + (require_entropyBalance and stateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT) + "= true, if partial derivative of uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. pressure at constant temperature is required"; + parameter Boolean require_dxs_avg_dT_p= + (require_entropyBalance and stateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT) + "= true, if partial derivative of uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. temperature at constant pressure is required"; + parameter Boolean require_dxs_avg_dx_T= + (require_entropyBalance) + "= true, if partial derivative of uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. uptake at constant temperature is required"; + parameter Boolean require_dxs_avg_dT_x= + (require_entropyBalance) + "= true, if partial derivative of uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. temperature at constant uptake is required"; + + parameter Boolean require_h_ads_Formal= + (calcCaloricProperties and approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Formal) + "= true, if properties for the specific enthalpy of adsorption are required"; + parameter Boolean require_h_ads_CC= + (calcCaloricProperties and approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron) + "= true, if properties for the specific enthalpy of adsorption according to + Clausius Clapeyron are required"; + parameter Boolean require_h_ads_Dubinin= + (calcCaloricProperties and approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Dubinin) + "= true, if properties for the specific enthalpy of adsorption according to + Dubinin are required"; + + parameter Boolean require_cp_ChakrabortyElAl= + (require_h_ads_Formal and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl) + "= true, if properties for the specific heat capacity according to Chakraborty + et al. are required"; + parameter Boolean require_cp_ChakrabortyElAl_CC= + (require_h_ads_CC and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl) + "= true, if properties for the specific heat capacity according to Chakraborty + et al. with the adsorption enthalpy according to Clausius Clapeyron are required"; + parameter Boolean require_cp_ChakrabortyElAl_Dubinin= + (require_h_ads_Dubinin and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl) + "= true, if properties for the specific heat capacity according to Chakraborty + et al. with the adsorption enthalpy according to Dubinin are required"; + + parameter Boolean require_cp_WaltonLeVan= + (require_h_ads_Formal and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.WaltonLeVan) + "= true, if properties for the specific heat capacity according to Walton and + Le Van are required"; + parameter Boolean require_cp_WaltonLeVan_CC= + (require_h_ads_CC and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.WaltonLeVan) + "= true, if properties for the specific heat capacity according to Walton and + Le Van with the adsorption enthalpy according to Clausius Clapeyron are required"; + parameter Boolean require_cp_WaltonLeVan_Dubinin= + (require_h_ads_Dubinin and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.WaltonLeVan) + "= true, if properties for the specific heat capacity according to Walton and + Le Van with the adsorption enthalpy according to Dubinin are required"; + + parameter Boolean require_cp_SchwambergerSchmidt= + (require_h_ads_Formal and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.SchwambergerSchmidt) + "= true, if properties for the specific heat capacity according to Schwamberger + and Schmidt are required"; + parameter Boolean require_cp_SchwambergerSchmidt_CC= + (require_h_ads_CC and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.SchwambergerSchmidt) + "= true, if properties for the specific heat capacity according to Schwamberger + and Schmidt with the adsorption enthalpy according to Clausius Clapeyron are required"; + parameter Boolean require_cp_SchwambergerSchmidt_Dubinin= + (require_h_ads_Dubinin and approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.SchwambergerSchmidt) + "= true, if properties for the specific heat capacity according to Schwamberger + and Schmidt with the adsorption enthalpy according to Dubinin are required"; + + parameter Boolean require_derivativesIsotherm_pT= + (calcDerivativesIsotherm) or + not neglectSpecifcVolume and (require_dxv_avg_dp_T) or + (require_h_ads_Formal) or + (require_h_ads_CC) or + (require_cp_ChakrabortyElAl) or + (require_cp_ChakrabortyElAl_CC) or + (require_cp_ChakrabortyElAl_Dubinin) or + (require_dxh_avg_dp_T) or + (require_dxh_avg_dT_p) + "= true, if partial derivatives of the isotherm model w.r.t. pressure and + temperature are required"; + parameter Boolean require_derivativesIsotherm_xT= + (require_derivativesIsotherm_pT and stateVariables== + SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.xT) or + (require_cp_ChakrabortyElAl) or + (require_cp_ChakrabortyElAl_CC) or + (require_cp_ChakrabortyElAl_Dubinin) or + (require_dxh_avg_dp_T) or + (require_dxh_avg_dT_p) + "= true, if partial derivatives of the isotherm model w.r.t. uptake and + temperature are required"; + parameter Boolean require_ddx_dp_dp_T= + (require_derivativesIsotherm_pT and require_massEnergyBalances and + (require_h_ads_Formal or require_h_ads_CC)) or + (require_derivativesIsotherm_pT and require_entropyBalance and + (require_h_ads_Formal or require_h_ads_CC)) or + (require_cp_ChakrabortyElAl) or + (require_cp_ChakrabortyElAl_CC) + "= true, if second-order partial derivative of the uptake w.r.t. pressure at + constant temperature is required"; + parameter Boolean require_ddx_dT_dT_p= + (require_ddx_dp_dp_T) + "= true, if second-order partial derivative of the uptake w.r.t. temperature + at constant pressure is required"; + parameter Boolean require_ddx_dp_dT= + (require_ddx_dp_dp_T) + "= true, if second-order partial derivative of the uptake w.r.t. pressure and + temperature is required"; + + parameter Boolean require_v= + not neglectSpecifcVolume or + not neglectSpecifcVolume and + ((require_dxv_avg_dp_T) or + (require_dxv_avg_dT_p) or + (require_caloricAdsorptAdsorbateState and require_h_ads_Formal) or + (require_entropicAdsorptAdsorbateState and require_h_ads_Formal) or + (require_h_ads_Formal) or + (require_cp_ChakrabortyElAl) or + (require_cp_ChakrabortyElAl_CC) or + (require_cp_WaltonLeVan) or + (require_cp_SchwambergerSchmidt)) or + (require_h_ads_Dubinin) or + (require_caloricAdsorptAdsorbateState and require_h_ads_Dubinin) or + (require_entropicAdsorptAdsorbateState and require_h_ads_Dubinin) or + (require_cp_ChakrabortyElAl_Dubinin) or + (require_cp_WaltonLeVan_Dubinin) or + (require_cp_SchwambergerSchmidt_Dubinin) + "= true, if specific volume of last adsorbed molecule is required"; + parameter Boolean require_dv_dp_T= + not neglectSpecifcVolume and + ((require_dxv_avg_dp_T) or + (require_cp_ChakrabortyElAl) or + (require_cp_WaltonLeVan) or + (require_cp_SchwambergerSchmidt)) or + (require_cp_ChakrabortyElAl_Dubinin) or + (require_cp_WaltonLeVan_Dubinin) or + (require_cp_SchwambergerSchmidt_Dubinin) + "= true, if the partial derivative of the specific volume of the last adsorbed + molecule w.r.t. pressure at constant temperature is required"; + parameter Boolean require_dv_dT_p= + (require_dv_dp_T) or + not neglectSpecifcVolume and + ((require_dxv_avg_dT_p) or + (require_cp_ChakrabortyElAl) or + (require_cp_ChakrabortyElAl_CC) or + (require_cp_WaltonLeVan) or + (require_cp_SchwambergerSchmidt)) or + (require_h_ads_Dubinin) or + (require_cp_ChakrabortyElAl_Dubinin) or + (require_cp_WaltonLeVan_Dubinin) or + (require_cp_SchwambergerSchmidt_Dubinin) + "= true, if the partial derivative of the specific volume of the last adsorbed + molecule w.r.t. temperature at pressure temperature is required"; + parameter Boolean require_ddv_dT_dT_p= + (require_dbeta_dT_p) + "= true, if the second-order partial derivative of the specific volume of the + last adsorbed molecule w.r.t. temperature at pressure temperature is required"; + + parameter Boolean require_cp= + calcCaloricProperties + "= true, if specific heat capacity of the last adsorbed molecule or uptake- + averaged adsorpt is required"; + + parameter Boolean require_beta= + (require_caloricAdsorptAdsorbateState and require_h_ads_Dubinin) or + (require_entropicAdsorptAdsorbateState and require_h_ads_Dubinin) or + (require_h_ads_Dubinin) or + (require_cp_ChakrabortyElAl_Dubinin) or + (require_cp_WaltonLeVan_Dubinin) or + (require_cp_SchwambergerSchmidt_Dubinin) + "= true, if isobaric expansion coefficient of the last adsorbed molecule is + required"; + parameter Boolean require_dbeta_dp_T= + (require_cp_ChakrabortyElAl_Dubinin) or + (require_cp_WaltonLeVan_Dubinin) or + (require_cp_SchwambergerSchmidt_Dubinin) + "= true, if the partial derivative of the isobaric expansion coefficient of + the last adsorbed molecule w.r.t. pressure at constant temperature is + required"; + parameter Boolean require_dbeta_dT_p= + (require_dbeta_dp_T) + "= true, if the partial derivative of the isobaric expansion coefficient of + the last adsorbed molecule w.r.t. temperature at pressure temperature is + required"; + + parameter Boolean require_h_ads= + (calcCaloricProperties) or + (require_entropyBalance) or + (require_cp_ChakrabortyElAl) or + (require_cp_ChakrabortyElAl_CC) or + (require_cp_ChakrabortyElAl_Dubinin) + "= true, if the specific enthalpy of adsorption of the last adsorbed molecule + is required"; + parameter Boolean require_dh_ads_dp_T= + (require_cp_ChakrabortyElAl) or + (require_cp_ChakrabortyElAl_CC) or + (require_cp_ChakrabortyElAl_Dubinin) + "= true, if the partial derivatieve of the specific enthalpy of adsorption + of the last adsorbed molecule w.r.t. pressure and constant temperature is + required"; + parameter Boolean require_dh_ads_dT_p= + (require_dh_ads_dp_T) + "= true, if the partial derivatieve of the specific enthalpy of adsorption + of the last adsorbed molecule w.r.t. temperature and constant pressure is + required"; + + // + // State variables + // + Modelica.Units.SI.Pressure p_avg + "Uptake-averaged pressure of the adsorpt phase"; + Modelica.Units.SI.Temperature T_avg + "Uptake-averaged temperature of the adsorpt phase"; + Modelica.Units.SI.SpecificVolume v_avg + "Uptake-averaged specific volume of the adsorpt phase"; + Modelica.Units.SI.SpecificEnthalpy h_avg + "Uptake-averaged specific enthalpy of the adsorpt phase"; + Modelica.Units.SI.SpecificInternalEnergy u_avg + "Uptake-averaged specific internal energy of the adsorpt phase"; + Modelica.Units.SI.SpecificEntropy s_avg + "Uptake-averaged specific entropy of the adsorpt phase"; + Modelica.Units.SI.SpecificGibbsFreeEnergy g_avg + "Uptake-averaged specific free enthalpy (i.e., Gibbs free energy) of the + adsorpt phase"; + Modelica.Units.SI.SpecificHelmholtzFreeEnergy a_avg + "Uptake-averaged specific free energy (i.e., Helmholts free energy) of the + adsorpt phase"; + + Modelica.Units.SI.SpecificVolume v + "Specific volume of last adsorbed molecule"; + + // + // Additional properties + // + Modelica.Units.SI.SpecificEnthalpy h_ads + "Specific enthalpy of adsorption of last adsorbed molecule"; + + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity of last adsorbed molecule or the uptake-averaged + adsorpt, depending on selected approach)"; + Modelica.Units.SI.RelativePressureCoefficient beta + "Isobaric expansion coefficient of last adsorbed molecule"; + + // + // Partial derivatives + // + SorpLib.Units.DerUptakeSpecificVolumeByPressure dxv_avg_dp_T + "Partial derivative of the uptake-averaged specific volume times the uptake + w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeSpecificVolumeByTemperature dxv_avg_dT_p + "Partial derivative of the uptake-averaged specific volume times the uptake + w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerUptakeSpecificEnthalpyByPressure dxh_avg_dp_T + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeSpecificEnthalpyByTemperature dxh_avg_dT_p + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. temperature at constant pressure"; + SorpLib.Units.DerUptakeSpecificEnthalpyByUptake dxh_avg_dx_T + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. uptake at constant temperature"; + SorpLib.Units.DerUptakeSpecificEnthalpyByTemperature dxh_avg_dT_x + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. temperature at constant uptake"; + + SorpLib.Units.DerUptakeSpecificEntropyByPressure dxs_avg_dp_T + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeSpecificEntropyByTemperature dxs_avg_dT_p + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. temperature at constant pressure"; + SorpLib.Units.DerUptakeSpecificEntropyByUptake dxs_avg_dx_T + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. uptake at constant temperature"; + SorpLib.Units.DerUptakeSpecificEntropyByTemperature dxs_avg_dT_x + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. temperature at constant uptake"; + + SorpLib.Units.DerSpecificVolumeByPressure dv_dp_T + "Partial derivative of the specific volume of the last adsorbed molecule + w.r.t. pressure at constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_dT_p + "Partial derivative of the specific volume of the last adsorbed molecule + w.r.t. temperature at constant pressure"; + SorpLib.Units.DerSpecificVolumeByTemperatureTemperature ddv_dT_dT_p + "Second-order partial derivative of specific volume of the last adsorbed + molecule w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerSpecificEnthalpyByPressure dh_ads_dp_T + "Partial derivative of the specific enthalpy of adsorption w.r.t. pressure + at constant temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_ads_dT_p + "Partial derivative of the specific enthalpy of adsorption w.r.t. temperature + at constant pressure"; + + SorpLib.Units.DerIsobaricExpansionCoefficientByPressure dbeta_dp_T + "Partial derivative of isobaric expansion coefficient of the adsorpt phase + w.r.t. pressure at constant temperature"; + SorpLib.Units.DerIsobaricExpansionCoefficientByTemperature dbeta_dT_p + "Partial derivative of isobaric expansion coefficient of the adsorpt phase + w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerUptakeByPressure dx_dp_T + "Partial derivative of the uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_dT_p + "Partial derivative of the uptake w.r.t. temperature at constant pressure"; + SorpLib.Units.DerPressureByUptake dp_dx_T + "Partial derivative of the uptake w.r.t. uptake at constant temperature"; + Modelica.Units.SI.DerPressureByTemperature dp_dT_x + "Partial derivative of the uptake w.r.t. temperature at constant uptake"; + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at constant + temperature"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at constant + pressure"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + +equation + // + // Partial derivatives of the isotherm model + // + dx_dp_T =if not require_derivativesIsotherm_pT then 0 else + IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of the uptake w.r.t. pressure at constant temperature"; + dx_dT_p =if not require_derivativesIsotherm_pT then 0 else + IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of the uptake w.r.t. temperature at constant pressure"; + + dp_dx_T =if not require_derivativesIsotherm_xT then 0 else 1/dx_dp_T + "Partial derivative of the uptake w.r.t. uptake at constant temperature"; + dp_dT_x =if not require_derivativesIsotherm_xT then 0 else -dx_dT_p/dx_dp_T + "Partial derivative of the uptake w.r.t. temperature at constant uptake"; + + ddx_adsorpt_dp_dp =if not require_ddx_dp_dp_T then 0 else + IsothermModel.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant + temperature"; + ddx_adsorpt_dT_dT =if not require_ddx_dT_dT_p then 0 else + IsothermModel.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. temperature at constant + pressure"; + ddx_adsorpt_dp_dT =if not require_ddx_dp_dT then 0 else + IsothermModel.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Uptake-averaged state properties of the adsorpt + // + p_avg = if not require_caloricAdsorptAdsorbateState then 0 else + p_adsorpt + "Uptake-averaged pressure of the adsorpt phase"; + T_avg = if not require_caloricAdsorptAdsorbateState then 0 else + T_adsorpt + "Uptake-averaged temperature of the adsorpt phase"; + v_avg = if not require_caloricAdsorptAdsorbateState or + neglectSpecifcVolume then 0 else v + "Uptake-averaged specific volume of the adsorpt phase: Corresponds to specific + volume of the last adsorbed molecule as specific volume is constant or only a + function of temperature for all implemented approaches"; + + if not require_caloricAdsorptAdsorbateState then + h_avg = 0 + "Uptake-averaged specific enthalpy of the adsorpt phase"; + + else + if approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Constant then + h_avg = 1 / ((x_adsorpt-min(x_adsorpt_lb,0.5*x_adsorpt))) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_h_avg_adsorpt_Constant( + T_adsorpt=T_adsorpt, + c=c, + h_ads = h_ads_constant, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=min(x_adsorpt_lb,0.5*x_adsorpt), + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_h) + "Uptake-averaged specific enthalpy of the adsorpt phase"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Formal then + h_avg = 1 / ((x_adsorpt-min(x_adsorpt_lb,0.5*x_adsorpt))) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_h_avg_adsorpt_Formal( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + v_adsorpt=if neglectSpecifcVolume then 0 else v, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=min(x_adsorpt_lb,0.5*x_adsorpt), + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_h) + "Uptake-averaged specific enthalpy of the adsorpt phase"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron then + h_avg = 1 / ((x_adsorpt-min(x_adsorpt_lb,0.5*x_adsorpt))) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_h_avg_adsorpt_CC( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=min(x_adsorpt_lb,0.5*x_adsorpt), + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_h) + "Uptake-averaged specific enthalpy of the adsorpt phase"; + + else + h_avg = 1 / ((x_adsorpt-min(x_adsorpt_lb,0.5*x_adsorpt))) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_h_avg_adsorpt_Dubinin( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + v_adsorpt=v, + beta_adsorpt=beta, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=min(x_adsorpt_lb,0.5*x_adsorpt), + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_h) + "Uptake-averaged specific enthalpy of the adsorpt phase"; + + end if; + end if; + + u_avg = if not require_caloricAdsorptAdsorbateState then 0 else + h_avg - p_avg * v_avg + "Uptake-averaged specific internal energy of the adsorpt phase"; + + + if not require_entropicAdsorptAdsorbateState then + s_avg = 0 + "Uptake-averaged specific enthalpy of the adsorpt phase"; + + else + if approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Constant then + s_avg = 1 / ((x_adsorpt-x_adsorpt_lb)) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_s_avg_adsorpt_Constant( + T_adsorpt=T_adsorpt, + c=c, + h_ads = h_ads_constant, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_h) + "Uptake-averaged specific entropy of the adsorpt phase"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Formal then + s_avg = 1 / ((x_adsorpt-x_adsorpt_lb)) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_s_avg_adsorpt_Formal( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + v_adsorpt=if neglectSpecifcVolume then 0 else v, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_h) + "Uptake-averaged specific entropy of the adsorpt phase"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron then + s_avg = 1 / ((x_adsorpt-x_adsorpt_lb)) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_s_avg_adsorpt_CC( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_h) + "Uptake-averaged specific entropy of the adsorpt phase"; + + else + s_avg = 1 / ((x_adsorpt-x_adsorpt_lb)) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_s_avg_adsorpt_Dubinin( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + v_adsorpt=v, + beta_adsorpt=beta, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_h) + "Uptake-averaged specific entropy of the adsorpt phase"; + + end if; + end if; + + g_avg = if not require_entropicAdsorptAdsorbateState then 0 else + h_avg - T_avg * s_avg + "Uptake-averaged specific free enthalpy (i.e., Gibbs free energy) of the + adsorpt phase"; + a_avg = if not require_entropicAdsorptAdsorbateState then 0 else + u_avg - T_avg * s_avg + "Uptake-averaged specific free energy (i.e., Helmholts free energy) of the + adsorpt phase"; + + // + // Specific volume of the last adsorbed molecule and its partial derivatives + // + if not require_v then + v =0 + "Specific volume of the last adsorbed molecule"; + + else + if approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.Constant then + v = v_adsorpt_constant + "Specific volume of the last adsorbed molecule"; + + elseif approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve then + v = properties_adsorptive.v_satLiq + "Specific volume of the last adsorbed molecule"; + + elseif approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction then + v = SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T_adsorpt, + T_ref=T_ref_v_adsorpt, + z_ref=v_adsorpt_ref, + coefficients=coefficients_v_adsorpt, + exponents=exponents_v_adsorpt, + approach=v_adsorpt_function) + "Specific volume of the last adsorbed molecule"; + + else + if v_adsorpt_interpolation == + SorpLib.Choices.InterpolationApproach.Linear then + v = SorpLib.Media.Functions.Utilities.linearInterpolation_T( + T=T_adsorpt, + abscissa=abscissa_v_adsorpt, + ordinate=ordinate_v_adsorpt) + "Specific volume of the last adsorbed molecule"; + + else + v = SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T( + T=T_adsorpt, + abscissa=abscissa_v_adsorpt, + ordinate=ordinate_v_adsorpt, + coefficients=coefficients_cubicSplines_v_adsorpt) + "Specific volume of the last adsorbed molecule"; + + end if; + end if; + end if; + + dv_dp_T =if not require_dv_dp_T then 0 else 0 + "Partial derivative of the specific volume of the last adsorbed molecule + w.r.t. pressure at constant temperature: Corresponds to unity because v_adsorpt + is not a function of pressure"; + + if not require_dv_dT_p then + dv_dT_p =0 + "Partial derivative of the specific volume of the last adsorbed molecule + w.r.t. temperature at constant pressure"; + + else + if approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.Constant then + dv_dT_p = 0 + "Partial derivative of the specific volume of the last adsorbed molecule + w.r.t. temperature at constant pressure"; + + elseif approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve then + dv_dT_p = properties_adsorptive.dv_satLiq_dT + "Partial derivative of the specific volume of the last adsorbed molecule + w.r.t. temperature at constant pressure"; + + elseif approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction then + dv_dT_p = SorpLib.Media.Functions.Utilities.dgeneralizedFunction_dT( + T=T_adsorpt, + T_ref=T_ref_v_adsorpt, + z_ref=v_adsorpt_ref, + coefficients=coefficients_v_adsorpt, + exponents=exponents_v_adsorpt, + approach=v_adsorpt_function) + "Partial derivative of the specific volume of the last adsorbed molecule + w.r.t. temperature at constant pressure"; + + else + if v_adsorpt_interpolation == + SorpLib.Choices.InterpolationApproach.Linear then + dv_dT_p = SorpLib.Media.Functions.Utilities.dlinearInterpolation_dT( + T=T_adsorpt, + abscissa=abscissa_v_adsorpt, + ordinate=ordinate_v_adsorpt) + "Partial derivative of the specific volume of the last adsorbed molecule + w.r.t. temperature at constant pressure"; + + else + dv_dT_p = SorpLib.Media.Functions.Utilities.dcubicSplineInterpolation_dT( + T=T_adsorpt, + abscissa=abscissa_v_adsorpt, + ordinate=ordinate_v_adsorpt, + coefficients=coefficients_cubicSplines_v_adsorpt) + "Partial derivative of the specific volume of the last adsorbed molecule + w.r.t. temperature at constant pressure"; + + end if; + end if; + end if; + + if not require_ddv_dT_dT_p then + ddv_dT_dT_p =0 + "Second-order partial derivative of the specific volume of the last adsorbed + molecule w.r.t. temperature at constant pressure"; + + else + if approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.Constant then + ddv_dT_dT_p = 0 + "Second-order partial derivative of the specific volume of the last + adsorbed molecule w.r.t. temperature at constant pressure"; + + elseif approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve then + ddv_dT_dT_p = properties_adsorptive.ddv_satLiq_dT_dT + "Second-order partial derivative of the specific volume of the last + adsorbed molecule w.r.t. temperature at constant pressure"; + + elseif approachSpecificVolume == + SorpLib.Choices.SpecificVolumeAdsorpt.GeneralizedFunction then + ddv_dT_dT_p = + SorpLib.Media.Functions.Utilities.ddgeneralizedFunction_dT_dT( + T=T_adsorpt, + T_ref=T_ref_v_adsorpt, + z_ref=v_adsorpt_ref, + coefficients=coefficients_v_adsorpt, + exponents=exponents_v_adsorpt, + approach=v_adsorpt_function) + "Second-order partial derivative of the specific volume of the last + adsorbed molecule w.r.t. temperature at constant pressure"; + + else + if v_adsorpt_interpolation == + SorpLib.Choices.InterpolationApproach.Linear then + ddv_dT_dT_p = + SorpLib.Media.Functions.Utilities.ddlinearInterpolation_dT_dT( + T=T_adsorpt, + abscissa=abscissa_v_adsorpt, + ordinate=ordinate_v_adsorpt) + "Second-order partial derivative of the specific volume of the last + adsorbed molecule w.r.t. temperature at constant pressure"; + + else + ddv_dT_dT_p = + SorpLib.Media.Functions.Utilities.ddcubicSplineInterpolation_dT_dT( + T=T_adsorpt, + abscissa=abscissa_v_adsorpt, + ordinate=ordinate_v_adsorpt, + coefficients=coefficients_cubicSplines_v_adsorpt) + "Second-order partial derivative of the specific volume of the last + adsorbed molecule w.r.t. temperature at constant pressure"; + + end if; + end if; + end if; + + // + // Isobaric expansion coefficient of the last adsorbed molecule + // + beta =if not require_beta or not require_v then 0 + else 1/v*dv_dT_p + "Isobaric expansion coefficient of the last adsorbed molecule"; + + dbeta_dp_T =if not require_dbeta_dp_T or not require_v + then 0 else 0 + "Partial derivative of isobaric expansion coefficient of the last adsorbed + molecule w.r.t. pressure at constant temperature: Corresponds to unity as + v_adsorpt is not a function of pressure"; + dbeta_dT_p =if not require_dbeta_dT_p or not require_v + then 0 else -(1/v*dv_dT_p)^2 + 1/v*ddv_dT_dT_p + "Partial derivative of isobaric expansion coefficient of the last adsorbed + molecule w.r.t. temperature at constant pressure"; + + // + // Specific enthalpy of adsorption of the last adsorbed molecule and its + // partial derivatives + // + if not require_h_ads then + h_ads =0 + "Specific enthalpy of adsorption of the last adsorbed molecule"; + + else + if approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Constant then + h_ads = h_ads_constant + "Specific enthalpy of adsorption of the last adsorbed molecule"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Formal then + h_ads = SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorpt, + T_adsorpt=T_adsorpt, + v_adsorptive=properties_adsorptive.state.v, + v_adsorpt=if neglectSpecifcVolume then 0 else v, + dx_adsorpt_dp=dx_dp_T, + dx_adsorpt_dT=dx_dT_p) / M_adsorpt + "Specific enthalpy of adsorption of the last adsorbed molecule"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron then + h_ads = + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_dp_T, + dx_adsorpt_dT=dx_dT_p) / M_adsorpt + "Specific enthalpy of adsorption of the last adsorbed molecule"; + + else + h_ads = calc_h_ads_Dubinin( + c=c, + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + v_adsorpt=v, + beta_adsorpt=beta, + properties_adsorptive=properties_adsorptive) + "Specific enthalpy of adsorption of the last adsorbed molecule"; + + end if; + end if; + + if not require_dh_ads_dp_T then + dh_ads_dp_T = 0 + "Partial derivative of the specific enthalpy of adsorption of the last + adsorbed molecule w.r.t. pressure at constant temperature"; + + else + if approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Constant then + dh_ads_dp_T = 0 + "Partial derivative of the specific enthalpy of adsorption of the last + adsorbed molecule w.r.t. pressure at constant temperature"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Formal then + dh_ads_dp_T = + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp( + M_adsorptive=M_adsorpt, + T_adsorpt=T_adsorpt, + v_adsorptive=properties_adsorptive.state.v, + v_adsorpt=if neglectSpecifcVolume then 0 else v, + dv_adsorptive_dp=properties_adsorptive.dv_dp_T, + dv_adsorpt_dp=if neglectSpecifcVolume then 0 else dv_dp_T, + dx_adsorpt_dp=dx_dp_T, + dx_adsorpt_dT=dx_dT_p, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) / M_adsorpt + "Partial derivative of the specific enthalpy of adsorption of the last + adsorbed molecule w.r.t. pressure at constant temperature"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron then + dh_ads_dp_T = + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_dp_T, + dx_adsorpt_dT=dx_dT_p, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) / M_adsorpt + "Partial derivative of the specific enthalpy of adsorption of the last + adsorbed molecule w.r.t. pressure at constant temperature"; + + else + dh_ads_dp_T = calc_dh_ads_dp_T_Dubinin( + c=c, + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + dx_adsorpt_dp=dx_dp_T, + v_adsorpt=v, + dv_adsorpt_dp=dv_dp_T, + beta_adsorpt=beta, + dbeta_adsorpt_dp=dbeta_dp_T, + properties_adsorptive=properties_adsorptive) + "Partial derivative of the specific enthalpy of adsorption of the last + adsorbed molecule w.r.t. pressure at constant temperature"; + + end if; + end if; + + if not require_dh_ads_dT_p then + dh_ads_dT_p = 0 + "Partial derivative of the specific enthalpy of adsorption of the last + adsorbed molecule w.r.t. temperature at constant pressure"; + + else + if approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Constant then + dh_ads_dT_p = 0 + "Partial derivative of the specific enthalpy of adsorption of the last + adsorbed molecule w.r.t. temperature at constant pressure"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Formal then + dh_ads_dT_p = + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT( + M_adsorptive=M_adsorpt, + T_adsorpt=T_adsorpt, + v_adsorptive=properties_adsorptive.state.v, + v_adsorpt=if neglectSpecifcVolume then 0 else v, + dv_adsorptive_dT=properties_adsorptive.dv_dT_p, + dv_adsorpt_dT=if neglectSpecifcVolume then 0 else dv_dT_p, + dx_adsorpt_dp=dx_dp_T, + dx_adsorpt_dT=dx_dT_p, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) / M_adsorpt + "Partial derivative of the specific enthalpy of adsorption of the last + adsorbed molecule w.r.t. temperature at constant pressure"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron then + dh_ads_dT_p = + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_dp_T, + dx_adsorpt_dT=dx_dT_p, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) / M_adsorpt + "Partial derivative of the specific enthalpy of adsorption of the last + adsorbed molecule w.r.t. temperature at constant pressure"; + + else + dh_ads_dT_p = calc_dh_ads_dT_p_Dubinin( + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + dx_adsorpt_dT=dx_dT_p, + v_adsorpt=v, + dv_adsorpt_dT=dv_dT_p, + beta_adsorpt=beta, + dbeta_adsorpt_dT=dbeta_dT_p, + properties_adsorptive=properties_adsorptive) + "Partial derivative of the specific enthalpy of adsorption of the last + adsorbed molecule w.r.t. temperature at constant pressure"; + + end if; + end if; + + // + // Specific heat capacity of the last adsorbed molecule or uptake-averaged + // adsorpt + // + if not require_cp then + cp = 0 + "Specific heat capacity: Corresponds to last adsorbed molecule but is + independent of uptake"; + else + if approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.Constant then + cp = cp_adsorpt_constant + "Specific heat capacity: Corresponds to last adsorbed molecule but is + independent of uptake"; + + elseif approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.BoilingCurve then + cp = properties_adsorptive.cp_satLiq + "Specific heat capacity: Corresponds to last adsorbed molecule but is + independent of uptake"; + + elseif approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.GeneralizedFunction then + cp = SorpLib.Media.Functions.Utilities.generalizedFunction_T( + T=T_adsorpt, + T_ref=T_ref_cp_adsorpt, + z_ref=cp_adsorpt_ref, + coefficients=coefficients_cp_adsorpt, + exponents=exponents_cp_adsorpt, + approach=cp_adsorpt_function) + "Specific heat capacity: Corresponds to last adsorbed molecule but is + independent of uptake"; + + elseif approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.Interpolation then + if cp_adsorpt_interpolation == + SorpLib.Choices.InterpolationApproach.Linear then + cp = SorpLib.Media.Functions.Utilities.linearInterpolation_T( + T=T_adsorpt, + abscissa=abscissa_cp_adsorpt, + ordinate=ordinate_cp_adsorpt) + "Specific heat capacity: Corresponds to last adsorbed molecule but is + independent of uptake"; + + else + cp = SorpLib.Media.Functions.Utilities.cubicSplineInterpolation_T( + T=T_adsorpt, + abscissa=abscissa_cp_adsorpt, + ordinate=ordinate_cp_adsorpt, + coefficients=coefficients_cubicSplines_cp_adsorpt) + "Specific heat capacity: Corresponds to last adsorbed molecule but is + independent of uptake"; + + end if; + + elseif approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.WaltonLeVan then + if approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Constant then + cp = properties_adsorptive.cp + "Specific heat capacity: Corresponds to last adsorbed molecule but is + dependent of uptake"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Formal then + cp = properties_adsorptive.cp - + 1 / ((x_adsorpt-x_adsorpt_lb) * M_adsorpt) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_WaltonLeVan( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + v_adsorpt=if neglectSpecifcVolume then 0 else v, + dv_adsorpt_dp=if neglectSpecifcVolume then 0 else dv_dp_T, + dv_adsorpt_dT=if neglectSpecifcVolume then 0 else dv_dT_p, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_cp) + "Specific heat capacity: Corresponds to last adsorbed molecule but is + dependent of uptake"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron then + cp = properties_adsorptive.cp - + 1 / ((x_adsorpt-x_adsorpt_lb) * M_adsorpt) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_WaltonLeVan_CC( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_cp) + "Specific heat capacity: Corresponds to last adsorbed molecule but is + dependent of uptake"; + + else + cp = properties_adsorptive.cp - + 1 / ((x_adsorpt-x_adsorpt_lb) * M_adsorpt) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_WaltonLeVan_Dubinin( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + v_adsorpt=v, + dv_adsorpt_dp=dv_dp_T, + dv_adsorpt_dT=dv_dT_p, + beta_adsorpt=beta, + dbeta_adsorpt_dp=dbeta_dp_T, + dbeta_adsorpt_dT=dbeta_dT_p, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_cp) + "Specific heat capacity: Corresponds to last adsorbed molecule but is + dependent of uptake"; + + end if; + + elseif approachSpecificHeatCapacity == + SorpLib.Choices.SpecificHeatCapacityAdsorpt.ChakrabortyElAl then + cp = + SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.cp_ChakrabortyEtAl( + M_adsorptive=M_adsorpt, + T_adsorpt=T_adsorpt, + cp_adsorptive=properties_adsorptive.cp, + v_adsorptive=properties_adsorptive.state.v, + dv_adsorptive_dT=properties_adsorptive.dv_dT_p, + v_adsorpt=if neglectSpecifcVolume then 0 else v, + h_ads=h_ads*M_adsorpt, + dh_ads_dT_x=M_adsorpt * (dh_ads_dT_p + dh_ads_dp_T * dp_dT_x)) + "Specific heat capacity: Corresponds to last adsorbed molecule but is + dependent of uptake"; + + else + if approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Constant then + cp = 1 / ((x_adsorpt-x_adsorpt_lb)) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_SchwambergerSchmidt_Constant( + T_adsorpt=T_adsorpt, + c=c, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_cp) + "Specific heat capacity: Corresponds to uptake-averaged adsorpt"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.Formal then + cp = 1 / ((x_adsorpt-x_adsorpt_lb)) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_SchwambergerSchmidt( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + v_adsorpt=if neglectSpecifcVolume then 0 else v, + dv_adsorpt_dp=if neglectSpecifcVolume then 0 else dv_dp_T, + dv_adsorpt_dT=if neglectSpecifcVolume then 0 else dv_dT_p, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_cp) + "Specific heat capacity: Corresponds to uptake-averaged adsorpt"; + + elseif approachSorptionEnthalpy == + SorpLib.Choices.SorptionEnthalpy.ClausiusClapeyron then + cp = 1 / ((x_adsorpt-x_adsorpt_lb)) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_SchwambergerSchmidt_CC( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_cp) + "Specific heat capacity: Corresponds to uptake-averaged adsorpt"; + + else + cp = 1 / ((x_adsorpt-x_adsorpt_lb)) * + Modelica.Math.Nonlinear.quadratureLobatto( + f=function calc_integrand_SchwambergerSchmidt_Dubinin( + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt, + adsorptiveAtDewPoint=adsorptiveAtDewPoint, + v_adsorpt=v, + dv_adsorpt_dp=dv_dp_T, + dv_adsorpt_dT=dv_dT_p, + beta_adsorpt=beta, + dbeta_adsorpt_dp=dbeta_dp_T, + dbeta_adsorpt_dT=dbeta_dT_p, + p_clausiusClyperon=p_adsorpt_min, + dp=dp, + dT=dT), + a=x_adsorpt_lb, + b=x_adsorpt, + tolerance=tolerance_adsorpt_int_cp) + "Specific heat capacity: Corresponds to uptake-averaged adsorpt"; + + end if; + + end if; + end if; + + // + // Partial derivatives required for mass, energy, and entropy balances + // + dxv_avg_dp_T = if not require_dxv_avg_dp_T or neglectSpecifcVolume then 0 + else x_adsorpt * dv_dp_T + dx_dp_T * v + "Partial derivative of the uptake-averaged specific volume times the uptake + w.r.t. pressure at constant temperature: Note that v_avg = v, as specific + volume is just a function of temperature"; + dxv_avg_dT_p = if not require_dxv_avg_dT_p or neglectSpecifcVolume then 0 + else x_adsorpt * dv_dT_p + dx_dT_p * v + "Partial derivative of the uptake-averaged specific volume times the uptake + w.r.t. temperature at constant pressure: Note that v_avg = v, as specific + volume is just a function of temperature"; + + dxh_avg_dp_T = if not require_dxh_avg_dp_T then 0 else + dxh_avg_dx_T / dp_dx_T + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. pressure at constant temperature"; + dxh_avg_dT_p = if not require_dxh_avg_dT_p then 0 else + dxh_avg_dT_x - dxh_avg_dp_T * dp_dT_x + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. temperature at constant pressure"; + dxh_avg_dx_T = if not require_dxh_avg_dx_T then 0 else + (properties_adsorptive.state.h - h_ads) + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. uptake at constant temperature"; + dxh_avg_dT_x = if not require_dxh_avg_dT_x then 0 else + x_adsorpt * cp + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. temperature at constant uptake"; + + dxs_avg_dp_T = if not require_dxs_avg_dp_T then 0 else + dxs_avg_dx_T / dp_dx_T + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. pressure at constant temperature"; + dxs_avg_dT_p = if not require_dxs_avg_dT_p then 0 else + dxs_avg_dT_x - dxs_avg_dp_T * dp_dT_x + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. temperature at constant pressure"; + dxs_avg_dx_T = if not require_dxs_avg_dx_T then 0 else + (properties_adsorptive.state.s - h_ads / T_adsorpt) + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. uptake at constant temperature"; + dxs_avg_dT_x = if not require_dxs_avg_dT_x then 0 else + x_adsorpt * cp / T_adsorpt + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. temperature at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates all properties of the adsorpt required for the working +pair model at once. Thus, computational costs are reduced because redundant +calculations of the same properties are avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end AdsorptProperties; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/IsothermCoefficients.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/IsothermCoefficients.mo new file mode 100644 index 0000000000000000000000000000000000000000..67e25b937d76e292df2403d66861fde7158f8041 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/IsothermCoefficients.mo @@ -0,0 +1,52 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +model IsothermCoefficients + "Calculates the temperature-dependent coefficients of the isotherm model" + extends Modelica.Icons.MaterialProperty; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference if derivatives are calculated numerically" + annotation (Dialog(tab="General",group="Inputs"), + HideResult=true); + + // + // Definition of outputs + // + output Real[no_coefficients] c + "Isotherm coefficients" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + output Real[no_coefficients] dc_dT + "Partial derivative of isotherm coefficients w.r.t. temperature" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + output Real[no_coefficients] ddc_dT_dT + "Second-order partial derivative of isotherm coefficients w.r.t. temperature" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + +equation + (c, dc_dT, ddc_dT_dT) = calc_coefficients(T_adsorpt=T_adsorpt, dT=dT) + "Isotherm coefficients and their partial derivatives w.r.t. temperature"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates temperature-dependent isotherm coefficients <i>c</i> and +their partial derivatives with respect to temperature <i>dc_dT</i> (first order) +and <i>ddc_dT_dT</i> (second order). +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end IsothermCoefficients; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_SchwambergerSchmidt.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_SchwambergerSchmidt.mo new file mode 100644 index 0000000000000000000000000000000000000000..78920964a8edbb7c49ef636792b6829ee1cdc3f0 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_SchwambergerSchmidt.mo @@ -0,0 +1,272 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_SchwambergerSchmidt + "Calculates the integrand required for calculating the specific heat capacity according to Schwamberger and Schmidt (2013)" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real ddc_dT_adsorpt_dT_adsorpt[:] + "Second-order partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding the specific volume of the adsorpt + // + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of the specific volume of the adsorpt w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of the specific volume of the adsorpt w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificVolume v_adsorptive + "Specific volume of the adsorptive"; + SorpLib.Units.DerSpecificVolumeByPressure dv_adsorptive_dp + "Partial derivative of specific volume of the adsorptive w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorptive_dT + "Partial derivative of specific volume of the adsorptive w.r.t. temperature at + constant pressure"; + + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptive_dT + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at contant + temperature"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at contant + pressure"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp := IsothermModel.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT := IsothermModel.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT := IsothermModel.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use-Clausius Clyperon assumptions + // + (v_adsorptive, dv_adsorptive_dp, dv_adsorptive_dT,,,dh_adsorptive_dT,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=true, + require_h_adsorptive=false, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=true, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific volume of the adsorptive and its partial derivatives as well as + the partial derivative of the specific enthalpy of the adsorptive w.r.t. + temperature at constant pressure"; + + // + // Calculation of partial derivatives of molar sorption enthalpy + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=v_adsorptive, + v_adsorpt=v_adsorpt, + dv_adsorptive_dp=dv_adsorptive_dp, + dv_adsorpt_dp=dv_adsorpt_dp, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=v_adsorptive, + v_adsorpt=v_adsorpt, + dv_adsorptive_dT=dv_adsorptive_dT, + dv_adsorpt_dT=dv_adsorpt_dT, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + else + // + // Use Clausius-Clyperon assumptions + // + (,,,,, dh_adsorptive_dT,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=true, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. + temperature at constant pressure"; + + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + end if; + + // + // Calculation of the integrand + // + y := dh_adsorptive_dT - + (dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp) / M_adsorptive + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy of the +adsorpt with respect to temperature at constant uptake. For more information, +check the model +<a href=\"Modelica://SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_adsorpt_dT_x\">SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_adsorpt_dT_x</a>. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_SchwambergerSchmidt; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_SchwambergerSchmidt_CC.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_SchwambergerSchmidt_CC.mo new file mode 100644 index 0000000000000000000000000000000000000000..820c64ee253e4948a45c9f798c63e5cd54fb347c --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_SchwambergerSchmidt_CC.mo @@ -0,0 +1,189 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_SchwambergerSchmidt_CC + "Calculates the integrand required for calculating the specific heat capacity according to Schwamberger and Schmidt (2013) when using the specifc enthalpy of adsorption according to Clausius Clayperon" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real ddc_dT_adsorpt_dT_adsorpt[:] + "Second-order partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptive_dT + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at contant + temperature"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at contant + pressure"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp := IsothermModel.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT := IsothermModel.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT := IsothermModel.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Calculation of partial derivatives + // + (,,,,, dh_adsorptive_dT,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=true, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. + temperature at constant pressure"; + + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + // + // Calculation of the integrand + // + y := dh_adsorptive_dT - + (dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp) / M_adsorptive + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy of the +adsorpt with respect to temperature at constant uptake when using the molar adsorption +enthalpy according to Clausius Clayperon. For more information, check the model +<a href=\"Modelica://SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_adsorpt_dT_x_CC\">SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_adsorpt_dT_x_CC</a>. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_SchwambergerSchmidt_CC; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_SchwambergerSchmidt_Constant.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_SchwambergerSchmidt_Constant.mo new file mode 100644 index 0000000000000000000000000000000000000000..ef1dc06e9d37a514aee5f1fef061e49e13e61d84 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_SchwambergerSchmidt_Constant.mo @@ -0,0 +1,106 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_SchwambergerSchmidt_Constant + "Calculates the integrand required for calculating the specific heat capacity according to Schwamberger and Schmidt (2013) when having a constant specific enthaloy of adsorption" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptive_dT + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + // + // Calculation of further properties + // + (,,,,, dh_adsorptive_dT,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=true, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. + temperature at constant pressure"; + + // + // Calculation of the integrand + // + y := dh_adsorptive_dT + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy of the +adsorpt with respect to temperature at constant uptake when using a constant +specific enthalpy of adsorption. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_SchwambergerSchmidt_Constant; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_WaltonLeVan.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_WaltonLeVan.mo new file mode 100644 index 0000000000000000000000000000000000000000..0b4aaf7cffc361b2b7d7960b803d52feef4f8310 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_WaltonLeVan.mo @@ -0,0 +1,248 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_WaltonLeVan + "Calculates the integrand required for calculating the specific heat capacity according to Walton and Le Van (2005)" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real ddc_dT_adsorpt_dT_adsorpt[:] + "Second-order partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding the specific volume of the adsorpt + // + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of the specific volume of the adsorpt w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of the specific volume of the adsorpt w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificVolume v_adsorptive + "Specific volume of the adsorptive"; + SorpLib.Units.DerSpecificVolumeByPressure dv_adsorptive_dp + "Partial derivative of specific volume of the adsorptive w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorptive_dT + "Partial derivative of specific volume of the adsorptive w.r.t. temperature at + constant pressure"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at contant + temperature"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at contant + pressure"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp := IsothermModel.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT := IsothermModel.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT := IsothermModel.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius Clyperon assumptions + // + (v_adsorptive, dv_adsorptive_dp, dv_adsorptive_dT,,,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=true, + require_h_adsorptive=false, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific volume of the adsorptive and its partial derivatives"; + + // + // Calculation of partial derivatives of molar sorption enthalpy + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=v_adsorptive, + v_adsorpt=v_adsorpt, + dv_adsorptive_dp=dv_adsorptive_dp, + dv_adsorpt_dp=dv_adsorpt_dp, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=v_adsorptive, + v_adsorpt=v_adsorpt, + dv_adsorptive_dT=dv_adsorptive_dT, + dv_adsorpt_dT=dv_adsorpt_dT, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + else + // + // Use Clausius-Clyperon assumptions: No further propiertes are required + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + end if; + + // + // Calculation of the integrand + // + y := dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the molar adsorption enthalpy +with respect to temperature at constant uptake. For more information, check the model +<a href=\"Modelica://SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_ads_dT_x\">SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_ads_dT_x</a>. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_WaltonLeVan; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_WaltonLeVan_CC.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_WaltonLeVan_CC.mo new file mode 100644 index 0000000000000000000000000000000000000000..cd85f59002904f8a1320ab7c4d8984780e2994e1 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_WaltonLeVan_CC.mo @@ -0,0 +1,147 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_WaltonLeVan_CC + "Calculates the integrand required for calculating the specific heat capacity according to Walton and Le Van (2005) when using the specifc enthalpy of adsorption according to Clausius Clayperon" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real ddc_dT_adsorpt_dT_adsorpt[:] + "Second-order partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp + "Second-order partial derivative of uptake w.r.t. pressure at contant + temperature"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT + "Second-order partial derivative of uptake w.r.t. temperature at contant + pressure"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + ddx_adsorpt_dp_dp := IsothermModel.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at constant temperature"; + ddx_adsorpt_dT_dT := IsothermModel.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. temperature at constant pressure"; + ddx_adsorpt_dp_dT := IsothermModel.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + // + // Calculation of partial derivatives + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + // + // Calculation of the integrand + // + y := dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the molar adsorption enthalpy +with respect to temperature at constant uptake when using the molar adsorption +enthalpy according to Clausius Clayperon. For more information, check the model +<a href=\"Modelica://SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_ads_dT_x_CC\">SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_ads_dT_x_CC</a>. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_WaltonLeVan_CC; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_h_avg_adsorpt_CC.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_h_avg_adsorpt_CC.mo new file mode 100644 index 0000000000000000000000000000000000000000..1ceb719f0632c44475c9679243c36f6ce8df4b71 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_h_avg_adsorpt_CC.mo @@ -0,0 +1,135 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_h_avg_adsorpt_CC + "Calculates the integrand required for calculating the uptake-averaged specific enthalpy of adsorpt using the Clausius-Clapeyron definition of the adsorption enthalpy" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptive + "Specific enthalpy of the adsorptive"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + Modelica.Units.SI.MolarEnthalpy h_ads + "Molar adsorption enthalpy"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + // + // Calculation of further properties + // + (,,,h_adsorptive,,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=true, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific enthalpy of the adsorptive"; + + h_ads := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar specific enthalpy of adsorption"; + + // + // Calculation of the integrand + // + y := h_adsorptive - h_ads / M_adsorptive + "Integrand: Specific enthalpy difference between the adsorptive and adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy difference between the adsorptive +and adsorpt using the Clausius-Clyperon definition of the specific enthalpy of +adsorption. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_h_avg_adsorpt_CC; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_h_avg_adsorpt_Constant.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_h_avg_adsorpt_Constant.mo new file mode 100644 index 0000000000000000000000000000000000000000..c6de7647b8463111d129ead85b5ce587cb9a2861 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_h_avg_adsorpt_Constant.mo @@ -0,0 +1,106 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_h_avg_adsorpt_Constant + "Calculates the integrand required for calculating the uptake-averaged specific enthalpy of adsorpt using a constant specific enthalpy of adsorption" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificEnthalpy h_ads + "Constant specific enthalpy of adsorption" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptive + "Specific enthalpy of the adsorptive"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + // + // Calculation of further properties + // + (,,,h_adsorptive,,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=true, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific enthalpy of the adsorptive"; + + // + // Calculation of the integrand + // + y := h_adsorptive - h_ads + "Integrand: Specific enthalpy difference between the adsorptive and adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy difference between the adsorptive +and adsorpt using a constant specific enthalpy of adsorption. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_h_avg_adsorpt_Constant; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_h_avg_adsorpt_Formal.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_h_avg_adsorpt_Formal.mo new file mode 100644 index 0000000000000000000000000000000000000000..2529fe11c6d74a518955ffec6ec11d58e7b422d3 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_h_avg_adsorpt_Formal.mo @@ -0,0 +1,178 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_h_avg_adsorpt_Formal + "Calculates the integrand required for calculating the uptake-averaged specific enthalpy of adsorpt using the formal definition of the adsorption enthalpy" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding the specific volume of the adsorpt + // + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificVolume v_adsorptive + "Specific volume of the adsorptive"; + Modelica.Units.SI.SpecificEnthalpy h_adsorptive + "Specific enthalpy of the adsorptive"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + Modelica.Units.SI.MolarEnthalpy h_ads + "Molar adsorption enthalpy"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius-Clyperon assumptions + // + (v_adsorptive,,,h_adsorptive,,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=true, + require_h_adsorptive=true, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific volume of the adsorptive and specifc enthalpy of the adsorptive"; + + h_ads := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=v_adsorptive, + v_adsorpt=v_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar specific enthalpy of adsorption"; + + else + // + // Use Clausius-Clyperon assumptions + // + (,,,h_adsorptive,,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=true, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific enthalpy of the adsorptive"; + + h_ads := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar specific enthalpy of adsorption"; + + end if; + + // + // Calculation of the integrand + // + y := h_adsorptive - h_ads / M_adsorptive + "Integrand: Specific enthalpy difference between the adsorptive and adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy difference between the adsorptive +and adsorpt using the formal definition of the specific enthalpy of adsorption. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_h_avg_adsorpt_Formal; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_s_avg_adsorpt_CC.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_s_avg_adsorpt_CC.mo new file mode 100644 index 0000000000000000000000000000000000000000..2e539c5c84a5e2140eea84d34db3a89dd5a6c939 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_s_avg_adsorpt_CC.mo @@ -0,0 +1,135 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_s_avg_adsorpt_CC + "Calculates the integrand required for calculating the uptake-averaged specific entropy of adsorpt using the Clausius-Clapeyron definition of the adsorption enthalpy" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificEntropy s_adsorptive + "Specific entropy of the adsorptive"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + Modelica.Units.SI.MolarEnthalpy h_ads + "Molar adsorption enthalpy"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + // + // Calculation of further properties + // + (,,,,s_adsorptive,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=true, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific entropy of the adsorptive"; + + h_ads := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar specific enthalpy of adsorption"; + + // + // Calculation of the integrand + // + y := s_adsorptive - h_ads / M_adsorptive / T_adsorpt + "Integrand: Specific entropy difference between the adsorptive and adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific entropy difference between the adsorptive +and adsorpt using the Clausius-Clyperon definition of the specific enthalpy of +adsorption. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_s_avg_adsorpt_CC; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_s_avg_adsorpt_Constant.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_s_avg_adsorpt_Constant.mo new file mode 100644 index 0000000000000000000000000000000000000000..07feeaf319a0d5503db15e4ed044b2173101ed59 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_s_avg_adsorpt_Constant.mo @@ -0,0 +1,106 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_s_avg_adsorpt_Constant + "Calculates the integrand required for calculating the uptake-averaged specific entropy of adsorpt using a constant specific enthalpy of adsorption" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificEnthalpy h_ads + "Constant specific enthalpy of adsorption" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificEntropy s_adsorptive + "Specific entropy of the adsorptive"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + // + // Calculation of further properties + // + (,,,,s_adsorptive,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=true, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific entropy of the adsorptive"; + + // + // Calculation of the integrand + // + y := s_adsorptive - h_ads / T_adsorpt + "Integrand: Specific entropy difference between the adsorptive and adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific entropy difference between the adsorptive +and adsorpt using a constant specific enthalpy of adsorption. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_s_avg_adsorpt_Constant; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_s_avg_adsorpt_Formal.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_s_avg_adsorpt_Formal.mo new file mode 100644 index 0000000000000000000000000000000000000000..6612d9864f66126a1ca79be97a292d6612e24879 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/calc_integrand_s_avg_adsorpt_Formal.mo @@ -0,0 +1,178 @@ +within SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization; +function calc_integrand_s_avg_adsorpt_Formal + "Calculates the integrand required for calculating the uptake-averaged specific entropy of adsorpt using the formal definition of the adsorption enthalpy" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding the specific volume of the adsorpt + // + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificVolume v_adsorptive + "Specific volume of the adsorptive"; + Modelica.Units.SI.SpecificEntropy s_adsorptive + "Specific entropy of the adsorptive"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + Modelica.Units.SI.MolarEnthalpy h_ads + "Molar adsorption enthalpy"; + +algorithm + // + // Calculation of sorption equilibrium + // + p_adsorpt := IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + dx_adsorpt_dp := IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + dx_adsorpt_dT := IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius-Clyperon assumptions + // + (v_adsorptive,,,,s_adsorptive,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=true, + require_h_adsorptive=false, + require_s_adsorptive=true, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific volume of the adsorptive and specifc entropy of the adsorptive"; + + h_ads := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + v_adsorptive=v_adsorptive, + v_adsorpt=v_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar specific enthalpy of adsorption"; + + else + // + // Use Clausius-Clyperon assumptions + // + (,,,,s_adsorptive,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=true, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific entropy of the adsorptive"; + + h_ads := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar specific enthalpy of adsorption"; + + end if; + + // + // Calculation of the integrand + // + y := s_adsorptive - h_ads / M_adsorptive / T_adsorpt + "Integrand: Specific entropy difference between the adsorptive and adsorpt"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific entropy difference between the adsorptive +and adsorpt using the formal definition of the specific enthalpy of adsorption. +</p> +</html>", + revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end calc_integrand_s_avg_adsorpt_Formal; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/package.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2c489e240857c2ede837af52184eef3c0baa5a62 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/package.mo @@ -0,0 +1,1086 @@ +within SorpLib.Media.WorkingPairs.Interfaces; +partial package PartialPureParametrization "Base package defining all properties for parametrization of pure component working pairs" + extends Modelica.Icons.MaterialPropertiesPackage; + + // + // Definition of constants + // + constant Modelica.Units.SI.MolarMass M_adsorptive + "Molar mass of the adsorptive" + annotation (Dialog(tab="General",group="Constants", enable=false), + choices(checkBox=true)); + constant Boolean twoPhaseAdsorptive + "= true, if media model of the adsorptive has a two-phase regime" + annotation (Dialog(tab="General",group="Constants", enable=false), + choices(checkBox=true)); + + constant Boolean modelOfDubinin + "= true, if the isotherm model is based on the model of Dubinin" + annotation (Dialog(tab="General",group="Constants", enable=false), + choices(checkBox=true)); + constant Integer no_coefficients + "Number of isotherm model coefficients" + annotation (Dialog(tab="General",group="Constants", enable=false)); + // + // Definition of packges + // + replaceable package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents + "Package of the isotherm model providing all functions of the isotherm model" + annotation (Dialog(tab = "General", group = "Packages", enable=false)); + + replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + constrainedby + SorpLib.Media.WorkingPairs.Interfaces.PartialPureMediumSpecificFunctions + "Package of medium specific functions" + annotation (Dialog(tab = "General", group = "Packages", enable=false)); + // + // Definition of models + // + replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.GenericSorbent + constrainedby SorpLib.Media.Solids.BaseClasses.PartialSolid + "Calculates the thermodynamic properties of the sorbent" + annotation (Dialog(tab = "General", group = "Models"), + choicesAllMatching=true); + // + // Definition of functions + // + replaceable partial function calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Real[no_coefficients] c + "Isotherm coefficients" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates the temperature-dependent isotherm coefficients <i>c</i>. +Functions that inherit from this partial function must add the equations of the +isotherm coefficients. Typical temperature dependencies of isotherm coefficients +are provided as generalized functions in the package +<a href=\"Modelica://SorpLib.Media.WorkingPairs.Parametrizations.Utilities\">SorpLib.Media.WorkingPairs.Parametrizations.Utilities</a>. +Constants required to calculate the temperature dependencies should be implemented +as new constants in the parametrization package.</p> +</html>")); + end calc_c; + + replaceable partial function calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + extends Modelica.Icons.Function; + + // + // Definition of inputs and outputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference if derivatives are calculated numerically" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Real[no_coefficients] c + "Isotherm coefficients" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + output Real[no_coefficients] dc_dT + "Partial derivative of isotherm coefficients w.r.t. temperature" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + output Real[no_coefficients] ddc_dT_dT + "Second-order partial derivative of isotherm coefficients w.r.t. temperature" + annotation (Dialog(tab="General",group="Outputs",enable=false)); + + // + // Annotations + // + annotation (Inline=true, Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates the temperature-dependent isotherm coefficients <i>c</i> +and their first- and second-order partial derivatives with respect to temperature +(<i>dc_dT</i> and <i>ddc_dT_dT</i>). Functions that inherit from this partial +function must add the equations of the isotherm coefficients and their partial +derivatives. Typical temperature dependencies of isotherm coefficients are provided +as generalized functions in the package +<a href=\"Modelica://SorpLib.Media.WorkingPairs.Parametrizations.Utilities\">SorpLib.Media.WorkingPairs.Parametrizations.Utilities</a>. +Constants required to calculate the temperature dependencies should be implemented +as new constants in the parametrization package.</p> +</html>")); + end calc_coefficients; + + replaceable partial function calc_h_ads_Dubinin + "Calculates the molar adsorption enthalpy according to the model of Dubinin" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real[no_coefficients] c + "Isotherm coefficients" + annotation (Dialog(tab="General",group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.Uptake x_adsorpt + "Equilibrium uptake" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Isobaric expansion coefficient of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + input + SorpLib.Media.WorkingPairs.Records.PropertiesPureAdsorptive properties_adsorptive + "Record containing all properties of the adsorptive required for the working + pair model" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificEnthalpy h_ads + "Specific enthalpy of adsorption" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=properties_adsorptive.p_sat, + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of the characteristic curve w.r.t. the molar adsorption + potential at constant pressure and temperaure"; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates the specific enthalpy of adsorption according to the +model of Dubinin. For more information, check the model +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin\">SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin</a>. +</p> +</html>")); + end calc_h_ads_Dubinin; + + replaceable partial function calc_dh_ads_dp_T_Dubinin + "Calculates the partial derivative of the molar adsorption enthalpy w.r.t. pressure at constant temperature according to the model of Dubinin" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real[no_coefficients] c + "Isotherm coefficients" + annotation (Dialog(tab="General",group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature" + annotation (Dialog(tab="General",group="Inputs")); + + input SorpLib.Units.Uptake x_adsorpt + "Equilibrium uptake" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp + "Partial derivative of uptake w.r.t. pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of specific volume of the adsorpt w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Isobaric expansion coefficient of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerIsobaricExpansionCoefficientByPressure dbeta_adsorpt_dp + "Partial derivative of isobaric expansion coefficient of the adsorpt phase + w.r.t. pressure at constant temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input + SorpLib.Media.WorkingPairs.Records.PropertiesPureAdsorptive properties_adsorptive + "Record containing all properties of the adsorptive required for the working + pair model" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output SorpLib.Units.DerSpecificEnthalpyByPressure dh_ads_dp + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=properties_adsorptive.p_sat, + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=properties_adsorptive.p_sat, + T_adsorpt=T_adsorpt) + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of the characteristic curve w.r.t. the molar adsorption + potential at constant pressure and temperaure"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA + "Second-order partial derivative of filled pore volume w.r.t. molar + adsorption potential and temperature at constant pressure and temperature"; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy of +adsorption with respect to pressure at constant temperature according to the +model of Dubinin. For more information, check the model +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_Dubinin\">SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_Dubinin</a>. +</p> +</html>")); + end calc_dh_ads_dp_T_Dubinin; + + replaceable partial function calc_dh_ads_dT_p_Dubinin + "Calculates the partial derivative of the molar adsorption enthalpy w.r.t. temperature at constant pressure according to the model of Dubinin" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real[no_coefficients] c + "Isotherm coefficients" + annotation (Dialog(tab="General",group="Inputs")); + input Real[no_coefficients] dc_dT_adsorpt + "Partial derivative of isotherm coefficients w.r.t. temperature" + annotation (Dialog(tab="General",group="Inputs")); + + input Modelica.Units.SI.Pressure p_adsorpt + "Equilibrium pressure" + annotation (Dialog(tab="General",group="Inputs")); + input Modelica.Units.SI.Temperature T_adsorpt + "Equilibrium temperature" + annotation (Dialog(tab="General",group="Inputs")); + + input SorpLib.Units.Uptake x_adsorpt + "Equilibrium uptake" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT + "Partial derivative of uptake w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of specific volume of the adsorpt w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Isobaric expansion coefficient of the adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + input SorpLib.Units.DerIsobaricExpansionCoefficientByTemperature dbeta_adsorpt_dT + "Partial derivative of isobaric expansion coefficient of the adsorpt phase + w.r.t. temperature at constant pressure" + annotation (Dialog(tab="General", group="Inputs")); + + input + SorpLib.Media.WorkingPairs.Records.PropertiesPureAdsorptive properties_adsorptive + "Record containing all properties of the adsorptive required for the working + pair model" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of outputs + // + output Modelica.Units.SI.SpecificHeatCapacity dh_ads_dT + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=properties_adsorptive.p_sat, + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=properties_adsorptive.p_sat, + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=properties_adsorptive.dp_sat_dT) + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of the characteristic curve w.r.t. the molar adsorption + potential at constant pressure and temperaure"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT + "Second-order partial derivative of filled pore volume w.r.t. molar + adsorption potential and temperature at constant pressure"; + + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy of +adsorption with respect to temperature at constant pressure according to the +model of Dubinin. For more information, check the model +<a href=\"Modelica://SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_Dubinin\">SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_Dubinin</a>. +</p> +</html>")); + end calc_dh_ads_dT_p_Dubinin; + + replaceable partial function calc_integrand_WaltonLeVan_Dubinin + "Calculates the integrand required for calculating the specific heat capacity according to Walton and Le Van (2005) when using the specifc enthalpy of adsorption according to Dubinin" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real ddc_dT_adsorpt_dT_adsorpt[:] + "Second-order partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding the specific volume of the adsorpt + // + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of the specific volume of the adsorpt w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of the specific volume of the adsorpt w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding the isobaric expansion coefficient of the adsorpt + // + input Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerIsobaricExpansionCoefficientByPressure dbeta_adsorpt_dp + "Partial derivative of the specific volume of the adsorpt w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerIsobaricExpansionCoefficientByTemperature dbeta_adsorpt_dT + "Partial derivative of the specific volume of the adsorpt w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt= + IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp= + IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT= + IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp= + IsothermModel.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at contant + temperature"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT= + IsothermModel.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. temperature at contant + pressure"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT= + IsothermModel.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + SorpLib.Units.DerSpecificEnthalpyByPressure dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the molar adsorption enthalpy +with respect to temperature at constant uptake when using the molar adsorption +enthalpy according to Dubinin. For more information, check the model +<a href=\"Modelica://SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_ads_dT_x_Dubinin\">SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_ads_dT_x_Dubinin</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end calc_integrand_WaltonLeVan_Dubinin; + + replaceable partial function calc_integrand_SchwambergerSchmidt_Dubinin + "Calculates the integrand required for calculating the specific heat capacity according to Schwamberger and Schmidt (2013) when using the specifc enthalpy of adsorption according to Dubinin" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + input Real ddc_dT_adsorpt_dT_adsorpt[:] + "Second-order partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding the specific volume of the adsorpt + // + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByPressure dv_adsorpt_dp + "Partial derivative of the specific volume of the adsorpt w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerSpecificVolumeByTemperature dv_adsorpt_dT + "Partial derivative of the specific volume of the adsorpt w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding the isobaric expansion coefficient of the adsorpt + // + input Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerIsobaricExpansionCoefficientByPressure dbeta_adsorpt_dp + "Partial derivative of the specific volume of the adsorpt w.r.t. pressure at + constant temperature" + annotation (Dialog(tab="General",group="Inputs")); + input SorpLib.Units.DerIsobaricExpansionCoefficientByTemperature dbeta_adsorpt_dT + "Partial derivative of the specific volume of the adsorpt w.r.t. temperature at + constant pressure" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt= + IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp= + IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT= + IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerUptakeByPressurePressure ddx_adsorpt_dp_dp= + IsothermModel.ddx_dp_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Second-order partial derivative of uptake w.r.t. pressure at contant + temperature"; + SorpLib.Units.DerUptakeByTemperatureTemperature ddx_adsorpt_dT_dT= + IsothermModel.ddx_dT_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt, + ddc_dT_adsorpt_dT_adsorpt=ddc_dT_adsorpt_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. temperature at contant + pressure"; + SorpLib.Units.DerUptakeByPressureTemperature ddx_adsorpt_dp_dT= + IsothermModel.ddx_dp_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of uptake w.r.t. pressure and temperature"; + + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptive_dT + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. temperature + at constant pressure"; + + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + SorpLib.Units.DerMolarAdsorptionPotentialByPressure dA_dp= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dp( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerMolarAdsorptionPotentialByTemperature dA_dT= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.dA_dT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt, + dp_sat_dT_adsorpt=dc_dT_adsorpt[1]) + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential ddW_dA_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotentialTemperature ddW_dA_dT + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + SorpLib.Units.DerSpecificEnthalpyByPressure dh_adsorptiveToLiquid_dp + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptiveToLiquid_dT + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + SorpLib.Units.DerMolarEnthalpyByPressure dh_ads_dp_T + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.MolarHeatCapacity dh_ads_dT_p + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the partial derivative of the specific enthalpy of the +adsorpt with respect to temperature at constant uptake when using the molar adsorption +enthalpy according to Dubinin. For more information, check the model +<a href=\"Modelica://SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_adsorpt_dT_x_Dubinin\">SorpLib.Media.Functions.SpecificHeatCapacitiesAdsorpt.PureComponents.Integrands.dh_adsorpt_dT_x_Dubinin</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end calc_integrand_SchwambergerSchmidt_Dubinin; + + replaceable partial function calc_integrand_h_avg_adsorpt_Dubinin + "Calculates the integrand required for calculating the uptake-averaged specific enthalpy of adsorpt using the adsorption enthalpy according to Dubinin" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding the specific volume of the adsorpt + // + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding the isobaric expansion coefficient of the adsorpt + // + input Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt= + IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptive + "Specific enthalpy of the adsorptive"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp= + IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT= + IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + + Modelica.Units.SI.MolarEnthalpy h_ads + "Molar adsorption enthalpy"; + + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific enthalpy difference between the adsorptive +and adsorpt using the specific enthalpy of adsorption according to Dubinin. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end calc_integrand_h_avg_adsorpt_Dubinin; + + + + replaceable partial function calc_integrand_s_avg_adsorpt_Dubinin + "Calculates the integrand required for calculating the uptake-averaged specific entropy of adsorpt using the adsorption enthalpy according to Dubinin" + extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction; + + // + // Definition of inputs + // + input Modelica.Units.SI.Temperature T_adsorpt + "Temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Real c[:] + "Coefficients of the isotherm model" + annotation (Dialog(tab="General", group="Inputs")); + input Real dc_dT_adsorpt[:] + "Partial derivative of coefficients of the isotherm model w.r.t. + temperature" + annotation (Dialog(tab="General", group="Inputs")); + + input Boolean adsorptiveAtDewPoint + "= true, if adsorptive (gas/vapor phase) is assumed to be at dew point at + T_adsorpt" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of inputs regarding the specific volume of the adsorpt + // + input Modelica.Units.SI.SpecificVolume v_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding the isobaric expansion coefficient of the adsorpt + // + input Modelica.Units.SI.RelativePressureCoefficient beta_adsorpt + "Specific volume of the adsorpt" + annotation (Dialog(tab="General",group="Inputs")); + + // + // Definition of inputs regarding numerics + // + input Modelica.Units.SI.Pressure p_clausiusClyperon + "Maximum pressure up to which the molar adsorption enthalpy is calculated + according to the Clausius Clyperon assumptions" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.PressureDifference dp + "Pressure difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + input Modelica.Units.SI.TemperatureDifference dT + "Temperature difference used to calculate partial derivatives w.r.t. pressure + numerially (just used if analytical solution does not exist)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of variables + // +protected + Modelica.Units.SI.Pressure p_adsorpt= + IsothermModel.p_xT( + x_adsorpt=u, + T_adsorpt=T_adsorpt, + c=c, + p_adsorpt_lb_start=1, + p_adsorpt_ub_start=10, + tolerance=100*Modelica.Constants.eps) + "Pressure at x_adsorpt = u and T_adsorpt"; + + Modelica.Units.SI.SpecificEntropy s_adsorptive + "Specific entropy of the adsorptive"; + + SorpLib.Units.DerUptakeByPressure dx_adsorpt_dp= + IsothermModel.dx_dp( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c) + "Partial derivative of uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_adsorpt_dT= + IsothermModel.dx_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Partial derivative of uptake w.r.t. temperature at constant pressure"; + + SorpLib.Units.MolarAdsorptionPotential A= + SorpLib.Media.Functions.SorptionEquilibria.Utilities.A_ppsT( + p_adsorpt=p_adsorpt, + p_sat=c[1], + T_adsorpt=T_adsorpt) + "Molar adsorption potential"; + SorpLib.Units.DerFilledPoreVolumeByAdsorptionPotential dW_dA + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + + Modelica.Units.SI.MolarEnthalpy h_ads + "Molar adsorption enthalpy"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function calculates the specific entropy difference between the adsorptive +and adsorpt using the specific enthalpy of adsorption according to Dubinin. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); + end calc_integrand_s_avg_adsorpt_Dubinin; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package contains all declaration for parametrization of a pure component working +pair. This means that constants, packages, models, and functions are defined that every pure +component working pair must support. Note that only some of the medium specific functions are +optional (see +<a href=\"Modelica://SorpLib.Media.WorkingPairs.BaseClasses.PartialPureMediumSpecificFunctions\">SorpLib.Media.WorkingPairs.BaseClasses.PartialPureMediumSpecificFunctions</a>). +Packages that inherit properties from this partial package must redeclare all constants, the +two partial packages <i>IsothermModel</i> and <i>MediumSpecificFunctions</i>, the model <i>Sorbent</i>, +the two functions <i>calc_c</i> and <i>calc_coefficients</i>, and optionally the five functions +<i>calc_h_ads_Dubinin</i>, <i>calc_dh_ads_dp_T_Dubinin</i>, <i>calc_dh_ads_dT_dp_Dubinin</i>, +<i>calc_integrand_WaltonLeVan_Dubinin</i>, and <i>calc_integrand_SchwambergerSchmidt_Dubinin</i> +(if using the model of Dubinin). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureParametrization; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/package.order b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e47c07f3bba53dbe83c5b6d20e51d6d63298f5d5 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrization/package.order @@ -0,0 +1,29 @@ +M_adsorptive +twoPhaseAdsorptive +modelOfDubinin +no_coefficients +IsothermModel +MediumSpecificFunctions +Sorbent +IsothermCoefficients +AdsorptProperties +calc_c +calc_coefficients +calc_h_ads_Dubinin +calc_dh_ads_dp_T_Dubinin +calc_dh_ads_dT_p_Dubinin +calc_integrand_WaltonLeVan +calc_integrand_WaltonLeVan_CC +calc_integrand_WaltonLeVan_Dubinin +calc_integrand_SchwambergerSchmidt_Constant +calc_integrand_SchwambergerSchmidt +calc_integrand_SchwambergerSchmidt_CC +calc_integrand_SchwambergerSchmidt_Dubinin +calc_integrand_h_avg_adsorpt_Constant +calc_integrand_h_avg_adsorpt_Formal +calc_integrand_h_avg_adsorpt_CC +calc_integrand_h_avg_adsorpt_Dubinin +calc_integrand_s_avg_adsorpt_Constant +calc_integrand_s_avg_adsorpt_Formal +calc_integrand_s_avg_adsorpt_CC +calc_integrand_s_avg_adsorpt_Dubinin diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationDubinin/package.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationDubinin/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d3996eb6878771fc549843e94895ee2f9d739985 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationDubinin/package.mo @@ -0,0 +1,551 @@ +within SorpLib.Media.WorkingPairs.Interfaces; +partial package PartialPureParametrizationDubinin "Base package defining all properties for parametrization of pure component working pairs based on the Dubinin model" + extends SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization( + final twoPhaseAdsorptive = true, + final modelOfDubinin = true, + redeclare replaceable package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponentsDubinin + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponentsDubinin); + // + // Redeclare functions + // + redeclare final function extends calc_h_ads_Dubinin + "Molar adsorption enthalpy according to the model of Dubinin" + algorithm + // + // Calculate additional properties + // + dW_dA :=IsothermModel.dW_dA( + A=A, + c=c) + "Partial derivative of the characteristic curve w.r.t. the molar adsorption + potential at constant pressure and temperaure"; + + // + // Calculate specific enthalpy of adsorption + // + h_ads := 1 / M_adsorptive * + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + h_adsorptiveToLiquid=properties_adsorptive.h_adsorptiveToLiquid, + v_adsorpt=v_adsorpt, + beta_adsorpt=beta_adsorpt, + A=A, + dW_dA=dW_dA) + "Specific enthalpy of adsorption"; + end calc_h_ads_Dubinin; + + redeclare final function extends calc_dh_ads_dp_T_Dubinin + "Calculates the partial derivative of the molar adsorption enthalpy w.r.t. pressure at constant temperature according to the model of Dubinin" + algorithm + // + // Calculate additional properties + // + dW_dA :=IsothermModel.dW_dA( + A=A, + c=c) + "Partial derivative of the characteristic curve w.r.t. the molar adsorption + potential at constant pressure and temperaure"; + ddW_dA_dA := IsothermModel.ddW_dA_dA( + A=A, + c=c) + "Second-order partial derivative of filled pore volume w.r.t. molar + adsorption potential and temperature at constant pressure and temperature"; + + // + // Calculate specific enthalpy of adsorption + // + dh_ads_dp := 1 / M_adsorptive * + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + h_adsorptiveToLiquid=properties_adsorptive.h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dp=properties_adsorptive.dh_adsorptiveToLiquid_dp_T, + v_adsorpt=v_adsorpt, + dv_adsorpt_dp=dv_adsorpt_dp, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dp=dbeta_adsorpt_dp, + dA_dp=dA_dp, + dW_dA=dW_dA, + ddW_dA_dA=ddW_dA_dA) + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature"; + end calc_dh_ads_dp_T_Dubinin; + + redeclare final function extends calc_dh_ads_dT_p_Dubinin + "Calculates the partial derivative of the molar adsorption enthalpy w.r.t. temperature at constant pressure according to the model of Dubinin" + algorithm + // + // Calculate additional properties + // + dW_dA :=IsothermModel.dW_dA( + A=A, + c=c) + "Partial derivative of the characteristic curve w.r.t. the molar adsorption + potential at constant pressure and temperaure"; + ddW_dA_dT := IsothermModel.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of filled pore volume w.r.t. molar + adsorption potential and temperature at constant pressure"; + + // + // Calculate specific enthalpy of adsorption + // + dh_ads_dT := 1 / M_adsorptive * + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=x_adsorpt, + dx_adsorpt_dT=dx_adsorpt_dT, + h_adsorptiveToLiquid=properties_adsorptive.h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dT=properties_adsorptive.dh_adsorptiveToLiquid_dT_p, + v_adsorpt=v_adsorpt, + dv_adsorpt_dT=dv_adsorpt_dT, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dT=dbeta_adsorpt_dT, + dA_dT=dA_dT, + dW_dA=dW_dA, + ddW_dA_dT=ddW_dA_dT) + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure"; + end calc_dh_ads_dT_p_Dubinin; + + redeclare final function extends calc_integrand_WaltonLeVan_Dubinin + "Calculates the integrand required for calculating the specific heat capacity according to Walton and Le Van (2005) when using the specifc enthalpy of adsorption according to Dubinin" + algorithm + dW_dA:=IsothermModel.dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dA := IsothermModel.ddW_dA_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dT := IsothermModel.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius Clyperon assumptions + // + (,,,,,,h_adsorptiveToLiquid,dh_adsorptiveToLiquid_dp,dh_adsorptiveToLiquid_dT) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=true, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point) and its partial derivatives"; + + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=u, + dx_adsorpt_dp=dx_adsorpt_dp, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dp=dh_adsorptiveToLiquid_dp, + v_adsorpt=v_adsorpt, + dv_adsorpt_dp=dv_adsorpt_dp, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dp=dbeta_adsorpt_dp, + dA_dp=dA_dp, + dW_dA=dW_dA, + ddW_dA_dA=ddW_dA_dA) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=u, + dx_adsorpt_dT=dx_adsorpt_dT, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dT=dh_adsorptiveToLiquid_dT, + v_adsorpt=v_adsorpt, + dv_adsorpt_dT=dv_adsorpt_dT, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dT=dbeta_adsorpt_dT, + dA_dT=dA_dT, + dW_dA=dW_dA, + ddW_dA_dT=ddW_dA_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + else + // + // Use Clausius Clyperon assumptions: No further propiertes are required + // + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + end if; + + // + // Calculation of the integrand + // + y := dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake"; + end calc_integrand_WaltonLeVan_Dubinin; + + redeclare final function extends calc_integrand_SchwambergerSchmidt_Dubinin + "Calculates the integrand required for calculating the specific heat capacity according to Schwamberger and Schmidt (2013) when using the specifc enthalpy of adsorption according to Dubinin" + algorithm + dW_dA:=IsothermModel.dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dA := IsothermModel.ddW_dA_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + ddW_dA_dT := IsothermModel.ddW_dA_dT( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + A=A, + c=c, + dc_dT_adsorpt=dc_dT_adsorpt) + "Second-order partial derivative of filled pore volume w.r.t. molar adsorption + potential and temperature at constant pressure"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius Clyperon assumptions + // + (,,,,, dh_adsorptive_dT, + h_adsorptiveToLiquid, dh_adsorptiveToLiquid_dp, dh_adsorptiveToLiquid_dT) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=true, + require_h_adsorptiveToLiquid=true, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. + temperature at constant pressure and specific enthalpy difference between + adsorptive state and saturated liquid state (i.e., bubble point) and its + partial derivatives"; + + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=u, + dx_adsorpt_dp=dx_adsorpt_dp, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dp=dh_adsorptiveToLiquid_dp, + v_adsorpt=v_adsorpt, + dv_adsorpt_dp=dv_adsorpt_dp, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dp=dbeta_adsorpt_dp, + dA_dp=dA_dp, + dW_dA=dW_dA, + ddW_dA_dA=ddW_dA_dA) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=u, + dx_adsorpt_dT=dx_adsorpt_dT, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + dh_adsorptiveToLiquid_dT=dh_adsorptiveToLiquid_dT, + v_adsorpt=v_adsorpt, + dv_adsorpt_dT=dv_adsorpt_dT, + beta_adsorpt=beta_adsorpt, + dbeta_adsorpt_dT=dbeta_adsorpt_dT, + dA_dT=dA_dT, + dW_dA=dW_dA, + ddW_dA_dT=ddW_dA_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + else + // + // Use Clausius Clyperon assumptions: No further propiertes are required + // + (,,,,, dh_adsorptive_dT,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=true, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Partial derivative of the specific enthalpy of the adsorptive w.r.t. + temperature at constant pressure"; + + dh_ads_dp_T := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dp_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dp=ddx_adsorpt_dp_dp, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. pressure at constant + temperature"; + dh_ads_dT_p := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.dh_ads_dT_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT, + ddx_adsorpt_dp_dT=ddx_adsorpt_dp_dT, + ddx_adsorpt_dT_dT=ddx_adsorpt_dT_dT) + "Partial derivative of molar adsorption enthalpy w.r.t. temperature at constant + pressure"; + + end if; + + // + // Calculation of the integrand + // + y := dh_adsorptive_dT - + (dh_ads_dT_p - dh_ads_dp_T * dx_adsorpt_dT / dx_adsorpt_dp) / M_adsorptive + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake"; + end calc_integrand_SchwambergerSchmidt_Dubinin; + + redeclare final function extends calc_integrand_h_avg_adsorpt_Dubinin + "Calculates the integrand required for calculating the uptake-averaged specific enthalpy of adsorpt using the adsorption enthalpy according to Dubinin" + algorithm + dW_dA:=IsothermModel.dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius-Clyperon assumptions + // + (,,,h_adsorptive,,,h_adsorptiveToLiquid,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=true, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=true, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific enthalpy of the adsorptive and specific enthalpy difference between + adsorptive state and saturated liquid state (i.e., bubble point)"; + + h_ads := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=u, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + v_adsorpt=v_adsorpt, + beta_adsorpt=beta_adsorpt, + A=A, + dW_dA=dW_dA) + "Molar specific enthalpy of adsorption"; + + else + // + // Use Clausius-Clyperon assumptions + // + (,,,h_adsorptive,,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=true, + require_s_adsorptive=false, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Partial enthalpy of the adsorptive"; + + h_ads := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar specific enthalpy of adsorption"; + + end if; + + // + // Calculation of the integrand + // + y := h_adsorptive - h_ads / M_adsorptive + "Integrand: Specific enthalpy difference between the adsorptive and adsorpt"; + end calc_integrand_h_avg_adsorpt_Dubinin; + + redeclare final function extends calc_integrand_s_avg_adsorpt_Dubinin + "Calculates the integrand required for calculating the uptake-averaged specific entropy of adsorpt using the adsorption enthalpy according to Dubinin" + algorithm + dW_dA:=IsothermModel.dW_dA( + A=A, + c=c) + "Partial derivative of filled pore volume w.r.t. molar adsorption potential + at constant pressure and temperature"; + + // + // Calculation of further properties + // + if p_adsorpt > p_clausiusClyperon then + // + // Do not use Clausius-Clyperon assumptions + // + (,,,,s_adsorptive,,h_adsorptiveToLiquid,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=true, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=true, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Specific entropy of the adsorptive and specific enthalpy difference between + adsorptive state and saturated liquid state (i.e., bubble point)"; + + h_ads := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_Dubinin( + M_adsorptive=M_adsorptive, + T_adsorpt=T_adsorpt, + x_adsorpt=u, + h_adsorptiveToLiquid=h_adsorptiveToLiquid, + v_adsorpt=v_adsorpt, + beta_adsorpt=beta_adsorpt, + A=A, + dW_dA=dW_dA) + "Molar specific enthalpy of adsorption"; + + else + // + // Use Clausius-Clyperon assumptions + // + (,,,,s_adsorptive,,,,) := + MediumSpecificFunctions.calc_properties( + p=p_adsorpt, + T=T_adsorpt, + dp=dp, + dT=dT, + p_min=p_clausiusClyperon, + require_v_adsorptive=false, + require_h_adsorptive=false, + require_s_adsorptive=true, + require_dh_adsorptive_dT_dp=false, + require_h_adsorptiveToLiquid=false, + adsorptiveAtDewPoint=adsorptiveAtDewPoint) + "Partial entropy of the adsorptive"; + + h_ads := + SorpLib.Media.Functions.SorptionEnthalpies.PureComponents.h_ads_clausiusClapeyron( + p_adsorpt=p_adsorpt, + T_adsorpt=T_adsorpt, + dx_adsorpt_dp=dx_adsorpt_dp, + dx_adsorpt_dT=dx_adsorpt_dT) + "Molar specific enthalpy of adsorption"; + + end if; + + // + // Calculation of the integrand + // + y := s_adsorptive - h_ads / M_adsorptive / T_adsorpt + "Integrand: Specific entropy difference between the adsorptive and adsorpt"; + end calc_integrand_s_avg_adsorpt_Dubinin; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package contains all declaration for parametrization of a pure component working +pair based on the model of Dubinin. This means that constants, packages, models, and functions +are defined that every pure component working pair must support. Packages that inherit properties +from this partial package must redeclare all constants except of <i>twoPhaseAdsorptive</i> and +<i>modelOfDubinin</i>, the two partial packages <i>IsothermModel</i> and <i>MediumSpecificFunctions</i>, +the model <i>Sorbent</i>, and the two functions <i>calc_c</i> and <i>calc_coefficients</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureParametrizationDubinin; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationDubinin/package.order b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationDubinin/package.order new file mode 100644 index 0000000000000000000000000000000000000000..112bbe237694f0e259af745b9faa0225b67a64a9 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationDubinin/package.order @@ -0,0 +1,7 @@ +calc_h_ads_Dubinin +calc_dh_ads_dp_T_Dubinin +calc_dh_ads_dT_p_Dubinin +calc_integrand_WaltonLeVan_Dubinin +calc_integrand_SchwambergerSchmidt_Dubinin +calc_integrand_h_avg_adsorpt_Dubinin +calc_integrand_s_avg_adsorpt_Dubinin diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationNonDubinin/package.mo b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationNonDubinin/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..7d6d12a97e4fb7fad9b4b69ea378bbe854344bd5 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationNonDubinin/package.mo @@ -0,0 +1,87 @@ +within SorpLib.Media.WorkingPairs.Interfaces; +partial package PartialPureParametrizationNonDubinin "Base package defining all properties for parametrization of pure component working pairs not based on the Dubinin model" + extends SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrization( + final modelOfDubinin = false, + redeclare replaceable package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents + constrainedby + SorpLib.Media.Functions.SorptionEquilibria.Interfaces.PartialPureComponents); + // + // Redeclare functions + // + redeclare final function extends calc_h_ads_Dubinin + "Molar adsorption enthalpy according to the model of Dubinin (i.e., not required)" + algorithm + h_ads := 0 + "Specific enthalpy of adsorption: Dummy value"; + end calc_h_ads_Dubinin; + + redeclare final function extends calc_dh_ads_dp_T_Dubinin + "Calculates the partial derivative of the molar adsorption enthalpy w.r.t. pressure at constant temperature according to the model of Dubinin (i.e., not required)" + algorithm + dh_ads_dp := 0 + "Partial derivative of molar adsorption potential w.r.t. pressure at + constant temperature: Dummy value"; + end calc_dh_ads_dp_T_Dubinin; + + redeclare final function extends calc_dh_ads_dT_p_Dubinin + "Calculates the partial derivative of the molar adsorption enthalpy w.r.t. temperature at constant pressure according to the model of Dubinin (i.e., not required)" + algorithm + dh_ads_dT := 0 + "Partial derivative of molar adsorption potential w.r.t. temperature at + constant pressure: Dummy value"; + end calc_dh_ads_dT_p_Dubinin; + + redeclare final function extends calc_integrand_WaltonLeVan_Dubinin + "Calculates the integrand required for calculating the specific heat capacity according to Walton and Le Van (2005) when using the specifc enthalpy of adsorption according to Dubinin (i.e., not required)" + algorithm + y := 0 + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake: Dummy value"; + end calc_integrand_WaltonLeVan_Dubinin; + + redeclare final function extends calc_integrand_SchwambergerSchmidt_Dubinin + "Calculates the integrand required for calculating the specific heat capacity according to Schwamberger and Schmidt (2013) when using the specifc enthalpy of adsorption according to Dubinin (i.e., not required)" + algorithm + y := 0 + "Integrand: Partial derivative of molar sorption enthalpy w.r.t. temperature + at constant uptake: Dummy value"; + end calc_integrand_SchwambergerSchmidt_Dubinin; + + redeclare final function extends calc_integrand_h_avg_adsorpt_Dubinin + "Calculates the integrand required for calculating the uptake-averaged specific enthalpy of adsorpt using the adsorption enthalpy according to Dubinin (i.e., not required)" + algorithm + y := 0 + "Integrand: Specific enthalpy difference between the adsorptive and adsorpt: + Dummy value"; + end calc_integrand_h_avg_adsorpt_Dubinin; + + redeclare final function extends calc_integrand_s_avg_adsorpt_Dubinin + "Calculates the integrand required for calculating the uptake-averaged specific entropy of adsorpt using the adsorption enthalpy according to Dubinin (i.e., not required)" + algorithm + y := 0 + "Integrand: Specific entropy difference between the adsorptive and adsorpt: + Dummy value"; + end calc_integrand_s_avg_adsorpt_Dubinin; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package contains all declaration for parametrization of a pure component working +pair not based on the model of Dubinin. This means that constants, packages, models, and functions +are defined that every pure component working pair must support. Packages that inherit properties +from this partial package must redeclare all constants except of <i>modelOfDubinin</i>, the two +partial packages <i>IsothermModel</i> and <i>MediumSpecificFunctions</i>, the model <i>Sorbent</i>, +and the two functions <i>calc_c</i> and <i>calc_coefficients</i>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PartialPureParametrizationNonDubinin; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationNonDubinin/package.order b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationNonDubinin/package.order new file mode 100644 index 0000000000000000000000000000000000000000..112bbe237694f0e259af745b9faa0225b67a64a9 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/PartialPureParametrizationNonDubinin/package.order @@ -0,0 +1,7 @@ +calc_h_ads_Dubinin +calc_dh_ads_dp_T_Dubinin +calc_dh_ads_dT_p_Dubinin +calc_integrand_WaltonLeVan_Dubinin +calc_integrand_SchwambergerSchmidt_Dubinin +calc_integrand_h_avg_adsorpt_Dubinin +calc_integrand_s_avg_adsorpt_Dubinin diff --git a/SorpLib/Media/WorkingPairs/Interfaces/package.mo b/SorpLib/Media/WorkingPairs/Interfaces/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..df582de36428cf2c3320b4ca38a5a2b470d1fb80 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Media.WorkingPairs; +package Interfaces "Interfaces for working pair models" +extends Modelica.Icons.InterfacesPackage; + +annotation (Documentation(info="<html> +<p> +This package provides definitions of basic interfaces for working pair models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Interfaces; diff --git a/SorpLib/Media/WorkingPairs/Interfaces/package.order b/SorpLib/Media/WorkingPairs/Interfaces/package.order new file mode 100644 index 0000000000000000000000000000000000000000..13217e76ccca9a189f77b86d21152b20446e748d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Interfaces/package.order @@ -0,0 +1,4 @@ +PartialPureMediumSpecificFunctions +PartialPureParametrization +PartialPureParametrizationNonDubinin +PartialPureParametrizationDubinin diff --git a/SorpLib/Media/WorkingPairs/MultiComponents/Testers/package.mo b/SorpLib/Media/WorkingPairs/MultiComponents/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..784c708a5e79a717554ad9891f37a4ea34ba9458 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/MultiComponents/Testers/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.WorkingPairs.MultiComponents; +package Testers "Models to test and varify models of multi-component working pairs" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented working pair model. +Each working pair model has its own test model that is saved in the correct adsorptive +package. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/WorkingPairs/MultiComponents/Testers/package.order b/SorpLib/Media/WorkingPairs/MultiComponents/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/WorkingPairs/MultiComponents/package.mo b/SorpLib/Media/WorkingPairs/MultiComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..ca60b53d044f7cde1d73b7d95b635d37f59a0ca7 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/MultiComponents/package.mo @@ -0,0 +1,34 @@ +within SorpLib.Media.WorkingPairs; +package MultiComponents "Package containing multi-component working pair models" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains fully parameterized working models. For this purpose, +the partially parametrized multi-component working pair models are extended by a +specific <i>MediumSpecificFunctions</i> package. This package calculates fluid +properties based on the open-source Modelica Standard Library (MSL). +</p> + +<h4>Structure</h4> +<p> +The package +<a href=\"Modelica://SorpLib.Media.WorkingPairs.MultiComponents.MediumSpecificFunctions\">SorpLib.Media.WorkingPairs.MultiComponents.MediumSpecificFunctions</a> +contains different versions of packages providing medium specific functions. For +each package version there is also a corresponding working pair model. The finally +parametrized working pair models are alphabetically sorted by available asdsorptives +and are stored in seperate packages. The naming convention for the parameterized working +pair models is as follows +</p> +<pre> + NameSorbent_NameIsothermModel_NameAuthorsYear_MediumType; +</pre> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MultiComponents; diff --git a/SorpLib/Components/Cells/Wall/package.order b/SorpLib/Media/WorkingPairs/MultiComponents/package.order similarity index 61% rename from SorpLib/Components/Cells/Wall/package.order rename to SorpLib/Media/WorkingPairs/MultiComponents/package.order index c459b3640ebfec57a37fed95f8c25e1121a50dcb..f9d890e603b11e52c6882a1ded44458caf0c550d 100644 --- a/SorpLib/Components/Cells/Wall/package.order +++ b/SorpLib/Media/WorkingPairs/MultiComponents/package.order @@ -1,2 +1 @@ -Wall Testers diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/CO2_H2O/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/CO2_H2O/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..76b75baffbac48a6e67b0752fea58b855056f35c --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/CO2_H2O/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.MultiComponents; +package CO2_H2O "Package containing parametrizations for CO2 and H2O as adsorptives" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrizations for CO<sub>2</sub> and H<sub>2</sub>O +as adsorptives. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CO2_H2O; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/CO2_H2O/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/CO2_H2O/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..897e7d5665b7799420c7d2c48157252ecccb0cdc --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.WorkingPairs.Parametrizations; +package MultiComponents "Package containing parametrizations of multi-component working pairs" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrized multi-component working pair models. Check +the package content to see for which adsorptive mixtures working pair models +are already implemented. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MultiComponents; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..46ee6a885f8f1ce50506d6945b79d3703e3591f6 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/MultiComponents/package.order @@ -0,0 +1 @@ +CO2_H2O diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/ActivatedCarbon_Toth_DantasEtAl2011/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/ActivatedCarbon_Toth_DantasEtAl2011/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..6fe9f1ed09bcb5e9a62b678d2ddc8f400197d8cd --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/ActivatedCarbon_Toth_DantasEtAl2011/package.mo @@ -0,0 +1,108 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2; +package ActivatedCarbon_Toth_DantasEtAl2011 "CO2 & Activated carbon via the Toth isotherm model according to Dantas et al. (2011)" + extends SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=44.0095/1000, + twoPhaseAdsorptive=false, + final no_coefficients=3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake x_sat = 10.05 * M_adsorptive + "First contants of the isotherm model"; + constant Real b_ref(unit="1/Pa") = 7.62e-5 / (1e5) + "Second contants of the isotherm model"; + constant Real Q_star(unit="K") = -21.84e3 / Modelica.Constants.R + "Third contants of the isotherm model"; + constant Real t(unit="1") = 0.678 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + c[3] :=t; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + c[3] :=t; + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] :=0; + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + dc_dT[3] :=0; + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] :=0; + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + ddc_dT_dT[3] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +CO<sub>2</sub> & activated carbon using the Toth isotherm model according to Dantas +et al. (2011). Packages that inherit properties from this partial package may +redeclare the package <i>MediumSpecificFunctions</i>, the model <i>Sorbent</i>, +and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Dantas, T.L.P. and Luna, F.M.T. and Silva Jr., I.J. and Azevedo, D.C.S. and Grande, C.A. and Rodrigues, A.E. and Moreira, R.F.P.M. (2011). Carbon dioxide–nitrogen separation through adsorption on activated carbon in a fixed bed, Chemical Engineering Journal, 169:11–19. DOI: https://doi.org/10.1016/j.cej.2010.08.026. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ActivatedCarbon_Toth_DantasEtAl2011; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/ActivatedCarbon_Toth_DantasEtAl2011/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/ActivatedCarbon_Toth_DantasEtAl2011/package.order new file mode 100644 index 0000000000000000000000000000000000000000..99a9913827eacfcc8c8dd7798c68bd308b026919 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/ActivatedCarbon_Toth_DantasEtAl2011/package.order @@ -0,0 +1,6 @@ +x_sat +b_ref +Q_star +t +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/SilicaGel_Toth_WangDouglasLeVan2009/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/SilicaGel_Toth_WangDouglasLeVan2009/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5f2beecac5cd05bf6f4b35182b32446a9b80f6c4 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/SilicaGel_Toth_WangDouglasLeVan2009/package.mo @@ -0,0 +1,131 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2; +package SilicaGel_Toth_WangDouglasLeVan2009 "CO2 & silica gel via the Toth isotherm model according to Wang and Douglas LeVan (2009)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=44.0095/1000, + twoPhaseAdsorptive=false, + final no_coefficients=3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake x_sat = 7.678e-9 / b_ref * M_adsorptive + "First contants of the isotherm model"; + constant Real b_ref(unit="1/Pa") = 5.164e-10 + "Second contants of the isotherm model"; + constant Real E(unit="K") = 2.330e3 + "Third contants of the isotherm model"; + constant Real t(unit="1") = -3.053e-1 + "Fourth contants of the isotherm model"; + constant Real alpha(unit="1/K") = 2.386e2 + "Fivth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] :=0; + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + dc_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] :=0; + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + ddc_dT_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddlinear1_dT_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +CO<sub>2</sub> & silica gel using the Toth isotherm model according to Wang +and Douglas LeVan (2010). Packages that inherit properties from this partial +package may redeclare the package <i>MediumSpecificFunctions</i>, the model +<i>Sorbent</i>, and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGel_Toth_WangDouglasLeVan2009; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/SilicaGel_Toth_WangDouglasLeVan2009/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/SilicaGel_Toth_WangDouglasLeVan2009/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e5bc23d0fbc2696b31b46df77da6ed02ab280ccf --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/SilicaGel_Toth_WangDouglasLeVan2009/package.order @@ -0,0 +1,7 @@ +x_sat +b_ref +E +t +alpha +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_DantasEtAl2011/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_DantasEtAl2011/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..cef108f335883ae7d726ed143da1ca84188e3cf1 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_DantasEtAl2011/package.mo @@ -0,0 +1,109 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2; +package Zeolith13X_Toth_DantasEtAl2011 "CO2 & Zeolith 13X via the Toth isotherm model according to Dantas et al. (2011)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=44.0095/1000, + twoPhaseAdsorptive=false, + final no_coefficients=3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake x_sat = 5.09 * M_adsorptive + "First contants of the isotherm model"; + constant Real b_ref(unit="1/Pa") = 4.305e-4 / (1e5) + "Second contants of the isotherm model"; + constant Real Q_star(unit="K") = -29.38e3 / Modelica.Constants.R + "Third contants of the isotherm model"; + constant Real t(unit="1") = 0.429 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + c[3] :=t; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + c[3] :=t; + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] :=0; + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + dc_dT[3] :=0; + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] :=0; + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + ddc_dT_dT[3] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +CO<sub>2</sub> & Zeolith 13X using the Toth isotherm model according to Dantas +et al. (2011). Packages that inherit properties from this partial package may +redeclare the package <i>MediumSpecificFunctions</i>, the model <i>Sorbent</i>, +and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Dantas, T.L.P. and Luna, F.M.T. and Silva Jr., I.J. and Torres, A.E.B. and Azevedo, D.C.S. and Rodrigues, A.E. and Moreira, R.F.P.M. (2011). Carbon dioxide–nitrogen separation through pressure swing adsorption, Chemical Engineering Journal, 172:698-704. DOI: https://doi.org/10.1016/j.cej.2011.06.037. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_Toth_DantasEtAl2011; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_DantasEtAl2011/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_DantasEtAl2011/package.order new file mode 100644 index 0000000000000000000000000000000000000000..99a9913827eacfcc8c8dd7798c68bd308b026919 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_DantasEtAl2011/package.order @@ -0,0 +1,6 @@ +x_sat +b_ref +Q_star +t +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_WangDouglasLeVan2010/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_WangDouglasLeVan2010/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..4a3002eeb1ae878eef8f3550e0913093b1848019 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_WangDouglasLeVan2010/package.mo @@ -0,0 +1,134 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2; +package Zeolith13X_Toth_WangDouglasLeVan2010 "CO2 & Zeolith 13X via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=44.0095/1000, + twoPhaseAdsorptive=false, + final no_coefficients=3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake x_sat = 6.509e-6 / b_ref * M_adsorptive + "First contants of the isotherm model"; + constant Real b_ref(unit="1/Pa") = 4.884e-7 + "Second contants of the isotherm model"; + constant Real E(unit="K") = 2.991e3 + "Third contants of the isotherm model"; + constant Real t(unit="1") = 7.487e-2 + "Fourth contants of the isotherm model"; + constant Real alpha(unit="1/K") = 3.805e1 + "Fivth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] :=0; + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + dc_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] :=0; + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + ddc_dT_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddlinear1_dT_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +CO<sub>2</sub> & Zeolith 13X using the Toth isotherm model according to Wang +and Douglas LeVan (2010). Packages that inherit properties from this partial +package may redeclare the package <i>MediumSpecificFunctions</i>, the model +<i>Sorbent</i>, and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> + <li> + Wang, Y. and Douglas LeVan, M. (2010). Adsorption Equilibrium of Binary Mixtures of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X, Hournal of Chemical & Engineering Data, 55(9):3189–3195. DOI: https://doi.org/10.1021/je100053g. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_Toth_WangDouglasLeVan2010; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_WangDouglasLeVan2010/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_WangDouglasLeVan2010/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e5bc23d0fbc2696b31b46df77da6ed02ab280ccf --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith13X_Toth_WangDouglasLeVan2010/package.order @@ -0,0 +1,7 @@ +x_sat +b_ref +E +t +alpha +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith5A_Toth_WangDouglasLeVan2010/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith5A_Toth_WangDouglasLeVan2010/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..0aad73a011156a94142d4f26b48ffeaa5bbaa2e1 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith5A_Toth_WangDouglasLeVan2010/package.mo @@ -0,0 +1,134 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2; +package Zeolith5A_Toth_WangDouglasLeVan2010 "CO2 & Zeolith 5A via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=44.0095/1000, + twoPhaseAdsorptive=false, + final no_coefficients=3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake x_sat = 9.875e-10 / b_ref * M_adsorptive + "First contants of the isotherm model"; + constant Real b_ref(unit="1/Pa") = 6.761e-11 + "Second contants of the isotherm model"; + constant Real E(unit="K") = 5.625e3 + "Third contants of the isotherm model"; + constant Real t(unit="1") = 2.7e-1 + "Fourth contants of the isotherm model"; + constant Real alpha(unit="1/K") = -2.002e1 + "Fivth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] :=0; + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + dc_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] :=0; + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + ddc_dT_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddlinear1_dT_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +CO<sub>2</sub> & Zeolith 5A using the Toth isotherm model according to Wang +and Douglas LeVan (2010). Packages that inherit properties from this partial +package may redeclare the package <i>MediumSpecificFunctions</i>, the model +<i>Sorbent</i>, and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> + <li> + Wang, Y. and Douglas LeVan, M. (2010). Adsorption Equilibrium of Binary Mixtures of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X, Journal of Chemical & Engineering Data, 55(9):3189–3195. DOI: https://doi.org/10.1021/je100053g. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith5A_Toth_WangDouglasLeVan2010; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith5A_Toth_WangDouglasLeVan2010/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith5A_Toth_WangDouglasLeVan2010/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e5bc23d0fbc2696b31b46df77da6ed02ab280ccf --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/Zeolith5A_Toth_WangDouglasLeVan2010/package.order @@ -0,0 +1,7 @@ +x_sat +b_ref +E +t +alpha +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..cb74850271c78fd33d4b20e3098679cb5335c257 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents; +package CO2 "Package containing parametrizations for CO2 as adsorptive" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrizations for CO<sub>2</sub> as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CO2; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..f00603846f2df3f099d4ffbbfedd445c927105bb --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/CO2/package.order @@ -0,0 +1,5 @@ +ActivatedCarbon_Toth_DantasEtAl2011 +SilicaGel_Toth_WangDouglasLeVan2009 +Zeolith5A_Toth_WangDouglasLeVan2010 +Zeolith13X_Toth_DantasEtAl2011 +Zeolith13X_Toth_WangDouglasLeVan2010 diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e4e189989f26d151d135c5cd555d1ee6463752a4 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.mo @@ -0,0 +1,115 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017 "H2O & AQSOA-Z01 via the Dubinin isotherm model with a Lorentzian Cumulative according to measurment data from Goldsworty (2014) and fit from Bau (2017)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a = 0.204162691322846 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol") = 1.714393556857407e2 * 1000 * M_adsorptive + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = -13.888991966535533 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d = 0.005500438155033 / 1000 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & AQSOA-Z01 (FAM-Z01) using the Dubinin isotherm model with a Lorentzian +Cumulative characteristic curve generated by Bau (2017) using measurement data from +Goldsworthy (2014). Packages that inherit properties from this partial package +may redeclare the package <i>MediumSpecificFunctions</i> and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Goldsworthy (2014). Measurements of water vapour sorption isotherms for RD silica gel, AQSOA-Z01, AQSOA-Z02, AQSOA-Z05 and CECA zeolite 3A, Microporous and Mesoporous Materials, 196:59-67. DOI: http://dx.doi.org/10.1016/j.micromeso.2014.04.046. + </li> + <li> + Bau (2018). From Dynamic Simulation to Optimal Design and Control of Adsorption Energy Systems, PhD thesis. DOI: https://doi.org/10.18154/RWTH-2018-222524. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + December 14, 2020, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + November 17, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c4d7e2fba79f8b1a9a8db94e223c8e9600bae832 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.order @@ -0,0 +1,6 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..73c893c277bdd2c52e0ff3920f26229c3a811fc9 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.mo @@ -0,0 +1,125 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017 "H2O & AQSOA-Z02 via the Dubinin isotherm model with a Lorentzian Cumulative according to measurment data from Goldsworty (2014) and fit from Bau (2017)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE); + + // + // Definition of further constants + // + /* Coefficients as published in Bau's PhD thesis vs. coefficients of SorpLib V1 + constant SorpLib.Units.FilledPoreVolume char_curve_a(min=-1) = -3.461028e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol") = 3.096522e2 * 1000 * M_adsorptive + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = 9.726662e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d = 3.535178e-1 / 1000 + "Fourth contants of the isotherm model"; + */ + constant SorpLib.Units.FilledPoreVolume char_curve_a(min=-1) = 3.466e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol") = 3.094e2 * 1000 * M_adsorptive + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = -9.765e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d = 7.312e-4 / 1000 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & AQSOA-Z02 (FAM-Z02) using the Dubinin isotherm model with a Lorentzian +Cumulative characteristic curve generated by Bau (2017) using measurement data from +Goldsworthy (2014). Packages that inherit properties from this partial package +may redeclare the package <i>MediumSpecificFunctions</i> and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Goldsworthy (2014). Measurements of water vapour sorption isotherms for RD silica gel, AQSOA-Z01, AQSOA-Z02, AQSOA-Z05 and CECA zeolite 3A, Microporous and Mesoporous Materials, 196:59-67. DOI: http://dx.doi.org/10.1016/j.micromeso.2014.04.046. + </li> + <li> + Bau (2018). From Dynamic Simulation to Optimal Design and Control of Adsorption Energy Systems, PhD thesis. DOI: https://doi.org/10.18154/RWTH-2018-222524. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + December 14, 2020, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + November 17, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c4d7e2fba79f8b1a9a8db94e223c8e9600bae832 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.order @@ -0,0 +1,6 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..55d5433fed47f18bc0b373cd3cddb5b391e1a4cb --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.mo @@ -0,0 +1,115 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017 "H2O & AQSOA-Z05 via the Dubinin isotherm model with a Lorentzian Cumulative according to measurment data from Goldsworty (2014) and fit from Bau (2017)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a = 0.214158550589450 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol") = 1.491564711211805e2 * 1000 * M_adsorptive + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = -5.363761702090807 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d = 0.004607265196576 / 1000 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & AQSOA-Z05 (FAM-Z05) using the Dubinin isotherm model with a Lorentzian +Cumulative characteristic curve generated by Bau (2017) using measurement data from +Goldsworthy (2014). Packages that inherit properties from this partial package +may redeclare the package <i>MediumSpecificFunctions</i> and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Goldsworthy (2014). Measurements of water vapour sorption isotherms for RD silica gel, AQSOA-Z01, AQSOA-Z02, AQSOA-Z05 and CECA zeolite 3A, Microporous and Mesoporous Materials, 196:59-67. DOI: http://dx.doi.org/10.1016/j.micromeso.2014.04.046. + </li> + <li> + Bau (2018). From Dynamic Simulation to Optimal Design and Control of Adsorption Energy Systems, PhD thesis. DOI: https://doi.org/10.18154/RWTH-2018-222524. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + December 14, 2020, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + November 17, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c4d7e2fba79f8b1a9a8db94e223c8e9600bae832 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017/package.order @@ -0,0 +1,6 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/NaZeolithY_DubininEmpirical2_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/NaZeolithY_DubininEmpirical2_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a699da3a7f0b01bf729b95cf8a16b650329c820f --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/NaZeolithY_DubininEmpirical2_Schawe2000/package.mo @@ -0,0 +1,134 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package NaZeolithY_DubininEmpirical2_Schawe2000 "H2O & Na-Zeolith Y via the Dubinin isotherm model with an empirical 2 approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=9, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.GenericSorbent ( + v_constant=1/450, + c_constant=920, + lambda_constant=0.085)); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a= + 3.393156e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b= + 8.766651e-3 * sqrt(1 / 1000 / M_adsorptive) + "Second contants of the isotherm model"; + constant Real char_curve_c= + -1.104630e-2 / 1000 * sqrt(1 / 1000 / M_adsorptive) + "Third contants of the isotherm model"; + constant Real char_curve_d= + -2.448014e-3 / 1000 / M_adsorptive + "Fourth contants of the isotherm model"; + constant Real char_curve_e= + 9.055743e-5 / 1000 / 1000 / M_adsorptive + "Fivth contants of the isotherm model"; + constant Real char_curve_f= + 6.243287e-5 / 1000 / M_adsorptive * sqrt(1 / 1000 / M_adsorptive) + "Sixth contants of the isotherm model"; + constant Real char_curve_g= + 0 + "Seventh contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + c[9] :=char_curve_g; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + c[9] :=char_curve_g; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + dc_dT[7] :=0; + dc_dT[8] :=0; + dc_dT[9] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + ddc_dT_dT[7] :=0; + ddc_dT_dT[8] :=0; + ddc_dT_dT[9] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & Na-Zeolith Y using the Dubinin isotherm model with an empirical 2 +characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end NaZeolithY_DubininEmpirical2_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/NaZeolithY_DubininEmpirical2_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/NaZeolithY_DubininEmpirical2_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..85e413706c5d9574d9e7db8066ff2afc3d69e58d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/NaZeolithY_DubininEmpirical2_Schawe2000/package.order @@ -0,0 +1,9 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +char_curve_e +char_curve_f +char_curve_g +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel123_DubininLorentzianCumulative_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel123_DubininLorentzianCumulative_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c1769f08cfb73cbe33c66d42af864e00d0fa3221 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel123_DubininLorentzianCumulative_Schawe2000/package.mo @@ -0,0 +1,106 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package SilicaGel123_DubininLorentzianCumulative_Schawe2000 "H2O & Silica gel 123 via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a = 5.072313e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol") = 1.305531e2 * 1000 * M_adsorptive + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = -8.492403e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d = 4.128962e-3 / 1000 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & silica gel 123 using the Dubinin isotherm model with a Lorentzian +Cumulative characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGel123_DubininLorentzianCumulative_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel123_DubininLorentzianCumulative_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel123_DubininLorentzianCumulative_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c4d7e2fba79f8b1a9a8db94e223c8e9600bae832 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel123_DubininLorentzianCumulative_Schawe2000/package.order @@ -0,0 +1,6 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel125_DubininLorentzianCumulative_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel125_DubininLorentzianCumulative_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..fa3cf01c2a31b77f07a9562aa8df8858ee6e9e9a --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel125_DubininLorentzianCumulative_Schawe2000/package.mo @@ -0,0 +1,106 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package SilicaGel125_DubininLorentzianCumulative_Schawe2000 "H2O & Silica gel 125 via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a = 4.527805e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol") = 1.229005e2 * 1000 * M_adsorptive + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = -8.847167e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d = 6.034706e-4 / 1000 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & silica gel 125 using the Dubinin isotherm model with a Lorentzian +Cumulative characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGel125_DubininLorentzianCumulative_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel125_DubininLorentzianCumulative_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel125_DubininLorentzianCumulative_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c4d7e2fba79f8b1a9a8db94e223c8e9600bae832 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel125_DubininLorentzianCumulative_Schawe2000/package.order @@ -0,0 +1,6 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelAF25_DubininLorentzianCumulative_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelAF25_DubininLorentzianCumulative_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e41c34f8e23ba5a9cacdf595c005b78e6f595a65 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelAF25_DubininLorentzianCumulative_Schawe2000/package.mo @@ -0,0 +1,108 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package SilicaGelAF25_DubininLorentzianCumulative_Schawe2000 "H2O & Silica gel AF-25 via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel ( + v_constant=1/600, + lambda_constant=0.2)); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a = 6.452704e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol") = 8.979911e1 * 1000 * M_adsorptive + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = -7.845557e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d = 0 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & silica gel AF-25 using the Dubinin isotherm model with a Lorentzian +Cumulative characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelAF25_DubininLorentzianCumulative_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelAF25_DubininLorentzianCumulative_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelAF25_DubininLorentzianCumulative_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c4d7e2fba79f8b1a9a8db94e223c8e9600bae832 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelAF25_DubininLorentzianCumulative_Schawe2000/package.order @@ -0,0 +1,6 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelFuji_DubininLorentzianCumulative_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelFuji_DubininLorentzianCumulative_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..0d764ec05752ff6ce2c29b42ce4fabcbefbfc8eb --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelFuji_DubininLorentzianCumulative_Schawe2000/package.mo @@ -0,0 +1,106 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package SilicaGelFuji_DubininLorentzianCumulative_Schawe2000 "H2O & Silica gel Fuji via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a = 3.857567e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol") = 1.262497e2 * 1000 * M_adsorptive + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = -9.919397e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d = 0 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & silica gel Fuji using the Dubinin isotherm model with a Lorentzian +Cumulative characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelFuji_DubininLorentzianCumulative_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelFuji_DubininLorentzianCumulative_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelFuji_DubininLorentzianCumulative_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c4d7e2fba79f8b1a9a8db94e223c8e9600bae832 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelFuji_DubininLorentzianCumulative_Schawe2000/package.order @@ -0,0 +1,6 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelH_DubininPearsonIV_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelH_DubininPearsonIV_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..00d9b479214f55090f32d94822ef87e979ed14e0 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelH_DubininPearsonIV_Schawe2000/package.mo @@ -0,0 +1,121 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package SilicaGelH_DubininPearsonIV_Schawe2000 "H2O & Silica gel H via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=8, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel ( + v_constant=1/700, + lambda_constant=0.2)); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a(min=-1) = -2.243367e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol")=7.354090e-1 / 1000 + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = 1.044776e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d= + 3.678460e1 * 1000 * M_adsorptive + "Fourth contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_e= 7.419258e-2 + "Fivth contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_f= 2.927265e-1 + "Sixth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + dc_dT[7] :=0; + dc_dT[8] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + ddc_dT_dT[7] :=0; + ddc_dT_dT[8] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & silica gel H using the Dubinin isotherm model with a Pearson +IV characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelH_DubininPearsonIV_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelH_DubininPearsonIV_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelH_DubininPearsonIV_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..58ce5c48bd62836acde869b820f9cb1bbcff3237 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelH_DubininPearsonIV_Schawe2000/package.order @@ -0,0 +1,8 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +char_curve_e +char_curve_f +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelLE32_DubininPearsonIV_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelLE32_DubininPearsonIV_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b64596a8bfa09387599c3a76675b9ca6a8d88ccb --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelLE32_DubininPearsonIV_Schawe2000/package.mo @@ -0,0 +1,121 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package SilicaGelLE32_DubininPearsonIV_Schawe2000 "H2O & Silica gel LE-32 via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=8, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel ( + v_constant=1/700, + lambda_constant=0.2)); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a(min=-1) = -1.044288e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol")=7.154669e-1 / 1000 + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = -2.345348e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d= + 3.327467e1 * 1000 * M_adsorptive + "Fourth contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_e= 1.201645e-1 + "Fivth contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_f= 5.058059e-1 + "Sixth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + dc_dT[7] :=0; + dc_dT[8] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + ddc_dT_dT[7] :=0; + ddc_dT_dT[8] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & silica gel LE-32 using the Dubinin isotherm model with a Pearson +IV characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelLE32_DubininPearsonIV_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelLE32_DubininPearsonIV_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelLE32_DubininPearsonIV_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..58ce5c48bd62836acde869b820f9cb1bbcff3237 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelLE32_DubininPearsonIV_Schawe2000/package.order @@ -0,0 +1,8 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +char_curve_e +char_curve_f +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelNAC_DubininEmpirical1_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelNAC_DubininEmpirical1_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..74ce2f410c3b98e7f83415c40b0f4273a6e515d4 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelNAC_DubininEmpirical1_Schawe2000/package.mo @@ -0,0 +1,106 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package SilicaGelNAC_DubininEmpirical1_Schawe2000 "H2O & Silica gel NAC via the Dubinin isotherm model with an empirical 1 approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical1, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a = 3.570644 * 1000 + "First contants of the isotherm model"; + constant Real char_curve_b=8.569149e-6 * 1000 * (1 / 1000 / M_adsorptive)^2 + "Second contants of the isotherm model"; + constant Real char_curve_c = 1 / 1000 / M_adsorptive + "Third contants of the isotherm model"; + constant Real char_curve_d=9.597209e-8 * 1000 * (1 / 1000 / M_adsorptive)^3 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & silica gel NAC using the Dubinin isotherm model with an empirical1 +characteristic curve according to Schawe (2000). Packages that inherit properties +from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelNAC_DubininEmpirical1_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelNAC_DubininEmpirical1_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelNAC_DubininEmpirical1_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c4d7e2fba79f8b1a9a8db94e223c8e9600bae832 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelNAC_DubininEmpirical1_Schawe2000/package.order @@ -0,0 +1,6 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelN_DubininPearsonIV_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelN_DubininPearsonIV_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e8157a3267cce7d3123313c3a64d6bf658ed2049 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelN_DubininPearsonIV_Schawe2000/package.mo @@ -0,0 +1,119 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package SilicaGelN_DubininPearsonIV_Schawe2000 "H2O & Silica gel N via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=8, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel(lambda_constant=0.2)); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a(min=-1) = -7.689279e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol")=1.176831 / 1000 + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = 1.485965e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d= + 4.244922e1 * 1000 * M_adsorptive + "Fourth contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_e= 2.207797e-2 + "Fivth contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_f= 1.146067e-1 + "Sixth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + dc_dT[7] :=0; + dc_dT[8] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + ddc_dT_dT[7] :=0; + ddc_dT_dT[8] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & silica gel N using the Dubinin isotherm model with a Pearson IV +characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelN_DubininPearsonIV_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelN_DubininPearsonIV_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelN_DubininPearsonIV_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..58ce5c48bd62836acde869b820f9cb1bbcff3237 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelN_DubininPearsonIV_Schawe2000/package.order @@ -0,0 +1,8 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +char_curve_e +char_curve_f +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelWS_DubininLorentzianCumulative_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelWS_DubininLorentzianCumulative_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..7414d2d773757a7d80b8ea31f7bf3f25b513ee21 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelWS_DubininLorentzianCumulative_Schawe2000/package.mo @@ -0,0 +1,106 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package SilicaGelWS_DubininLorentzianCumulative_Schawe2000 "H2O & Silica gel WS via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=6, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininLorentzianCumulative, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel(lambda_constant=0.2)); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a = 5.046468e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol") = 1.002140e2 * 1000 * M_adsorptive + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = -7.264229e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d = 0 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & silica gel WS using the Dubinin isotherm model with a Lorentzian +Cumulative characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelWS_DubininLorentzianCumulative_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelWS_DubininLorentzianCumulative_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelWS_DubininLorentzianCumulative_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c4d7e2fba79f8b1a9a8db94e223c8e9600bae832 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGelWS_DubininLorentzianCumulative_Schawe2000/package.order @@ -0,0 +1,6 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..716de8a1b5e66b1020564c9df9edf065079305e2 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009/package.mo @@ -0,0 +1,131 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package SilicaGel_Toth_WangDouglasLeVan2009 "H2O & silica gel via the Toth isotherm model according to Wang and Douglas LeVan (2009)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=18.0153/1000, + twoPhaseAdsorptive=false, + final no_coefficients=3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake x_sat = 1.767e-1 / b_ref * M_adsorptive + "First contants of the isotherm model"; + constant Real b_ref(unit="1/Pa") = 2.787e-8 + "Second contants of the isotherm model"; + constant Real E(unit="K") = 1.093e3 + "Third contants of the isotherm model"; + constant Real t(unit="1") = -1.190e-3 + "Fourth contants of the isotherm model"; + constant Real alpha(unit="1/K") = 2.213e1 + "Fivth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] :=0; + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + dc_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] :=0; + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + ddc_dT_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddlinear1_dT_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & silica gel using the Toth isotherm model according to Wang +and Douglas LeVan (2010). Packages that inherit properties from this partial +package may redeclare the package <i>MediumSpecificFunctions</i>, the model +<i>Sorbent</i>, and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGel_Toth_WangDouglasLeVan2009; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e5bc23d0fbc2696b31b46df77da6ed02ab280ccf --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009/package.order @@ -0,0 +1,7 @@ +x_sat +b_ref +E +t +alpha +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Sizeo15_DubininPearsonIV_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Sizeo15_DubininPearsonIV_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9116d14e00a510a5a330a575c4aa3155bd0274a8 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Sizeo15_DubininPearsonIV_Schawe2000/package.mo @@ -0,0 +1,119 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package Sizeo15_DubininPearsonIV_Schawe2000 "H2O & Sizeo 15 via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=8, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininPearsonIV, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.RDSilicaGel(v_constant=1/660)); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a(min=-1) = -5.798998e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b(unit="J/mol")=9.685636e-1 / 1000 + "Second contants of the isotherm model"; + constant Real char_curve_c(unit="J/mol") = 1.313229e1 * 1000 * M_adsorptive + "Third contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_d= + 3.586237e1 * 1000 * M_adsorptive + "Fourth contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_e= 3.214072e-2 + "Fivth contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_f= 1.179455e-1 + "Sixth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + dc_dT[7] :=0; + dc_dT[8] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + ddc_dT_dT[7] :=0; + ddc_dT_dT[8] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & Sizeo 15 using the Dubinin isotherm model with a Pearson IV +characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Sizeo15_DubininPearsonIV_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Sizeo15_DubininPearsonIV_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Sizeo15_DubininPearsonIV_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..58ce5c48bd62836acde869b820f9cb1bbcff3237 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Sizeo15_DubininPearsonIV_Schawe2000/package.order @@ -0,0 +1,8 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +char_curve_e +char_curve_f +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_DubininEmpirical2_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_DubininEmpirical2_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c9f47a5b749ab3cc3e79892ecddfd2d8ef452829 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_DubininEmpirical2_Schawe2000/package.mo @@ -0,0 +1,134 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package Zeolith13X_DubininEmpirical2_Schawe2000 "H2O & Zeolith 13X via the Dubinin isotherm model with an empirical 2 approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=9, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.GenericSorbent ( + v_constant=1/670, + c_constant=920, + lambda_constant=0.085)); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a= + 3.083531e-1 / 1000 + "First contants of the isotherm model"; + constant Real char_curve_b= + -5.415506e-2 * sqrt(1 / 1000 / M_adsorptive) + "Second contants of the isotherm model"; + constant Real char_curve_c= + -1.969937e-2 / 1000 * sqrt(1 / 1000 / M_adsorptive) + "Third contants of the isotherm model"; + constant Real char_curve_d= + 8.174501e-4 / 1000 / M_adsorptive + "Fourth contants of the isotherm model"; + constant Real char_curve_e= + 4.362905e-4 / 1000 / 1000 / M_adsorptive + "Fivth contants of the isotherm model"; + constant Real char_curve_f= + 2.339058e-6 / 1000 / M_adsorptive * sqrt(1 / 1000 / M_adsorptive) + "Sixth contants of the isotherm model"; + constant Real char_curve_g= + -3.199002e-6 / 1000 / 1000 / M_adsorptive * sqrt(1 / 1000 / M_adsorptive) + "Seventh contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + c[9] :=char_curve_g; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + c[9] :=char_curve_g; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + dc_dT[7] :=0; + dc_dT[8] :=0; + dc_dT[9] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + ddc_dT_dT[7] :=0; + ddc_dT_dT[8] :=0; + ddc_dT_dT[9] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & Zeolith 13X using the Dubinin isotherm model with an empirical 2 +characteristic curve according to Schawe (2000). Packages that inherit +properties from this partial package may redeclare the package <i>MediumSpecificFunctions</i> +and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_DubininEmpirical2_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_DubininEmpirical2_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_DubininEmpirical2_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..85e413706c5d9574d9e7db8066ff2afc3d69e58d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_DubininEmpirical2_Schawe2000/package.order @@ -0,0 +1,9 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +char_curve_e +char_curve_f +char_curve_g +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d95e884e79b2a3a9b1cb61f7d96e4baced75a01b --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010/package.mo @@ -0,0 +1,134 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package Zeolith13X_Toth_WangDouglasLeVan2010 "H2O & Zeolith 13X via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=18.0153/1000, + twoPhaseAdsorptive=false, + final no_coefficients=3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake x_sat = 3.634e-9 / b_ref * M_adsorptive + "First contants of the isotherm model"; + constant Real b_ref(unit="1/Pa") = 2.408e-10 + "Second contants of the isotherm model"; + constant Real E(unit="K") = 6.852e3 + "Third contants of the isotherm model"; + constant Real t(unit="1") = 3.974e-1 + "Fourth contants of the isotherm model"; + constant Real alpha(unit="1/K") = -4.199 + "Fivth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] :=0; + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + dc_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] :=0; + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + ddc_dT_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddlinear1_dT_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & Zeolith 13X using the Toth isotherm model according to Wang +and Douglas LeVan (2010). Packages that inherit properties from this partial +package may redeclare the package <i>MediumSpecificFunctions</i>, the model +<i>Sorbent</i>, and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> + <li> + Wang, Y. and Douglas LeVan, M. (2010). Adsorption Equilibrium of Binary Mixtures of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X, Hournal of Chemical & Engineering Data, 55(9):3189–3195. DOI: https://doi.org/10.1021/je100053g. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_Toth_WangDouglasLeVan2010; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e5bc23d0fbc2696b31b46df77da6ed02ab280ccf --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010/package.order @@ -0,0 +1,7 @@ +x_sat +b_ref +E +t +alpha +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d7d79af9bba99700a62b9a5b595dfb15b4b7519b --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010/package.mo @@ -0,0 +1,134 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package Zeolith5A_Toth_WangDouglasLeVan2010 "H2O & Zeolith 5A via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=18.0153/1000, + twoPhaseAdsorptive=false, + final no_coefficients=3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake x_sat = 1.106e-11 / b_ref * M_adsorptive + "First contants of the isotherm model"; + constant Real b_ref(unit="1/Pa") = 4.714e-13 + "Second contants of the isotherm model"; + constant Real E(unit="K") = 9.955e3 + "Third contants of the isotherm model"; + constant Real t(unit="1") = 3.548e-1 + "Fourth contants of the isotherm model"; + constant Real alpha(unit="1/K") = -5.114e1 + "Fivth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + c[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] :=0; + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + dc_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] :=0; + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=E); + ddc_dT_dT[3] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddlinear1_dT_dT( + T=T_adsorpt, + a=t, + b=0, + c=alpha, + d=1); + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & Zeolith 5A using the Toth isotherm model according to Wang +and Douglas LeVan (2010). Packages that inherit properties from this partial +package may redeclare the package <i>MediumSpecificFunctions</i>, the model +<i>Sorbent</i>, and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> + <li> + Wang, Y. and Douglas LeVan, M. (2010). Adsorption Equilibrium of Binary Mixtures of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X, Hournal of Chemical & Engineering Data, 55(9):3189–3195. DOI: https://doi.org/10.1021/je100053g. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith5A_Toth_WangDouglasLeVan2010; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e5bc23d0fbc2696b31b46df77da6ed02ab280ccf --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010/package.order @@ -0,0 +1,7 @@ +x_sat +b_ref +E +t +alpha +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/ZeolithTypeA_DubininChebyshevSeries33_Schawe2000/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/ZeolithTypeA_DubininChebyshevSeries33_Schawe2000/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b99299ed609259e6fcc321d1bea0c7fb086e9d46 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/ZeolithTypeA_DubininChebyshevSeries33_Schawe2000/package.mo @@ -0,0 +1,148 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O; +package ZeolithTypeA_DubininChebyshevSeries33_Schawe2000 "H2O & Type A via the Dubinin isotherm model with a Chebyshev series rational order 3/3 approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationDubinin( + final M_adsorptive=18.0153/1000, + final no_coefficients=11, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.DubininEmpirical2, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE, + redeclare replaceable model Sorbent = + SorpLib.Media.Solids.Sorbents.GenericSorbent ( + v_constant=1/740, + c_constant=920, + lambda_constant=0.085)); + + // + // Definition of further constants + // + constant SorpLib.Units.FilledPoreVolume char_curve_a= + 3.472616e-2 / 100 + "First contants of the isotherm model"; + constant Real char_curve_b= + 1.322831 + "Second contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_c= + 9.401171e-3 / 1000 + "Third contants of the isotherm model"; + constant Real char_curve_d= + 5.760414e-1 + "Fourth contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_e= + 1.350676e-3 / 1000 + "Fivth contants of the isotherm model"; + constant Real char_curve_f= + 1.313913e-1 + "Sixth contants of the isotherm model"; + constant SorpLib.Units.FilledPoreVolume char_curve_g(min=-1)= + -1.926730e-4 / 1000 + "Seventh contants of the isotherm model"; + constant SorpLib.Units.MolarAdsorptionPotential char_curve_h= + 1061.930 * 1000 * M_adsorptive + "Eigth contants of the isotherm model"; + constant SorpLib.Units.MolarAdsorptionPotential char_curve_i= + 1065.595 * 1000 * M_adsorptive + "Ninth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := MediumSpecificFunctions.p_sat_T( + T=T_adsorpt); + c[2] := MediumSpecificFunctions.rho_satLiq_T( + T=T_adsorpt); + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + c[9] :=char_curve_g; + c[10] :=char_curve_h; + c[11] :=char_curve_i; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Get medium-specific functions (p_sat, rho_satLiq, and their partial + // derivatives w.r.t. temperature) + // + (c[1],dc_dT[1],ddc_dT_dT[1],c[2],dc_dT[2],ddc_dT_dT[2]) := + MediumSpecificFunctions.pRho_satLiq(T=T_adsorpt, dT=dT) + "Calculates saturated vapor pressure, density and bubble point, and their + first- and secon-order partial derivatives w.r.t. temperature)"; + + // + // Calculate further coefficients + // + c[3] :=char_curve_a; + c[4] :=char_curve_b; + c[5] :=char_curve_c; + c[6] :=char_curve_d; + c[7] :=char_curve_e; + c[8] :=char_curve_f; + c[9] :=char_curve_g; + c[10] :=char_curve_h; + c[11] :=char_curve_i; + + // + // Calculate further partial derivatives of the coefficients w.r.t. + // temperature + // + dc_dT[3] :=0; + dc_dT[4] :=0; + dc_dT[5] :=0; + dc_dT[6] :=0; + dc_dT[7] :=0; + dc_dT[8] :=0; + dc_dT[9] :=0; + dc_dT[10] :=0; + dc_dT[11] :=0; + + // + // Calculate further second-order partial derivatives of the coefficients + // w.r.t. temperature + // + ddc_dT_dT[3] :=0; + ddc_dT_dT[4] :=0; + ddc_dT_dT[5] :=0; + ddc_dT_dT[6] :=0; + ddc_dT_dT[7] :=0; + ddc_dT_dT[8] :=0; + ddc_dT_dT[9] :=0; + ddc_dT_dT[10] :=0; + ddc_dT_dT[11] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +H<sub>2</sub>0 & Zeolith Type A using the Dubinin isotherm model with a Chebyshev +series rational order 3/3 characteristic curve according to Schawe (2000). Packages +that inherit properties from this partial package may redeclare the package +<i>MediumSpecificFunctions</i> and the model <i>Sorbent</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ZeolithTypeA_DubininChebyshevSeries33_Schawe2000; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/ZeolithTypeA_DubininChebyshevSeries33_Schawe2000/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/ZeolithTypeA_DubininChebyshevSeries33_Schawe2000/package.order new file mode 100644 index 0000000000000000000000000000000000000000..97dd261b8cc881de7a58735f0676389d045ef8e9 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/ZeolithTypeA_DubininChebyshevSeries33_Schawe2000/package.order @@ -0,0 +1,11 @@ +char_curve_a +char_curve_b +char_curve_c +char_curve_d +char_curve_e +char_curve_f +char_curve_g +char_curve_h +char_curve_i +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..3e7c08657538aa67de59dcb9b8d387f7427271b5 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents; +package H2O "Package containing parametrizations for H2O as adsorptive" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrizations for H<sub>2</sub>O as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end H2O; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/package.order new file mode 100644 index 0000000000000000000000000000000000000000..543f6edc509e269384a78936eb87c674aaa4b05a --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/H2O/package.order @@ -0,0 +1,19 @@ +AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017 +AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017 +AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017 +NaZeolithY_DubininEmpirical2_Schawe2000 +SilicaGel_Toth_WangDouglasLeVan2009 +SilicaGel123_DubininLorentzianCumulative_Schawe2000 +SilicaGelAF25_DubininLorentzianCumulative_Schawe2000 +SilicaGel125_DubininLorentzianCumulative_Schawe2000 +SilicaGelFuji_DubininLorentzianCumulative_Schawe2000 +SilicaGelH_DubininPearsonIV_Schawe2000 +SilicaGelLE32_DubininPearsonIV_Schawe2000 +SilicaGelNAC_DubininEmpirical1_Schawe2000 +SilicaGelN_DubininPearsonIV_Schawe2000 +SilicaGelWS_DubininLorentzianCumulative_Schawe2000 +Sizeo15_DubininPearsonIV_Schawe2000 +Zeolith5A_Toth_WangDouglasLeVan2010 +Zeolith13X_DubininEmpirical2_Schawe2000 +Zeolith13X_Toth_WangDouglasLeVan2010 +ZeolithTypeA_DubininChebyshevSeries33_Schawe2000 diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/Gas/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/Gas/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..36677ce00da5af52e90ba6be4797123f436f0f69 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/Gas/package.mo @@ -0,0 +1,340 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions; +package Gas "Medium-specific functions using a fluid with just one regime (i.e., gas/vapor)" + + // + // Definition of replaceable medium package: This is required to have access to + // functions that change with the selected medium. + // + replaceable package Medium = Modelica.Media.IdealGases.SingleGases.H2O + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Medium"), + choicesAllMatching = true); + // + // Inherit from base class and finalize it + // + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureMediumSpecificFunctions; + + // + // Redeclare models + // + redeclare final model extends AdsorptiveProperties + "Calculates all properties of the adsorptive at gas/vapor phase required for the working pair model at once" + + // + // Definition of state records + // +protected + Medium.ThermodynamicState state + "Thermodynamic properties at p and T or at p_sat(T) and T"; + + equation + // + // Calculate state records + // + if adsorptiveAtDewPoint or + require_dp_sat_dT or + require_rho_satLiq_T or + require_drho_satLiq_dT or + require_h_adsorptiveToLiquid or + require_cp_satLiq_T or + require_dh_adsorptiveToLiquid_dp_T or + require_dh_adsorptiveToLiquid_dT_p or + require_ddrho_satLiq_dT_dT or + (adsorptiveAtDewPoint and require_dv_adsorptive_dT_p) then + assert(false, + "Selected adsorptive medium model does not have a two-phase regime. " + + "Cannot calculate state properties of bubble or dew point at T_adsorpt." + + "Thus, the specific volume or heat capacity of the adsorpt at the bubble " + + "point can also not be calculated.", + level = AssertionLevel.error); + end if; + + state = Medium.setState_pTX(p=p, T=T, X=Medium.reference_X) + "Thermodynamic properties at p and T or at p_sat(T) and T"; + + // + // State variables + // + v = 1/Medium.density(state=state) + "Specific volume"; + + if calcCaloricProperties then + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + u = h - p*v + "Specific internal energy"; + + else + h = 0 + "Specific enthalpy"; + u = 0 + "Specific internal energy"; + + end if; + + if calcCaloricProperties and calcEntropicProperties then + s = Medium.specificEntropy(state=state) + "Specific entropy"; + g = h - T*s + "Free enthalpy (i.e., Gibbs free energy)"; + a = u - T*s + "Free energy (i.e., Helmholts free energy)"; + + else + s = 0 + "Specific entropy"; + g = 0 + "Free enthalpy (i.e., Gibbs free energy)"; + a = 0 + "Free energy (i.e., Helmholts free energy)"; + + end if; + + // + // Additional properties of the one-phase regime + // + cp = if not require_cp_adsorptive then 0 else + Medium.specificHeatCapacityCp(state=state) + "Specific heat capacity"; + + // + // Additional properties of the two-phase regime + // + p_sat = 0 + "Saturated vapor pressure"; + v_satLiq = 0 + "Specific volume at the bubble point at given temperature"; + + h_adsorptiveToLiquid = 0 + "Specific enthalpy of vaporization"; + + cp_satLiq = 0 + "Specific heat capacity at the bubble point at given temeprature"; + + // + // Partial derivatives of the one-phase regime + // + dv_dp_T = if not require_dv_adsorptive_dp_T then 0 else + (1/Medium.density_pTX(p=p + dp, T=T, X=Medium.reference_X) - + 1/Medium.density_pTX(p=p - dp, T=T, X=Medium.reference_X))/(2*dp) + "Partial derivative of the specific volume w.r.t. pressure at constant + temperature"; + + dv_dT_p = if not require_dv_adsorptive_dT_p then 0 else + (1/Medium.density_pTX(p=p, T=T + dT, X=Medium.reference_X) - + 1/Medium.density_pTX(p=p, T=T - dT, X=Medium.reference_X))/(2*dT) + "Partial derivative of the specific volume w.r.t. temperature at constant + pressure"; + + // + // Partial derivatives of the two-phase regime + // + dp_sat_dT = 0 + "Partial derivative of saturated vapor pressure w.r.t. temperature"; + + dv_satLiq_dT = 0 + "Partial derivative of the specific volume at the bubble point at given + temperature w.r.t. temperature"; + ddv_satLiq_dT_dT = 0 + "Second-order partial derivative of the specific volume at the bubble point + at given temperature w.r.t. temperature"; + + dh_adsorptiveToLiquid_dp_T = 0 + "Partial derivative of specific enthalpy of vaporization w.r.t. pressure + at constant temperature"; + dh_adsorptiveToLiquid_dT_p = 0 + "Partial derivative of specific enthalpy of vaporization w.r.t. pressure + at constant temperature"; + end AdsorptiveProperties; + // + // Redeclare functions of the two-phase regime + // + redeclare final function extends p_sat_T + "Calculates the vapor pressure as function of temperature (i.e., not supported)" + algorithm + p_sat :=0 + "Saturated vapor pressure: Dummy value"; + end p_sat_T; + + redeclare final function extends rho_satLiq_T + "Calculates the density at the bubble point as function of temperature (i.e., not supported)" + algorithm + rho_satLiq:=0 + "Density at bubble point: Dummy value"; + end rho_satLiq_T; + + redeclare final function extends pRho_satLiq + "Calculates the vapor pressure, density at the bubble point, and their first- and second-order partial derivatives w.r.t. temperature (i.e., not supported)" + extends Modelica.Icons.Function; + algorithm + p_sat := 0 + "Saturated vapor pressure: Dummy value"; + dp_sat_dT:= 0 + "Partial derivative of the vapor pressure w.r.t. temperature: Dummy value"; + ddp_sat_dT_dT :=0 + "Calculates the second-order partial derivative of the vapor pressure w.r.t. + temperature: Dummy value"; + + rho_satLiq:=0 + "Density at bubble point: Dummy value"; + drho_satLiq_dT :=0 + "Calculates the partial derivative of the density at the bubble point w.r.t. + temperature: Dummy value"; + ddrho_satLiq_dT_dT:=0 + "Calculates the second-order partial derivative of the density at the bubble + point w.r.t. temperature: Dummy value"; + end pRho_satLiq; + // + // Functions of the one-phase regime + // + redeclare final function extends h_pT + "Calculates the specific enthalpy of the adsorptive as function of pressure + and temperature" + algorithm + h := if p > p_lb then + Medium.specificEnthalpy_pTX(p=p, T=T, X=Medium.reference_X) else + h_ref + (T - T_ref) * Medium.specificHeatCapacityCp(state= + Medium.setState_pTX(p=p_lb, T=T, X=Medium.reference_X)) + "Specific enthalpy"; + end h_pT; + + redeclare final function extends s_pT + "Calculates the specific entropy of the adsorptive as function of pressure + and temperature" + algorithm + s :=if p > p_lb then + Medium.specificEntropy_pTX(p=p, T=T, X=Medium.reference_X) else + s_ref - Modelica.Constants.R * log(p_lb / p_ref) + (T - T_ref) / T * + Medium.specificHeatCapacityCp(state= + Medium.setState_pTX(p=p_lb, T=T, X=Medium.reference_X)) + "Specific entropy"; + end s_pT; + // + // Functions calculating properties required for calculating the specific heat + // capacity of the adsorpt + // + redeclare final function extends calc_properties + "Calculates all properties of the adsorptive at gas/vapor phase required for the working pair model at once" + extends Modelica.Icons.Function; + + // + // Definition of state records + // +protected + Medium.ThermodynamicState state + "Thermodynamic properties at p and T"; + + algorithm + // + // Calculate state records + // + if adsorptiveAtDewPoint or require_h_adsorptiveToLiquid then + assert(false, + "Selected adsorptive medium model does not have a two-phase regime. " + + "Cannot calculate state properties of bubble or dew point at T_adsorpt.", + level = AssertionLevel.error); + end if; + + if require_v_adsorptive or + require_h_adsorptive or + require_dh_adsorptive_dT_dp or + require_s_adsorptive then + state := Medium.setState_pTX(p=max(p,p_min), T=T, X=Medium.reference_X) + "Thermodynamic properties at p and T"; + + end if; + + // + // Calculate specific volume + // + if require_v_adsorptive then + v := 1 / Medium.density(state=state) + "Specific volume"; + dv_dp_T := if p > p_min then + (1 / Medium.density_pTX(p=p+dp, T=T, X=Medium.reference_X) - + 1 / Medium.density_pTX(p=p-dp, T=T, X=Medium.reference_X)) / (2 * dp) else + (1 / Medium.density_pTX(p=p_min+dp, T=T, X=Medium.reference_X) - + 1 / Medium.density_pTX(p=p_min, T=T, X=Medium.reference_X)) / (2 * dp) + "Partial derivative of the specific volume w.r.t. pressure at constant + temperature"; + dv_dT_p := + (1 / Medium.density_pTX(p=max(p,p_min), T=T+dT, X=Medium.reference_X) - + 1 / Medium.density_pTX(p=max(p,p_min), T=T-dT, X=Medium.reference_X)) / + (2 * dT) + "Partial derivative of the specific volume w.r.t. temperature at constant + pressure"; + + else + v :=0 + "Specific volume"; + dv_dp_T :=0 + "Partial derivative of the specific volume w.r.t. pressure at constant + temperature"; + dv_dT_p :=0 + "Partial derivative of the specific volume w.r.t. temperature at constant + pressure"; + + end if; + + // + // Calculate specific enthalpy + // + h := if not require_h_adsorptive then 0 else + Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + dh_dT_p := if not require_dh_adsorptive_dT_dp then 0 else + Medium.specificHeatCapacityCp(state=state) + "Partial derivative of the specific enthalpy w.r.t. temperature at constant + pressure"; + + // + // Calculate specific enthalpy + // + s := if not require_s_adsorptive then 0 else s_pT( + p=p, + T=T, + p_lb=p_min, + s_ref=Medium.specificEntropy(state=state), + p_ref=p_min, + T_ref=T) + "Specific entropy"; + + // + // Calculate specific enthalpy difference between adsorptive phase and bubble + // phase: Cannot be calculated for ideal gas, so set dummy values + // + h_atl :=0 + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + dh_atl_dp :=0 + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + dh_atl_dT :=0 + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + end calc_properties; + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This package provides media-specific functions for a fluid with just one regime, +i.e., the gas or vapor phase. Thus, this fluid does not support functions of +the two-phase regime and cannot be used for isotherm models based on the model +of Dubinin. +</p> +</html>")); +end Gas; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/Gas/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/Gas/package.order new file mode 100644 index 0000000000000000000000000000000000000000..1ae20c0f29d346b9ac813f4770d568cfea5fbc6a --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/Gas/package.order @@ -0,0 +1,8 @@ +Medium +AdsorptiveProperties +p_sat_T +rho_satLiq_T +pRho_satLiq +h_pT +s_pT +calc_properties diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/VLE/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/VLE/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f6d5f898723e91eacdad7d63c5f29a9ee83e2a75 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/VLE/package.mo @@ -0,0 +1,502 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions; +package VLE "Medium-specific functions using a real fluid with a two-phase regime" + + // + // Definition of replaceable medium package: This is required to have access to + // functions that change with the selected medium. + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Medium"), + choicesAllMatching = true); + // + // Inherit from base class and finalize it + // + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureMediumSpecificFunctions; + + // + // Redeclare models + // + redeclare final model extends AdsorptiveProperties + "Calculates all properties of the adsorptive at gas/vapor phase required for the working pair model at once" + + // + // Definition of state records + // +protected + Medium.SaturationProperties sat_T + "Saturated state properties at T"; + Medium.SaturationProperties sat_T_pdT + "Saturated state properties at T + dT"; + Medium.SaturationProperties sat_T_mdT + "Saturated state properties at T - dT"; + + Medium.ThermodynamicState state + "Thermodynamic properties at p and T or at p_sat(T) and T"; + Medium.ThermodynamicState state_bubble + "Thermodynamic properties at bubble point calculated with T"; + + equation + // + // Calculate state records + // + if adsorptiveAtDewPoint or + require_dp_sat_dT or + require_rho_satLiq_T or + require_drho_satLiq_dT or + require_h_adsorptiveToLiquid or + require_cp_satLiq_T then + sat_T = Medium.setSat_T(T=T) + "Saturated state properties at T"; + + else + sat_T = Medium.setSat_T(T=Medium.reference_T) + "Saturated state properties at reference temperature"; + + end if; + + if require_ddrho_satLiq_dT_dT or + (adsorptiveAtDewPoint and require_dv_adsorptive_dT_p) then + sat_T_pdT = Medium.setSat_T(T=T + dT) + "Saturated state properties at T + dT"; + sat_T_mdT = Medium.setSat_T(T=T - dT) + "Saturated state properties at T - dT"; + + else + sat_T_pdT = Medium.setSat_T(T=Medium.reference_T) + "Saturated state properties at reference temperature"; + sat_T_mdT = Medium.setSat_T(T=Medium.reference_T) + "Saturated state properties at reference temperature"; + + end if; + + state = if adsorptiveAtDewPoint then Medium.setDewState(sat=sat_T) else + Medium.setState_pTX(p=p, T=T, X=Medium.reference_X) + "Thermodynamic properties at p and T or at p_sat(T) and T"; + + if require_h_adsorptiveToLiquid or + require_dh_adsorptiveToLiquid_dT_p or + require_cp_satLiq_T then + state_bubble = Medium.setBubbleState(sat=sat_T) + "Thermodynamic properties at bubble point calculated with T"; + + else + state_bubble = Medium.setBubbleState(sat=sat_T) + "Thermodynamic properties at bubble point calculated at reference temperature"; + + end if; + + // + // State variables + // + // v = if adsorptiveAtDewPoint then 1/Medium.dewDensity(sat=sat_T) else + // 1/Medium.density(state=state) + // "Specific volume"; + v = 1/Medium.density(state=state) + "Specific volume"; + + if calcCaloricProperties then + // h = if adsorptiveAtDewPoint then Medium.dewEnthalpy(sat=sat_T) else + // Medium.specificEnthalpy(state=state) + // "Specific enthalpy"; + h = Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + u = h - p*v + "Specific internal energy"; + + else + h = 0 + "Specific enthalpy"; + u = 0 + "Specific internal energy"; + + end if; + + if calcCaloricProperties and calcEntropicProperties then + // s = if adsorptiveAtDewPoint then Medium.dewEntropy(sat=sat_T) else + // Medium.specificEntropy(state=state) + // "Specific entropy"; + s = Medium.specificEntropy(state=state) + "Specific entropy"; + g = h - T*s + "Free enthalpy (i.e., Gibbs free energy)"; + a = u - T*s + "Free energy (i.e., Helmholts free energy)"; + + else + s = 0 + "Specific entropy"; + g = 0 + "Free enthalpy (i.e., Gibbs free energy)"; + a = 0 + "Free energy (i.e., Helmholts free energy)"; + + end if; + + // + // Additional properties of the one-phase regime + // + cp = if not require_cp_adsorptive then 0 else + Medium.specificHeatCapacityCp(state=state) + "Specific heat capacity"; + + // + // Additional properties of the two-phase regime + // + p_sat = if not require_p_sat then 0 else + Medium.saturationPressure(T) + "Saturated vapor pressure"; + v_satLiq = if not require_rho_satLiq_T then 0 else + 1/Medium.bubbleDensity(sat=sat_T) + "Specific volume at the bubble point at given temperature"; + + h_adsorptiveToLiquid = if not require_h_adsorptiveToLiquid then 0 else + h - Medium.specificEnthalpy(state=state_bubble) + "Specific enthalpy of vaporization"; + + cp_satLiq = if not require_cp_satLiq_T then 0 else + Medium.specificHeatCapacityCp(state=state_bubble) + "Specific heat capacity at the bubble point at given temeprature"; + + // + // Partial derivatives of the one-phase regime + // + dv_dp_T = if not require_dv_adsorptive_dp_T then 0 else + (if adsorptiveAtDewPoint then 0 else + (1/Medium.density_pTX(p=p+dp, T=T, X=Medium.reference_X) - + 1/Medium.density_pTX(p=p-dp, T=T, X=Medium.reference_X))/(2*dp)) + "Partial derivative of the specific volume w.r.t. pressure at constant + temperature"; + + dv_dT_p = if not require_dv_adsorptive_dT_p then 0 else + (if adsorptiveAtDewPoint then + (1/Medium.dewDensity(sat=sat_T_pdT) - + 1 /Medium.dewDensity(sat=sat_T_mdT))/(2*dT) else + (1/Medium.density_pTX(p=p, T=T+dT, X=Medium.reference_X) - + 1/Medium.density_pTX(p=p, T=T-dT, X=Medium.reference_X))/(2*dT)) + "Partial derivative of the specific volume w.r.t. temperature at constant + pressure"; + + // + // Partial derivatives of the two-phase regime + // + dp_sat_dT = if not require_dp_sat_dT then 0 else + 1/Medium.saturationTemperature_derp_sat(sat=sat_T) + "Partial derivative of saturated vapor pressure w.r.t. temperature"; + + dv_satLiq_dT = if not require_drho_satLiq_dT then 0 else + -v_satLiq^2*Medium.dBubbleDensity_dPressure(sat=sat_T)* dp_sat_dT + "Partial derivative of the specific volume at the bubble point at given + temperature w.r.t. temperature"; + ddv_satLiq_dT_dT = if not require_ddrho_satLiq_dT_dT then 0 else + ((-Medium.dBubbleDensity_dPressure(sat=sat_T_pdT)/ + Medium.saturationTemperature_derp_sat(sat=sat_T_pdT)/Medium.bubbleDensity( + sat=sat_T_pdT)^2 + + Medium.dBubbleDensity_dPressure(sat=sat_T_mdT)/ + Medium.saturationTemperature_derp_sat(sat=sat_T_mdT)/Medium.bubbleDensity( + sat=sat_T_mdT)^2)/(2*dT)) + "Second-order partial derivative of the specific volume at the bubble point + at given temperature w.r.t. temperature"; + + dh_adsorptiveToLiquid_dp_T = if not require_dh_adsorptiveToLiquid_dp_T then 0 + else v * (1 - T * Medium.isobaricExpansionCoefficient(state=state)) - 0 + "Partial derivative of specific enthalpy of vaporization w.r.t. pressure + at constant temperature"; + dh_adsorptiveToLiquid_dT_p = if not require_dh_adsorptiveToLiquid_dT_p then 0 + else + Medium.specificHeatCapacityCp(state=state) - + Medium.specificHeatCapacityCp(state=state_bubble) + "Partial derivative of specific enthalpy of vaporization w.r.t. pressure + at constant temperature"; + end AdsorptiveProperties; + // + // Redeclare functions of the two-phase regime + // + redeclare final function extends p_sat_T + "Calculates the vapor pressure as function of temperature" + algorithm + p_sat :=Medium.saturationPressure(T) + "Saturated vapor pressure"; + end p_sat_T; + + redeclare final function extends rho_satLiq_T + "Calculates the density at the bubble point as function of temperature" + algorithm + rho_satLiq:=Medium.bubbleDensity(sat=Medium.setSat_T(T=T)) + "Density at bubble point"; + end rho_satLiq_T; + + redeclare final function extends pRho_satLiq + "Calculates the vapor pressure, density at the bubble point, and their first- and second-order partial derivatives w.r.t. temperature" + extends Modelica.Icons.Function; + + // + // Definition of variables + // +protected + Medium.SaturationProperties sat_T + "Saturated state properties at T"; + Medium.SaturationProperties sat_T_pdT + "Saturated state properties at T + dT"; + Medium.SaturationProperties sat_T_mdT + "Saturated state properties at T - dT"; + + algorithm + sat_T :=Medium.setSat_T(T=T) + "Saturated state properties at T"; + sat_T_pdT :=Medium.setSat_T(T=T + dT) + "Saturated state properties at T"; + sat_T_mdT :=Medium.setSat_T(T=T - dT) + "Saturated state properties at T"; + + p_sat := Medium.saturationPressure(T) + "Saturated vapor pressure"; + dp_sat_dT:= 1 / Medium.saturationTemperature_derp_sat(sat=sat_T) + "Partial derivative of the vapor pressure w.r.t. temperature"; + ddp_sat_dT_dT := + (1 / Medium.saturationTemperature_derp_sat(sat=sat_T_pdT) - + 1 / Medium.saturationTemperature_derp_sat(sat=sat_T_mdT)) / (2 * dT) + "Calculates the second-order partial derivative of the vapor pressure w.r.t. + temperature"; + + rho_satLiq:=Medium.bubbleDensity(sat=sat_T) + "Density at bubble point"; + drho_satLiq_dT :=Medium.dBubbleDensity_dPressure(sat=sat_T) * dp_sat_dT + "Calculates the partial derivative of the density at the bubble point w.r.t. + temperature"; + ddrho_satLiq_dT_dT:= + (Medium.dBubbleDensity_dPressure(sat=sat_T_pdT) / + Medium.saturationTemperature_derp_sat(sat=sat_T_pdT) - + Medium.dBubbleDensity_dPressure(sat=sat_T_mdT) / + Medium.saturationTemperature_derp_sat(sat=sat_T_mdT)) / (2 * dT) + "Calculates the second-order partial derivative of the density at the bubble + point w.r.t. temperature"; + end pRho_satLiq; + // + // Functions of the one-phase regime + // + redeclare final function extends h_pT + "Calculates the specific enthalpy of the adsorptive as function of pressure + and temperature" + algorithm + h := if p > p_lb then + Medium.specificEnthalpy_pTX(p=p, T=T, X=Medium.reference_X) else + h_ref + (T - T_ref) * Medium.specificHeatCapacityCp(state= + Medium.setState_pTX(p=p_lb, T=T, X=Medium.reference_X)) + "Specific enthalpy"; + end h_pT; + + redeclare final function extends s_pT + "Calculates the specific entropy of the adsorptive as function of pressure + and temperature" + algorithm + s :=if p > p_lb then + Medium.specificEntropy_pTX(p=p, T=T, X=Medium.reference_X) else + s_ref - Modelica.Constants.R * log(p_lb / p_ref) + (T - T_ref) / T * + Medium.specificHeatCapacityCp(state= + Medium.setState_pTX(p=p_lb, T=T, X=Medium.reference_X)) + "Specific entropy"; + end s_pT; + // + // Functions calculating properties required for calculating the specific heat + // capacity of the adsorpt + // + redeclare final function extends calc_properties + "Calculates all properties of the adsorptive at gas/vapor phase required for the working pair model at once" + extends Modelica.Icons.Function; + + // + // Definition of state records + // +protected + Medium.SaturationProperties sat_T + "Saturated state properties at T"; + Medium.SaturationProperties sat_T_pdT + "Saturated state properties at T + dT"; + Medium.SaturationProperties sat_T_mdT + "Saturated state properties at T - dT"; + + Medium.ThermodynamicState state + "Thermodynamic properties at p and T or at p_sat(T) and T"; + Medium.ThermodynamicState state_bubble + "Thermodynamic properties at bubble point calculated with T"; + + algorithm + // + // Calculate state records + // + if adsorptiveAtDewPoint and ( + require_v_adsorptive or + require_h_adsorptive or + require_dh_adsorptive_dT_dp or + require_s_adsorptive or + require_h_adsorptiveToLiquid) or + require_h_adsorptiveToLiquid then + sat_T :=Medium.setSat_T(T=T) + "Saturated state properties at T"; + end if; + + if adsorptiveAtDewPoint and + (require_v_adsorptive) then + sat_T_pdT :=Medium.setSat_T(T=T+dT) + "Saturated state properties at T + dT"; + sat_T_mdT :=Medium.setSat_T(T=T-dT) + "Saturated state properties at T - dT"; + end if; + + if require_v_adsorptive or + require_h_adsorptive or + require_dh_adsorptive_dT_dp or + require_s_adsorptive or + require_h_adsorptiveToLiquid then + state := if adsorptiveAtDewPoint then + Medium.setDewState(sat=sat_T) else + Medium.setState_pTX(p=max(p,p_min), T=T, X=Medium.reference_X) + "Thermodynamic properties at p and T or at p_sat(T) and T"; + end if; + + if require_h_adsorptiveToLiquid then + state_bubble := Medium.setBubbleState(sat=sat_T) + "Thermodynamic properties at bubble point calculated with T"; + end if; + + // + // Calculate specific volume + // + if require_h_adsorptiveToLiquid then + v := 1 / Medium.density(state=state) + "Specific volume"; + + elseif require_v_adsorptive then + // v := if adsorptiveAtDewPoint then 1 / Medium.dewDensity(sat=sat_T) else + // 1 / Medium.density_pTX(p=p, T=T, X=Medium.reference_X) + // "Specific volume"; + v := 1 / Medium.density(state=state) + "Specific volume"; + + else + v :=0 + "Specific volume"; + + end if; + + if require_v_adsorptive then + if adsorptiveAtDewPoint then + dv_dp_T :=0 + "Partial derivative of the specific volume w.r.t. pressure at constant + temperature: Corresponds to unity as dew state is determined by temperature"; + dv_dT_p := + (1 / Medium.dewDensity(sat=sat_T_pdT) - + 1 / Medium.dewDensity(sat=sat_T_mdT)) / (2 * dT) + "Partial derivative of the specific volume w.r.t. temperature at constant + pressure"; + + else + dv_dp_T := if p > p_min then + (1 / Medium.density_pTX(p=p+dp, T=T, X=Medium.reference_X) - + 1 / Medium.density_pTX(p=p-dp, T=T, X=Medium.reference_X)) / (2 * dp) else + (1 / Medium.density_pTX(p=p_min+dp, T=T, X=Medium.reference_X) - + 1 / Medium.density_pTX(p=p_min, T=T, X=Medium.reference_X)) / (2 * dp) + "Partial derivative of the specific volume w.r.t. pressure at constant + temperature"; + dv_dT_p := + (1 / Medium.density_pTX(p=max(p,p_min), T=T+dT, X=Medium.reference_X) - + 1 / Medium.density_pTX(p=max(p,p_min), T=T-dT, X=Medium.reference_X)) / + (2 * dT) + "Partial derivative of the specific volume w.r.t. temperature at constant + pressure"; + + end if; + + else + dv_dp_T :=0 + "Partial derivative of the specific volume w.r.t. pressure at constant + temperature"; + dv_dT_p :=0 + "Partial derivative of the specific volume w.r.t. temperature at constant + pressure"; + + end if; + + // + // Calculate specific enthalpy + // + h := if not require_h_adsorptive then 0 else + Medium.specificEnthalpy(state=state) + "Specific enthalpy"; + + dh_dT_p := if not require_dh_adsorptive_dT_dp then 0 else + Medium.specificHeatCapacityCp(state=state) + "Partial derivative of the specific enthalpy w.r.t. temperature at constant + pressure"; + + // + // Calculate specific enthalpy + // + s := if not require_s_adsorptive then 0 else s_pT( + p=p, + T=T, + p_lb=p_min, + s_ref=Medium.specificEntropy(state=state), + p_ref=p_min, + T_ref=T) + "Specific entropy"; + + // + // Calculate specific enthalpy difference between adsorptive phase and bubble phase + // + if require_h_adsorptiveToLiquid then + h_atl := + Medium.specificEnthalpy(state=state) - + Medium.specificEnthalpy(state=state_bubble) + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + dh_atl_dp := v * (1 - T * + Medium.isobaricExpansionCoefficient(state=state)) - 0 + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + dh_atl_dT := + Medium.specificHeatCapacityCp(state=state) - + Medium.specificHeatCapacityCp(state=state_bubble) + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + else + h_atl :=0 + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + dh_atl_dp :=0 + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + dh_atl_dT :=0 + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + end if; + + end calc_properties; + // + // Annotations + // + annotation (Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This package provides media-specific functions for a real fluid. The term +\"real\" is used to indicate that the fluid has a two-phase regime. Such fluids +are necessary, for example, when using the model of Dubinin as the isotherm +model. +</p> +</html>")); +end VLE; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/VLE/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/VLE/package.order new file mode 100644 index 0000000000000000000000000000000000000000..1ae20c0f29d346b9ac813f4770d568cfea5fbc6a --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/VLE/package.order @@ -0,0 +1,8 @@ +Medium +AdsorptiveProperties +p_sat_T +rho_satLiq_T +pRho_satLiq +h_pT +s_pT +calc_properties diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..f6f9f96f2784436830328fdae16a835e4dd0fc2b --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents; +package MediumSpecificFunctions "Package containing packages with medium-specific functions using the Modelica standard library" + extends Modelica.Icons.InternalPackage; + + annotation (Documentation(info="<html> +<p> +This package contains packages that provide media-specific functions. The +provided packages are required to fully parameterize working pair models. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end MediumSpecificFunctions; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/package.order new file mode 100644 index 0000000000000000000000000000000000000000..581a2dfb1d7015000c6ac859b35f0c6c93c2d6b5 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/MediumSpecificFunctions/package.order @@ -0,0 +1,2 @@ +Gas +VLE diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ActivatedCarbon_Toth_DantasEtAl2011/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ActivatedCarbon_Toth_DantasEtAl2011/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..74ff9518b8e57c3bd944df707d4b4eac09fe81c1 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ActivatedCarbon_Toth_DantasEtAl2011/package.mo @@ -0,0 +1,109 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.N2; +package ActivatedCarbon_Toth_DantasEtAl2011 "N2 & Activated carbon via the Toth isotherm model according to Dantas et al. (2011)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=28.0134/1000, + twoPhaseAdsorptive=false, + final no_coefficients=3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake x_sat = 9.74 * M_adsorptive + "First contants of the isotherm model"; + constant Real b_ref(unit="1/Pa") = 6.91e-5 / (1e5) + "Second contants of the isotherm model"; + constant Real Q_star(unit="K") = -16.31e3 / Modelica.Constants.R + "Third contants of the isotherm model"; + constant Real t(unit="1") = 0.518 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + c[3] :=t; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + c[3] :=t; + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] :=0; + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + dc_dT[3] :=0; + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] :=0; + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + ddc_dT_dT[3] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +N<sub>2</sub> & activated carbon using the Toth isotherm model according to Dantas +et al. (2011). Packages that inherit properties from this partial package may +redeclare the package <i>MediumSpecificFunctions</i>, the model <i>Sorbent</i>, +and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Dantas, T.L.P. and Luna, F.M.T. and Silva Jr., I.J. and Azevedo, D.C.S. and Grande, C.A. and Rodrigues, A.E. and Moreira, R.F.P.M. (2011). Carbon dioxide–nitrogen separation through adsorption on activated carbon in a fixed bed, Chemical Engineering Journal, 169:11–19. DOI: https://doi.org/10.1016/j.cej.2010.08.026. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ActivatedCarbon_Toth_DantasEtAl2011; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ActivatedCarbon_Toth_DantasEtAl2011/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ActivatedCarbon_Toth_DantasEtAl2011/package.order new file mode 100644 index 0000000000000000000000000000000000000000..99a9913827eacfcc8c8dd7798c68bd308b026919 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ActivatedCarbon_Toth_DantasEtAl2011/package.order @@ -0,0 +1,6 @@ +x_sat +b_ref +Q_star +t +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/Zeolith13X_Toth_DantasEtAl2011/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/Zeolith13X_Toth_DantasEtAl2011/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..bfca39445de82d43d8727fff420857868b373561 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/Zeolith13X_Toth_DantasEtAl2011/package.mo @@ -0,0 +1,109 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.N2; +package Zeolith13X_Toth_DantasEtAl2011 "N2 & Zeolith 13X via the Toth isotherm model according to Dantas et al. (2011)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=28.0134/1000, + twoPhaseAdsorptive=false, + final no_coefficients=3, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Toth, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake x_sat = 3.08 * M_adsorptive + "First contants of the isotherm model"; + constant Real b_ref(unit="1/Pa") = 0.882e-4 / (1e5) + "Second contants of the isotherm model"; + constant Real Q_star(unit="K") = -17.19e3 / Modelica.Constants.R + "Third contants of the isotherm model"; + constant Real t(unit="1") = 0.869 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + c[3] :=t; + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] :=x_sat; + c[2] :=SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + c[3] :=t; + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] :=0; + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + dc_dT[3] :=0; + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] :=0; + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=b_ref, + b=0, + c=0, + d=-Q_star); + ddc_dT_dT[3] :=0; + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +N<sub>2</sub> & Zeolith 13X using the Toth isotherm model according to Dantas +et al. (2011). Packages that inherit properties from this partial package may +redeclare the package <i>MediumSpecificFunctions</i>, the model <i>Sorbent</i>, +and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Dantas, T.L.P. and Luna, F.M.T. and Silva Jr., I.J. and Torres, A.E.B. and Azevedo, D.C.S. and Rodrigues, A.E. and Moreira, R.F.P.M. (2011). Carbon dioxide–nitrogen separation through pressure swing adsorption, Chemical Engineering Journal, 172:698-704. DOI: https://doi.org/10.1016/j.cej.2011.06.037. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_Toth_DantasEtAl2011; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/Zeolith13X_Toth_DantasEtAl2011/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/Zeolith13X_Toth_DantasEtAl2011/package.order new file mode 100644 index 0000000000000000000000000000000000000000..99a9913827eacfcc8c8dd7798c68bd308b026919 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/Zeolith13X_Toth_DantasEtAl2011/package.order @@ -0,0 +1,6 @@ +x_sat +b_ref +Q_star +t +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..e794af84397c9a76a47449508640d3d0bdd87107 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.mo @@ -0,0 +1,131 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.N2; +package ZeolithLiLSX_Langmuir_LiEtAl2021 "N2 & Zeolith LiLSX via the Langmuir isotherm model according to Li et al. (2021)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive=28.0134/1000, + twoPhaseAdsorptive=false, + final no_coefficients=2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake k1 = 7.488 * M_adsorptive + "First contants of the isotherm model"; + constant Real k2(unit="kg/(kg.K)") = -0.016 * M_adsorptive + "Second contants of the isotherm model"; + constant Real k3(unit="1/Pa") = 0.012 * 1e-5 + "Third contants of the isotherm model"; + constant Modelica.Units.SI.Temperature k4 = 1070.199 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=k1, + b=k2, + c=0, + d=1); + c[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=k3, + b=0, + c=0, + d=k4); + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=k1, + b=k2, + c=0, + d=1); + c[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=k3, + b=0, + c=0, + d=k4); + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T_adsorpt, + a=k1, + b=k2, + c=0, + d=1); + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=k3, + b=0, + c=0, + d=k4); + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddlinear1_dT_dT( + T=T_adsorpt, + a=k1, + b=k2, + c=0, + d=1); + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=k3, + b=0, + c=0, + d=k4); + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +N<sub>2</sub> & Zeolith LiLSX using the Langmuir isotherm model according to Li +et al. (2011). Packages that inherit properties from this partial package may +redeclare the package <i>MediumSpecificFunctions</i>, the model <i>Sorbent</i>, +and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Li, L., and Yu, M., and Zi, Y., and Dang, Y., and Wu, Q., and Wang, Z., and Xu, Y., and Yan, H, and Dang, Y. (2021). A Thermodynamic Model for Pure and Binary Adsorption Equilibria of N<sub>2</sub> and O<sub>2</sub> on Lithium-Exchanged Low Silicon-to-Aluminum Ratio X Zeolite, Journal of Chemical & Engineering Data, 60:1032-1042. DOI: https://dx.doi.org/10.1021/acs.jced.0c00830. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ZeolithLiLSX_Langmuir_LiEtAl2021; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bf326a650e73724c0e707690a2b84d7d42cdee0a --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.order @@ -0,0 +1,6 @@ +k1 +k2 +k3 +k4 +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c70de2d11dd713c53d6a8da994f4b84f670d5a88 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents; +package N2 "Package containing parametrizations for N2 as adsorptive" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrizations for N<sub>2</sub> as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end N2; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..9280fa782a449cbbb4c9a8362deb12663002125b --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/N2/package.order @@ -0,0 +1,3 @@ +ActivatedCarbon_Toth_DantasEtAl2011 +Zeolith13X_Toth_DantasEtAl2011 +ZeolithLiLSX_Langmuir_LiEtAl2021 diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..8d411b3df44586289dfb1c040e1c32b96e23bc5c --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.mo @@ -0,0 +1,131 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.O2; +package ZeolithLiLSX_Langmuir_LiEtAl2021 "O2 & Zeolith LiLSX via the Langmuir isotherm model according to Li et al. (2021)" + extends + SorpLib.Media.WorkingPairs.Interfaces.PartialPureParametrizationNonDubinin( + final M_adsorptive= 31.9988/1000, + twoPhaseAdsorptive=false, + final no_coefficients=2, + redeclare final package IsothermModel = + SorpLib.Media.Functions.SorptionEquilibria.PureComponents.Langmuir, + redeclare replaceable package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas); + + // + // Definition of further constants + // + constant SorpLib.Units.Uptake k1 = 33.947 * M_adsorptive + "First contants of the isotherm model"; + constant Real k2(unit="kg/(kg.K)") = -0.090 * M_adsorptive + "Second contants of the isotherm model"; + constant Real k3(unit="1/Pa") = 0.090 * 1e-5 + "Third contants of the isotherm model"; + constant Modelica.Units.SI.Temperature k4(min=-500) = -426.018 + "Fourth contants of the isotherm model"; + + // + // Redeclare functions + // + redeclare final function extends calc_c + "Calculates temperature-dependent coefficients of the isotherm model" + algorithm + c[1] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=k1, + b=k2, + c=0, + d=1); + c[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=k3, + b=0, + c=0, + d=k4); + end calc_c; + + redeclare final function extends calc_coefficients + "Calculates temperature-dependent coefficients and their the partial derivatives w.r.t. temperature" + algorithm + // + // Calculate coefficients + // + c[1] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T_adsorpt, + a=k1, + b=k2, + c=0, + d=1); + c[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T_adsorpt, + a=k3, + b=0, + c=0, + d=k4); + + // + // Calculate partial derivatives of the coefficients w.r.t. temperature + // + dc_dT[1] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T_adsorpt, + a=k1, + b=k2, + c=0, + d=1); + dc_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T_adsorpt, + a=k3, + b=0, + c=0, + d=k4); + + // + // Calculate second-order partial derivatives of the coefficients w.r.t. + // temperature + // + ddc_dT_dT[1] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddlinear1_dT_dT( + T=T_adsorpt, + a=k1, + b=k2, + c=0, + d=1); + ddc_dT_dT[2] := + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T_adsorpt, + a=k3, + b=0, + c=0, + d=k4); + end calc_coefficients; + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This partial package describes the adsorption equilibrium of the working pair +O<sub>2</sub> & Zeolith LiLSX using the Langmuir isotherm model according to Li +et al. (2011). Packages that inherit properties from this partial package may +redeclare the package <i>MediumSpecificFunctions</i>, the model <i>Sorbent</i>, +and the constant <i>twoPhaseAdsorptive</i>. +</p> + +<h4>References</h4> +<ul> + <li> + Li, L., and Yu, M., and Zi, Y., and Dang, Y., and Wu, Q., and Wang, Z., and Xu, Y., and Yan, H, and Dang, Y. (2021). A Thermodynamic Model for Pure and Binary Adsorption Equilibria of N<sub>2</sub> and O<sub>2</sub> on Lithium-Exchanged Low Silicon-to-Aluminum Ratio X Zeolite, Journal of Chemical & Engineering Data, 60:1032-1042. DOI: https://dx.doi.org/10.1021/acs.jced.0c00830. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ZeolithLiLSX_Langmuir_LiEtAl2021; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.order new file mode 100644 index 0000000000000000000000000000000000000000..bf326a650e73724c0e707690a2b84d7d42cdee0a --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/ZeolithLiLSX_Langmuir_LiEtAl2021/package.order @@ -0,0 +1,6 @@ +k1 +k2 +k3 +k4 +calc_c +calc_coefficients diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5a855f0900ba8f3bb7c9d0cc2b785bc1d20be1e4 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.PureComponents; +package O2 "Package containing parametrizations for O2 as adsorptive" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrizations for O<sub>2</sub> as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end O2; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..7ccdea9932b0ceffb8dbe76ac960dcc5d133beb9 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/O2/package.order @@ -0,0 +1 @@ +ZeolithLiLSX_Langmuir_LiEtAl2021 diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..702b8cf8f37ac39537f492dee6de991c8df7e09c --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.WorkingPairs.Parametrizations; +package PureComponents "Package containing parametrizations of pure component working pairs" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrized pure component working pair models. Check +the package content to see for which adsorptives working pair models are +already implemented. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PureComponents; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..1956989c4604e207cd7e7ee8ae1c24e374dc2c93 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/PureComponents/package.order @@ -0,0 +1,5 @@ +MediumSpecificFunctions +CO2 +H2O +N2 +O2 diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/Test_exponential1.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/Test_exponential1.mo new file mode 100644 index 0000000000000000000000000000000000000000..348440bb564a30c9442c9bb36c158393a3550b80 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/Test_exponential1.mo @@ -0,0 +1,119 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities.Testers; +model Test_exponential1 + "Tester for the function 'exponential1' and all corresponding functions" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real a = 0.1 + "First coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real b = 1 + "Second coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real c = 0.001 + "Third coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real d = 100 + "Fourth coefficient" + annotation (Dialog(tab="General", group="General")); + + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculate derivatives numerically" + annotation (Dialog(tab="General", group="General")); + + // + // Definition of variables + // + Modelica.Units.SI.Temperature T(start=273.15, fixed=true) + "Temperature"; + + Real z + "Temperature-dependent coefficient"; + + Real dz_dT + "Partial derivative of temperature-dependent coefficient w.r.t. temperature"; + Real dz_dT_num + "Partial derivative of temperature-dependent coefficient w.r.t. temperature + calculated numerically"; + + Real ddz_dT_dT + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature"; + Real ddz_dT_dT_num + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature calculated numerically"; + +equation + // + // Definition of derivatives + // + der(T) = 1000/20 + "Predecsriped slope of T"; + + // + // Calculation of coefficients and their partial derivatives + // + z = SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T, a=a, b=b, c=c, d=d) + "Temperature-dependent coefficient"; + + dz_dT = SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T, a=a, b=b, c=c, d=d) + "Partial derivative of temperature-dependent coefficient w.r.t. temperature"; + dz_dT_num = (SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T+dT, a=a, b=b, c=c, d=d) - + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1( + T=T-dT, a=a, b=b, c=c, d=d)) / (2 * dT) + "Partial derivative of temperature-dependent coefficient w.r.t. temperature + calculated numerically"; + + ddz_dT_dT = SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential1_dT_dT( + T=T, a=a, b=b, c=c, d=d) + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature"; + ddz_dT_dT_num = (SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T+dT, a=a, b=b, c=c, d=d) - + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential1_dT( + T=T-dT, a=a, b=b, c=c, d=d)) / (2 * dT) + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature calculated numerically"; + + // + // Definition of assertions: Check numerical implementations + // + assert(abs(dz_dT-dz_dT_num) < 1e-6, + "Partial derivative of z w.r.t. temperature is not valied: Deviation (|" + + String(abs(dz_dT-dz_dT_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(ddz_dT_dT-ddz_dT_dT_num) < 1e-6, + "Second-order partial derivative of z w.r.t. temperature is not valied: Deviation (|" + + String(abs(ddz_dT_dT-ddz_dT_dT_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'exponential1' function and its partials derivatives +with resprect to temperature. +<br/><br/> +To see the function behavior, plot the variables <i>z_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_exponential1; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/Test_exponential2.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/Test_exponential2.mo new file mode 100644 index 0000000000000000000000000000000000000000..e134ef615d9fd7ec115c9b3ad93fc57ae137701d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/Test_exponential2.mo @@ -0,0 +1,128 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities.Testers; +model Test_exponential2 + "Tester for the function 'exponential2' and all corresponding functions" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real a = 10 + "First coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real b = 1 + "Second coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real c = 0.001 + "Third coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real d = 100 + "Fourth coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real f = 5 + "Fivth coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real g = -0.1 + "Sixth coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real h = 0.1 + "Seventh coefficient" + annotation (Dialog(tab="General", group="General")); + + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculate derivatives numerically" + annotation (Dialog(tab="General", group="General")); + + // + // Definition of variables + // + Modelica.Units.SI.Temperature T(start=273.15, fixed=true) + "Temperature"; + + Real z + "Temperature-dependent coefficient"; + + Real dz_dT + "Partial derivative of temperature-dependent coefficient w.r.t. temperature"; + Real dz_dT_num + "Partial derivative of temperature-dependent coefficient w.r.t. temperature + calculated numerically"; + + Real ddz_dT_dT + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature"; + Real ddz_dT_dT_num + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature calculated numerically"; + +equation + // + // Definition of derivatives + // + der(T) = 1000/20 + "Predecsriped slope of T"; + + // + // Calculation of coefficients and their partial derivatives + // + z = SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential2( + T=T, a=a, b=b, c=c, d=d, f=f, g=g, h=h) + "Temperature-dependent coefficient"; + + dz_dT = SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential2_dT( + T=T, a=a, b=b, c=c, d=d, f=f, g=g, h=h) + "Partial derivative of temperature-dependent coefficient w.r.t. temperature"; + dz_dT_num = (SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential2( + T=T+dT, a=a, b=b, c=c, d=d, f=f, g=g, h=h) - + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential2( + T=T-dT, a=a, b=b, c=c, d=d, f=f, g=g, h=h)) / (2 * dT) + "Partial derivative of temperature-dependent coefficient w.r.t. temperature + calculated numerically"; + + ddz_dT_dT = SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddexponential2_dT_dT( + T=T, a=a, b=b, c=c, d=d, f=f, g=g, h=h) + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature"; + ddz_dT_dT_num = (SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential2_dT( + T=T+dT, a=a, b=b, c=c, d=d, f=f, g=g, h=h) - + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dexponential2_dT( + T=T-dT, a=a, b=b, c=c, d=d, f=f, g=g, h=h)) / (2 * dT) + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature calculated numerically"; + + // + // Definition of assertions: Check numerical implementations + // + assert(abs(dz_dT-dz_dT_num) < 1e-6, + "Partial derivative of z w.r.t. temperature is not valied: Deviation (|" + + String(abs(dz_dT-dz_dT_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(ddz_dT_dT-ddz_dT_dT_num) < 1e-6, + "Second-order partial derivative of z w.r.t. temperature is not valied: Deviation (|" + + String(abs(ddz_dT_dT-ddz_dT_dT_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'exponential2' function and its partials derivatives +with resprect to temperature. +<br/><br/> +To see the function behavior, plot the variables <i>z_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_exponential2; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/Test_linear1.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/Test_linear1.mo new file mode 100644 index 0000000000000000000000000000000000000000..9b259d8b9f5416e6841aad5519556571cae3ede5 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/Test_linear1.mo @@ -0,0 +1,119 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities.Testers; +model Test_linear1 + "Tester for the function 'linear1' and all corresponding functions" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real a = 0.1 + "First coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real b = 1 + "Second coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real c = -5 + "Third coefficient" + annotation (Dialog(tab="General", group="General")); + parameter Real d = -1 + "Fourth coefficient" + annotation (Dialog(tab="General", group="General")); + + parameter Modelica.Units.SI.TemperatureDifference dT = 1e-3 + "Temperature difference used to calculate derivatives numerically" + annotation (Dialog(tab="General", group="General")); + + // + // Definition of variables + // + Modelica.Units.SI.Temperature T(start=273.15, fixed=true) + "Temperature"; + + Real z + "Temperature-dependent coefficient"; + + Real dz_dT + "Partial derivative of temperature-dependent coefficient w.r.t. temperature"; + Real dz_dT_num + "Partial derivative of temperature-dependent coefficient w.r.t. temperature + calculated numerically"; + + Real ddz_dT_dT + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature"; + Real ddz_dT_dT_num + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature calculated numerically"; + +equation + // + // Definition of derivatives + // + der(T) = 1000/20 + "Predecsriped slope of T"; + + // + // Calculation of coefficients and their partial derivatives + // + z = SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T, a=a, b=b, c=c, d=d) + "Temperature-dependent coefficient"; + + dz_dT = SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T, a=a, b=b, c=c, d=d) + "Partial derivative of temperature-dependent coefficient w.r.t. temperature"; + dz_dT_num = (SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T+dT, a=a, b=b, c=c, d=d) - + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1( + T=T-dT, a=a, b=b, c=c, d=d)) / (2 * dT) + "Partial derivative of temperature-dependent coefficient w.r.t. temperature + calculated numerically"; + + ddz_dT_dT = SorpLib.Media.WorkingPairs.Parametrizations.Utilities.ddlinear1_dT_dT( + T=T, a=a, b=b, c=c, d=d) + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature"; + ddz_dT_dT_num = (SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T+dT, a=a, b=b, c=c, d=d) - + SorpLib.Media.WorkingPairs.Parametrizations.Utilities.dlinear1_dT( + T=T-dT, a=a, b=b, c=c, d=d)) / (2 * dT) + "Second-order partial derivative of temperature-dependent coefficient w.r.t. + temperature calculated numerically"; + + // + // Definition of assertions: Check numerical implementations + // + assert(abs(dz_dT-dz_dT_num) < 1e-6, + "Partial derivative of z w.r.t. temperature is not valied: Deviation (|" + + String(abs(dz_dT-dz_dT_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + assert(abs(ddz_dT_dT-ddz_dT_dT_num) < 1e-6, + "Second-order partial derivative of z w.r.t. temperature is not valied: Deviation (|" + + String(abs(ddz_dT_dT-ddz_dT_dT_num)) + + "|) is greater than 1e-6!", + level = AssertionLevel.warning); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'linear1' function and its partials derivatives +with resprect to temperature. +<br/><br/> +To see the function behavior, plot the variables <i>z_i</i> over the time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_linear1; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5e069ad1c22a4ad5734618726a22bc1458c17990 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities; +package Testers "Models to test and varify utility functions" +extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all utility functions. The test +models check the implementation and demonstrate the utility functions' general +applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..77b32f29224c63cabe76618940c091b75ca96fea --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/Testers/package.order @@ -0,0 +1,3 @@ +Test_linear1 +Test_exponential1 +Test_exponential2 diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/ddexponential1_dT_dT.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/ddexponential1_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..193896ce5ce77d53937f3075fff375038b4b01a3 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/ddexponential1_dT_dT.mo @@ -0,0 +1,46 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities; +function ddexponential1_dT_dT + "Second-order partial derivative of generalized exponential function 1 w.r.t. temperature" + extends BaseClasses.Partial_ddz_dT_dT; + + // + // Definition of inputs + // + input Real a + "First parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real b + "Second parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real c + "Third parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real d + "Fourth parameter" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + ddz_dT_dT := (2 * a * d * exp(c * T + d / T + b)) / T^3 + + a * (c - d / T^2)^2 * exp(c * T + d / T + b) + "Second-order partial derivative of coefficient w.r.t. temperature"; + + // + // Annotations + // + annotation (Inline=true, + Documentation(info="<html> +<p> +This function is the second-order partial derivative of the function 'exponential1' +with respect to the temperature. For full details of the original function 'exponential1,' +check the documentation of the function +<a href=\"Modelica://SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1\">SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddexponential1_dT_dT; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/ddexponential2_dT_dT.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/ddexponential2_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..376e827ea3612b0c73b1ff7de42523cb0d4b513f --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/ddexponential2_dT_dT.mo @@ -0,0 +1,58 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities; +function ddexponential2_dT_dT + "Second-order partial derivative of generalized exponential function 2 w.r.t. temperature" + extends BaseClasses.Partial_ddz_dT_dT; + + // + // Definition of inputs + // + input Real a + "First parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real b + "Second parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real c + "Third parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real d + "Fourth parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real f + "Fivth parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real g + "Sixth parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real h + "Seventh parameter" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + ddz_dT_dT := (a * (f^2 * T^2 * (g * T - 1)^2 * exp(2 * g * T) + + f * T * (T * (g^2 * h * T^3 - 2 * g * h * T^2 + 2 * h * T - 2 * b * g * T - + 4 * d * g + 2 * b) + 4 * d) * exp(g * T) + 2 * b * h * T^3 + (6 * d * h + b^2) * + T^2 + 4 * b * d * T + 4 * d^2) * exp((T * (f * exp(g * T) + c * T + b) + d) / + (h * T^2))) / (h^2 * T^6) + "Second-order partial derivative of coefficient w.r.t. temperature"; + + // + // Annotations + // + annotation (Inline=true, + Documentation(info="<html> +<p> +This function is the second-order partial derivative of the function 'exponential2' +with respect to the temperature. For full details of the original function 'exponential2,' +check the documentation of the function +<a href=\"Modelica://SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential2\">SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential2</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddexponential2_dT_dT; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/ddlinear1_dT_dT.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/ddlinear1_dT_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..35c6834563800fba7ceb7dcce4359703f3e0ade9 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/ddlinear1_dT_dT.mo @@ -0,0 +1,46 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities; +function ddlinear1_dT_dT + "Second-order partial derivative of generalized linear function 1 w.r.t. temperature" + extends BaseClasses.Partial_ddz_dT_dT; + + // + // Definition of inputs + // + input Real a + "First parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real b + "Second parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real c + "Third parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real d + "Fourth parameter" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + ddz_dT_dT := (2 * c * d * (b * T + c / T + a) ^ (d - 1)) / T^3 + + (d - 1) * d * (b - c / T^2)^2 * (b * T + c / T + a) ^ (d - 2) + "Second-order partial derivative of coefficient w.r.t. temperature"; + + // + // Annotations + // + annotation (Inline=true, + Documentation(info="<html> +<p> +This function is the second-order partial derivative of the function 'linear1' +with respect to the temperature. For full details of the original function 'linear1,' +check the documentation of the function +<a href=\"Modelica://SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1\">SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ddlinear1_dT_dT; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/dexponential1_dT.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/dexponential1_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..0c5313488386031f63d8fbf4a5be025482ab396c --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/dexponential1_dT.mo @@ -0,0 +1,45 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities; +function dexponential1_dT + "Partial derivative of generalized exponential function 1 w.r.t. temperature" + extends BaseClasses.Partial_dz_dT; + + // + // Definition of inputs + // + input Real a + "First parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real b + "Second parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real c + "Third parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real d + "Fourth parameter" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + dz_dT := a * (c - d / T^2) * exp(c * T + d / T + b) + "Partial derivative of coefficient w.r.t. temperature"; + + // + // Annotations + // + annotation (Inline=true, + Documentation(info="<html> +<p> +This function is the partial derivative of the function 'exponential1' with respect +to the temperature. For full details of the original function 'exponential1,' check +the documentation of the function +<a href=\"Modelica://SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1\">SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential1</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dexponential1_dT; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/dexponential2_dT.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/dexponential2_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..a01d538edc4abc19d8f49db02703e5cb32851819 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/dexponential2_dT.mo @@ -0,0 +1,55 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities; +function dexponential2_dT + "Partial derivative of generalized exponential function 2 w.r.t. temperature" + extends BaseClasses.Partial_dz_dT; + + // + // Definition of inputs + // + input Real a + "First parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real b + "Second parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real c + "Third parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real d + "Fourth parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real f + "Fivth parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real g + "Sixth parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real h + "Seventh parameter" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + dz_dT := (a * (T * (f * (g * T - 1) * exp(g * T) - b) - 2 * d) * + exp((T * (f * exp(g * T) + c * T + b) + d) / (h * T^2))) / (h * T^3) + "Partial derivative of coefficient w.r.t. temperature"; + + // + // Annotations + // + annotation (Inline=true, + Documentation(info="<html> +<p> +This function is the partial derivative of the function 'exponential2' with respect +to the temperature. For full details of the original function 'exponential2,' check +the documentation of the function +<a href=\"Modelica://SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential2\">SorpLib.Media.WorkingPairs.Parametrizations.Utilities.exponential2</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dexponential2_dT; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/dlinear1_dT.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/dlinear1_dT.mo new file mode 100644 index 0000000000000000000000000000000000000000..794adc40fbdb655fa36f550aa0f96f842bdcaea5 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/dlinear1_dT.mo @@ -0,0 +1,45 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities; +function dlinear1_dT + "Partial derivative of generalized linear function 1 w.r.t. temperature" + extends BaseClasses.Partial_dz_dT; + + // + // Definition of inputs + // + input Real a + "First parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real b + "Second parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real c + "Third parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real d + "Fourth parameter" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + dz_dT := d * (b - c / T^2) * (b * T + c / T + a) ^ (d - 1) + "Partial derivative of coefficient w.r.t. temperature"; + + // + // Annotations + // + annotation (Inline=true, + Documentation(info="<html> +<p> +This function is the partial derivative of the function 'linear1' with respect +to the temperature. For full details of the original function 'linear1,' check +the documentation of the function +<a href=\"Modelica://SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1\">SorpLib.Media.WorkingPairs.Parametrizations.Utilities.linear1</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end dlinear1_dT; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/exponential1.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/exponential1.mo new file mode 100644 index 0000000000000000000000000000000000000000..d0a46fa04c49822d6aa328742cb56b689288be93 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/exponential1.mo @@ -0,0 +1,53 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities; +function exponential1 "Generalized exponential function 1" + extends BaseClasses.Partial_z_T; + + // + // Definition of inputs + // + input Real a + "First parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real b + "Second parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real c + "Third parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real d + "Fourth parameter" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + z := a * exp(b + c * T + d / T) + "Coefficient"; + + // + // Annotations + // + annotation (Inline=true, + Documentation(info="<html> +<p> +This generalized exponential function calculates temperature-dependent isotherm +coefficients. +</p> + +<h4>Main equations</h4> +<p> +The generalized exponential function has the following form: +</p> +<pre> + z = a * <strong>exp</strong>(b + c * T + d / T); +</pre> +<p> +where <i>a</i>, <i>b</i>, <i>c</i>, and <i>d</i> are the coefficients. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end exponential1; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/exponential2.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/exponential2.mo new file mode 100644 index 0000000000000000000000000000000000000000..ec47cb90462019ac95da290bb28fdc779cabe33b --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/exponential2.mo @@ -0,0 +1,63 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities; +function exponential2 "Generalized exponential function 2" + extends BaseClasses.Partial_z_T; + + // + // Definition of inputs + // + input Real a + "First parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real b + "Second parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real c + "Third parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real d + "Fourth parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real f + "Fivth parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real g + "Sixth parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real h + "Seventh parameter" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + z := a * exp((b + c * T + d / T + f * exp(g * T)) / (h * T)) + "Coefficient"; + + // + // Annotations + // + annotation (Inline=true, + Documentation(info="<html> +<p> +This generalized exponential function calculates temperature-dependent isotherm +coefficients. +</p> + +<h4>Main equations</h4> +<p> +The generalized exponential function has the following form: +</p> +<pre> + z = a * <strong>exp</strong>((b + c * T + d / T + f * <strong>exp</strong>(g * T)) / (h * T)); +</pre> +<p> +where <i>a</i>, <i>b</i>, <i>c</i>, <i>d</i>, <i>f</i>, <i>g</i>, and <i>h</i> +are the coefficients. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end exponential2; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/linear1.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/linear1.mo new file mode 100644 index 0000000000000000000000000000000000000000..8602b21c813710784715c41ef7c7a11d506b39bf --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/linear1.mo @@ -0,0 +1,53 @@ +within SorpLib.Media.WorkingPairs.Parametrizations.Utilities; +function linear1 "Generalized linear function 1" + extends BaseClasses.Partial_z_T; + + // + // Definition of inputs + // + input Real a + "First parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real b + "Second parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real c + "Third parameter" + annotation (Dialog(tab="General", group="Inputs")); + input Real d + "Fourth parameter" + annotation (Dialog(tab="General", group="Inputs")); + +algorithm + z :=(a + b*T + c/T)^d + "Coefficient"; + + // + // Annotations + // + annotation (Inline=true, + Documentation(info="<html> +<p> +This generalized linear function calculates temperature-dependent isotherm +coefficients. +</p> + +<h4>Main equations</h4> +<p> +The generalized linear function has the following form: +</p> +<pre> + z = (a + b * T + c / T) ^ d; +</pre> +<p> +where <i>a</i>, <i>b</i>, <i>c</i>, and <i>d</i> are the coefficients. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end linear1; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..1c0ec8b9dff02f68d32407d88282861d13057cbc --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs.Parametrizations; +package Utilities "Package containing utility functions used to parametrize working pairs" +extends Modelica.Icons.UtilitiesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains utility functions used to parametrize working pair +models. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Utilities; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/package.order new file mode 100644 index 0000000000000000000000000000000000000000..9105f11d69073c61fe550a1b107fef50cfcfa8e6 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/Utilities/package.order @@ -0,0 +1,10 @@ +linear1 +dlinear1_dT +ddlinear1_dT_dT +exponential1 +dexponential1_dT +ddexponential1_dT_dT +exponential2 +dexponential2_dT +ddexponential2_dT_dT +Testers diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/package.mo b/SorpLib/Media/WorkingPairs/Parametrizations/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..dde0eef0c8335f473595659ab6f5c8723d289a23 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/package.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs; +package Parametrizations "Parametrized working pair models without fixed media models" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parameterized working models. For this purpose, the interfaces +of the pure and multi-component working pair models are extended by the parameterization +of the isotherm model. Furthermore, the <i>MediumSpecificFunctions</i> package has been +selected but can still be replaced. Note that this is a design decision to enable using +different Modelica libraries for the fluid property calculation, e.g., the open-source +Modelica Standard Library (MSL) or the commercial library TILMedia. +</p> + +<h4>Structure</h4> +<p> +The package +<a href=\"Modelica://SorpLib.Media.WorkingPairs.Parametrizations.Utilities\">SorpLib.Media.WorkingPairs.Parametrizations.Utilities</a> +contains auxiliary functions for calculating temperature-dependent coefficients of +the isotherm model. The <i>PureComponents</i> and <i>MultiComponents</i> packages +contain parameterized pure component or multi-component working pair models. In each +package, a separate package is provided for each available adsorptive or adsorptive +mixture, sorted alphabetically. The naming convention for the parameterized working +pair models is as follows +</p> +<pre> + NameSorbent_NameIsothermModel_NameAuthorsYear; +</pre> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Parametrizations; diff --git a/SorpLib/Media/WorkingPairs/Parametrizations/package.order b/SorpLib/Media/WorkingPairs/Parametrizations/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5950ae1205da6ab4565bce9432ed0ff4e46993b4 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Parametrizations/package.order @@ -0,0 +1,3 @@ +Utilities +PureComponents +MultiComponents diff --git a/SorpLib/Media/WorkingPairs/PureComponents/CO2/ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/CO2/ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..82c22934dbda4ff31184263d3accccda6fb76748 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/CO2/ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo @@ -0,0 +1,46 @@ +within SorpLib.Media.WorkingPairs.PureComponents.CO2; +model ActivatedCarbon_Toth_DantasEtAl2011_Gas + "CO2 & Activated carbon via the Toth isotherm model according to Dantas et al. (2011)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.CO2, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2.ActivatedCarbon_Toth_DantasEtAl2011 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + redeclare replaceable model Sorbent = + Solids.Sorbents.GenericSorbent ( + v_constant=1/1138, + c_constant=880, + lambda_constant=0.075), + v_adsorpt_constant=1/990, + cp_adsorpt_constant=2.5e3, + h_ads_constant=496e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair CO<sub>2</sub> & activated carbon using the Toth isotherm model +according to Dantas et al. (2011). +</p> + +<h4>References</h4> +<ul> + <li> + Dantas, T.L.P. and Luna, F.M.T. and Silva Jr., I.J. and Azevedo, D.C.S. and Grande, C.A. and Rodrigues, A.E. and Moreira, R.F.P.M. (2011). Carbon dioxide–nitrogen separation through adsorption on activated carbon in a fixed bed, Chemical Engineering Journal, 169: 11–19. DOI: https://doi.org/10.1016/j.cej.2010.08.026. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ActivatedCarbon_Toth_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/CO2/SilicaGel_Toth_WangDouglasLeVan2009_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/CO2/SilicaGel_Toth_WangDouglasLeVan2009_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..bc19a91650d75d1f2e70d4c4603529fb1d053147 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/CO2/SilicaGel_Toth_WangDouglasLeVan2009_Gas.mo @@ -0,0 +1,43 @@ +within SorpLib.Media.WorkingPairs.PureComponents.CO2; +model SilicaGel_Toth_WangDouglasLeVan2009_Gas + "CO2 & silica gel via the Toth isotherm model according to Wang and Douglas LeVan (2009)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.CO2, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2.SilicaGel_Toth_WangDouglasLeVan2009 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + redeclare replaceable model Sorbent = + Solids.Sorbents.RDSilicaGel, + v_adsorpt_constant=1/990, + cp_adsorpt_constant=2.5e3, + h_ads_constant=496e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair CO<sub>2</sub> & silica gel using the Toth isotherm model +according to Wang and Douglas LeVan (2010). +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGel_Toth_WangDouglasLeVan2009_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/CO2/Zeolith13X_Toth_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/CO2/Zeolith13X_Toth_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..7166ccfd70b2aa63d20a42239444f944f12aa486 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/CO2/Zeolith13X_Toth_DantasEtAl2011_Gas.mo @@ -0,0 +1,46 @@ +within SorpLib.Media.WorkingPairs.PureComponents.CO2; +model Zeolith13X_Toth_DantasEtAl2011_Gas + "CO2 & Zeolith 13X via the Toth isotherm model according to Dantas et al. (2011)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.CO2, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2.Zeolith13X_Toth_DantasEtAl2011 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + redeclare replaceable model Sorbent = + Solids.Sorbents.GenericSorbent ( + v_constant=1/1940, + c_constant=920, + lambda_constant=0.085), + v_adsorpt_constant=1/990, + cp_adsorpt_constant=2.5e3, + h_ads_constant=496e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair CO<sub>2</sub> & Zeolith 13X using the Toth isotherm model according +to Dantas et al. (2011). +</p> + +<h4>References</h4> +<ul> + <li> + Dantas, T.L.P. and Luna, F.M.T. and Silva Jr., I.J. and Torres, A.E.B. and Azevedo, D.C.S. and Rodrigues, A.E. and Moreira, R.F.P.M. (2011). Carbon dioxide–nitrogen separation through pressure swing adsorption, Chemical Engineering Journal, 172:698-704. DOI: https://doi.org/10.1016/j.cej.2011.06.037. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_Toth_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/CO2/Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/CO2/Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..790c4f4309c411c7a51a5d799122c1f19805efe3 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/CO2/Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo @@ -0,0 +1,49 @@ +within SorpLib.Media.WorkingPairs.PureComponents.CO2; +model Zeolith13X_Toth_WangDouglasLeVan2010_Gas + "CO2 & Zeolith 13X via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.CO2, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2.Zeolith13X_Toth_WangDouglasLeVan2010 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + redeclare replaceable model Sorbent = + Solids.Sorbents.GenericSorbent ( + v_constant=1/670, + c_constant=920, + lambda_constant=0.085), + v_adsorpt_constant=1/990, + cp_adsorpt_constant=2.5e3, + h_ads_constant=496e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair CO<sub>2</sub> & Zeolith 13X using the Toth isotherm model +according to Wang and Douglas LeVan (2010). +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> + <li> + Wang, Y. and Douglas LeVan, M. (2010). Adsorption Equilibrium of Binary Mixtures of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X, Hournal of Chemical & Engineering Data, 55(9):3189–3195. DOI: https://doi.org/10.1021/je100053g. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_Toth_WangDouglasLeVan2010_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/CO2/Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/CO2/Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..7bab7f7a068c3ef155115f93a2527c1d1f73542b --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/CO2/Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo @@ -0,0 +1,49 @@ +within SorpLib.Media.WorkingPairs.PureComponents.CO2; +model Zeolith5A_Toth_WangDouglasLeVan2010_Gas + "CO2 & Zeolith 5A via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.CO2, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2.Zeolith5A_Toth_WangDouglasLeVan2010 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + redeclare replaceable model Sorbent = + Solids.Sorbents.GenericSorbent ( + v_constant=1/670, + c_constant=920, + lambda_constant=0.085), + v_adsorpt_constant=1/990, + cp_adsorpt_constant=2.5e3, + h_ads_constant=496e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair CO<sub>2</sub> & Zeolith 5A using the Toth isotherm model +according to Wang and Douglas LeVan (2010). +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> + <li> + Wang, Y. and Douglas LeVan, M. (2010). Adsorption Equilibrium of Binary Mixtures of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X, Hournal of Chemical & Engineering Data, 55(9):3189–3195. DOI: https://doi.org/10.1021/je100053g. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith5A_Toth_WangDouglasLeVan2010_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/CO2/package.mo b/SorpLib/Media/WorkingPairs/PureComponents/CO2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..218b2fc3df221d3ad0349a774e5edfd874a6be38 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/CO2/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs.PureComponents; +package CO2 "Package containing parametrizations for CO2 as adsorptive" + extends Modelica.Icons.VariantsPackage; + + + annotation (Documentation(info="<html> +<p> +This package contains parametrizations for CO<sub>2</sub> as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CO2; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/CO2/package.order b/SorpLib/Media/WorkingPairs/PureComponents/CO2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..cc9361c7ba0c7b6e676dfc75d4b4c87f318b15f1 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/CO2/package.order @@ -0,0 +1,5 @@ +ActivatedCarbon_Toth_DantasEtAl2011_Gas +SilicaGel_Toth_WangDouglasLeVan2009_Gas +Zeolith5A_Toth_WangDouglasLeVan2010_Gas +Zeolith13X_Toth_DantasEtAl2011_Gas +Zeolith13X_Toth_WangDouglasLeVan2010_Gas diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..e83878bf9a14e3f16c18924ddbaf50733a8f3671 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo @@ -0,0 +1,53 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + "H2O & AQSOA-Z01 via the Dubinin isotherm model with a Lorentzian Cumulative according to measurment data from Goldsworty (2014) and fit from Bau (2017)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & AQSOA-Z02 (FAM-Z02) using the Dubinin isotherm +model with a Lorentzian Cumulative characteristic curve generated by Bau (2017) +using measurement data from Goldsworthy (2014). +</p> + +<h4>References</h4> +<ul> + <li> + Goldsworthy (2014). Measurements of water vapour sorption isotherms for RD silica gel, AQSOA-Z01, AQSOA-Z02, AQSOA-Z05 and CECA zeolite 3A, Microporous and Mesoporous Materials, 196:59-67. DOI: http://dx.doi.org/10.1016/j.micromeso.2014.04.046. + </li> + <li> + Bau (2018). From Dynamic Simulation to Optimal Design and Control of Adsorption Energy Systems, PhD thesis. DOI: https://doi.org/10.18154/RWTH-2018-222524. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + December 14, 2020, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + November 17, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..1408df85b2fefbbfa02b43440beb7c189213d1f7 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo @@ -0,0 +1,53 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + "H2O & AQSOA-Z02 via the Dubinin isotherm model with a Lorentzian Cumulative according to measurment data from Goldsworty (2014) and fit from Bau (2017)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & AQSOA-Z02 (FAM-Z02) using the Dubinin isotherm +model with a Lorentzian Cumulative characteristic curve generated by Bau (2017) +using measurement data from Goldsworthy (2014). +</p> + +<h4>References</h4> +<ul> + <li> + Goldsworthy (2014). Measurements of water vapour sorption isotherms for RD silica gel, AQSOA-Z01, AQSOA-Z02, AQSOA-Z05 and CECA zeolite 3A, Microporous and Mesoporous Materials, 196:59-67. DOI: http://dx.doi.org/10.1016/j.micromeso.2014.04.046. + </li> + <li> + Bau (2018). From Dynamic Simulation to Optimal Design and Control of Adsorption Energy Systems, PhD thesis. DOI: https://doi.org/10.18154/RWTH-2018-222524. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + December 14, 2020, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + November 17, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..7cd8535f38f7f688057a0ef253a3c6a98b41dee5 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo @@ -0,0 +1,53 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + "H2O & AQSOA-Z05 via the Dubinin isotherm model with a Lorentzian Cumulative according to measurment data from Goldsworty (2014) and fit from Bau (2017)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & AQSOA-Z05 (FAM-Z05) using the Dubinin isotherm +model with a Lorentzian Cumulative characteristic curve generated by Bau (2017) +using measurement data from Goldsworthy (2014). +</p> + +<h4>References</h4> +<ul> + <li> + Goldsworthy (2014). Measurements of water vapour sorption isotherms for RD silica gel, AQSOA-Z01, AQSOA-Z02, AQSOA-Z05 and CECA zeolite 3A, Microporous and Mesoporous Materials, 196:59-67. DOI: http://dx.doi.org/10.1016/j.micromeso.2014.04.046. + </li> + <li> + Bau (2018). From Dynamic Simulation to Optimal Design and Control of Adsorption Energy Systems, PhD thesis. DOI: https://doi.org/10.18154/RWTH-2018-222524. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + December 14, 2020, by Mirko Engelpracht:<br/> + Revision after restructering of the library. + </li> + <li> + November 17, 2017, by Uwe Bau:<br/> + Tidy up implementation and enhance documentation for publication of library. + </li> +</ul> +</html>")); +end AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/NaZeolithY_DubininEmpirical2_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/NaZeolithY_DubininEmpirical2_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..db43dc903e62e3249078bc0336b7b602cbb54073 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/NaZeolithY_DubininEmpirical2_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model NaZeolithY_DubininEmpirical2_Schawe2000_VLE + "H2O & Na-Zeolith Y via the Dubinin isotherm model with an empirical 2 approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.NaZeolithY_DubininEmpirical2_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & Na-Zeolith Y using the Dubinin isotherm model +with an empirical 2 characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end NaZeolithY_DubininEmpirical2_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..1aef5536eb7b59bc9c4d19a429b2b4ceb0e267f9 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE + "H2O & Silica gel 125 via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGel125_DubininLorentzianCumulative_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel 125 using the Dubinin isotherm model +with a Lorentzian Cumulative characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..8f5f81fd60be88bdb393318ee17e2ebfb9b91bb2 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE + "H2O & Silica gel AF-25 via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGelAF25_DubininLorentzianCumulative_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel AF-25 using the Dubinin isotherm model +with a Lorentzian Cumulative characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..ebaa6754d793303843cdb626519df4930de6f89f --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE + "H2O & Silica gel Fuji via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGelFuji_DubininLorentzianCumulative_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel Fuji using the Dubinin isotherm model +with a Lorentzian Cumulative characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelH_DubininPearsonIV_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelH_DubininPearsonIV_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..7514915e9e9e0a5d84fb6074bd257b0d93e16e0d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelH_DubininPearsonIV_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model SilicaGelH_DubininPearsonIV_Schawe2000_VLE + "H2O & Silica gel H via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGelH_DubininPearsonIV_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel H using the Dubinin isotherm model +with a Pearson IV characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelH_DubininPearsonIV_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..687134fc3322e4ed3db7e4e04ecad28d4a2c2ef9 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE + "H2O & Silica gel LE-32 via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGelLE32_DubininPearsonIV_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel LE-32 using the Dubinin isotherm model +with a Pearson IV characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..d1b15b3dbee60c2f794f4dcb4b8fb54721846e68 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE + "H2O & Silica gel NAC via the Dubinin isotherm model with an empircal 1 approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGelNAC_DubininEmpirical1_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel NAC using the Dubinin isotherm model +with an empirical 1 characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelN_DubininPearsonIV_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelN_DubininPearsonIV_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..54247f1d14508cc025754b56f31cbd2a420726e2 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelN_DubininPearsonIV_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model SilicaGelN_DubininPearsonIV_Schawe2000_VLE + "H2O & Silica gel N via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGelN_DubininPearsonIV_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel N using the Dubinin isotherm model +with a Pearson IV characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelN_DubininPearsonIV_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..fcb9a0c4902f2aa1f363af9d348abb5ba1711f11 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE + "H2O & Silica gel WS via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGelWS_DubininLorentzianCumulative_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel WS using the Dubinin isotherm model +with a Lorentzian Cumulative characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..0a76159ef236e438d278d35788c63132da0b0c03 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009_Gas.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model SilicaGel_Toth_WangDouglasLeVan2009_Gas + "H2O & Zeolith 5A via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.H2O, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGel_Toth_WangDouglasLeVan2009 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel using the Toth isotherm model according +to Wang and Douglas LeVan (2010). +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGel_Toth_WangDouglasLeVan2009_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..9048d358c63d37e1a05b629406145382e7ee7784 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/SilicaGel_Toth_WangDouglasLeVan2009_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model SilicaGel_Toth_WangDouglasLeVan2009_VLE + "H2O & Zeolith 5A via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGel_Toth_WangDouglasLeVan2009 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel using the Toth isotherm model according +to Wang and Douglas LeVan (2010). +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end SilicaGel_Toth_WangDouglasLeVan2009_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..869748323ff25055072c35a218c2d70613ea783c --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + "H2O & Silica gel 123 via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.SilicaGel123_DubininLorentzianCumulative_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & silica gel 123 using the Dubinin isotherm model +with a Lorentzian Cumulative characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/Sizeo15_DubininPearsonIV_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Sizeo15_DubininPearsonIV_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..b3b6e0c190b5873735e8c511e6b9f77e0c1f4fb2 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Sizeo15_DubininPearsonIV_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model Sizeo15_DubininPearsonIV_Schawe2000_VLE + "H2O & Sizeo 15 via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.Sizeo15_DubininPearsonIV_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & Sizeo 15 using the Dubinin isotherm model +with a Pearson IV characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Sizeo15_DubininPearsonIV_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith13X_DubininEmpirical2_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith13X_DubininEmpirical2_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..f68e5d8a36752b9f19dc2946b3fa266f4896c77d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith13X_DubininEmpirical2_Schawe2000_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model Zeolith13X_DubininEmpirical2_Schawe2000_VLE + "H2O & Zeolith 13X via the Dubinin isotherm model with an empircal 2 approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.Zeolith13X_DubininEmpirical2_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & Zeolith 13X using the Dubinin isotherm model +with an empirical 2 characteristic curve according to Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_DubininEmpirical2_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..bb594a1af19a2a44671bb34bc684d23a01403112 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model Zeolith13X_Toth_WangDouglasLeVan2010_Gas + "H2O & Zeolith 13X via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.H2O, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.Zeolith13X_Toth_WangDouglasLeVan2010 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & Zeolith 13X using the Toth isotherm model according +to Wang and Douglas LeVan (2010). +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_Toth_WangDouglasLeVan2010_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..fa2fcbe7de7f6688b7661fb3e92968e184d948d6 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith13X_Toth_WangDouglasLeVan2010_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model Zeolith13X_Toth_WangDouglasLeVan2010_VLE + "H2O & Zeolith 13X via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.Zeolith13X_Toth_WangDouglasLeVan2010 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & Zeolith 13X using the Toth isotherm model according +to Wang and Douglas LeVan (2010). +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_Toth_WangDouglasLeVan2010_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..588802017a69f01acc687db373b83bd604ad2c82 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model Zeolith5A_Toth_WangDouglasLeVan2010_Gas + "H2O & Zeolith 5A via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.H2O, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.Zeolith5A_Toth_WangDouglasLeVan2010 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & Zeolith 5A using the Toth isotherm model according +to Wang and Douglas LeVan (2010). +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith5A_Toth_WangDouglasLeVan2010_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..1bd7ddfd93ae5a800612b8179a9081d975ca1c42 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/Zeolith5A_Toth_WangDouglasLeVan2010_VLE.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model Zeolith5A_Toth_WangDouglasLeVan2010_VLE + "H2O & Zeolith 5A via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.Zeolith5A_Toth_WangDouglasLeVan2010 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & Zeolith 5A using the Toth isotherm model according +to Wang and Douglas LeVan (2010). +</p> + +<h4>References</h4> +<ul> + <li> + Wang, Y. and Douglas LeVan, M. (2009). Adsorption Equilibrium of Carbon Dioxide and Water Vapor on Zeolites 5A and 13X and Silica Gel: Pure Components, Journal of Chemical & Engineering Data, 54:2839-2844. DOI: https://doi.org/10.1021/je800900a. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith5A_Toth_WangDouglasLeVan2010_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..803eaa9538cd7f0fefa1cee637449b545984c222 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE.mo @@ -0,0 +1,42 @@ +within SorpLib.Media.WorkingPairs.PureComponents.H2O; +model ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE + "H2O & Zeolith Type A via the Dubinin isotherm model with a Chebyshev Series rational order 3/3 approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE( + redeclare replaceable package Medium = + Modelica.Media.Water.StandardWater, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.H2O.Zeolith13X_DubininEmpirical2_Schawe2000 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.VLE + ( + redeclare final package Medium = Medium)), + v_adsorpt_constant=1/947, + cp_adsorpt_constant=4.3e3, + h_ads_constant=2750e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair H<sub>2</sub>0 & Zeolith Type A using the Dubinin isotherm model +with a Chebyshev series rational order 3/3 characteristic curve according to +Schawe (2000). +</p> + +<h4>References</h4> +<ul> + <li> + Schawe (2000). Theoretical and Experimental Investigations of an Adsorption Heat Pump with Heat Transfer between two Adsorbers, PhD thesis. DOI: http://dx.doi.org/10.18419/opus-1518. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/package.mo b/SorpLib/Media/WorkingPairs/PureComponents/H2O/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..8e87de50251590566480de77aa500e61359f0a90 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs.PureComponents; +package H2O "Package containing internal models used just for testing purposes" +extends Modelica.Icons.VariantsPackage; + + +annotation (Documentation(info="<html> +<p> +This package contains parametrizations for H<sub>2</sub>O as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end H2O; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/H2O/package.order b/SorpLib/Media/WorkingPairs/PureComponents/H2O/package.order new file mode 100644 index 0000000000000000000000000000000000000000..a83cc71a9ac9e5b111d1d40ced4e39892a892354 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/H2O/package.order @@ -0,0 +1,22 @@ +AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE +AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE +AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE +NaZeolithY_DubininEmpirical2_Schawe2000_VLE +SilicaGel_Toth_WangDouglasLeVan2009_Gas +SilicaGel_Toth_WangDouglasLeVan2009_VLE +Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE +SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE +SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE +SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE +SilicaGelH_DubininPearsonIV_Schawe2000_VLE +SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE +SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE +SilicaGelN_DubininPearsonIV_Schawe2000_VLE +SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE +Sizeo15_DubininPearsonIV_Schawe2000_VLE +Zeolith5A_Toth_WangDouglasLeVan2010_Gas +Zeolith5A_Toth_WangDouglasLeVan2010_VLE +Zeolith13X_DubininEmpirical2_Schawe2000_VLE +Zeolith13X_Toth_WangDouglasLeVan2010_Gas +Zeolith13X_Toth_WangDouglasLeVan2010_VLE +ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE diff --git a/SorpLib/Media/WorkingPairs/PureComponents/N2/ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/N2/ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..d1d4055f29fd1adf23c19d7df11fba1ac206ee1d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/N2/ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo @@ -0,0 +1,46 @@ +within SorpLib.Media.WorkingPairs.PureComponents.N2; +model ActivatedCarbon_Toth_DantasEtAl2011_Gas + "N2 & Activated carbon via the Toth isotherm model according to Dantas et al. (2011)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.N2, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.N2.ActivatedCarbon_Toth_DantasEtAl2011 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + redeclare replaceable model Sorbent = + Solids.Sorbents.GenericSorbent ( + v_constant=1/1138, + c_constant=880, + lambda_constant=0.075), + v_adsorpt_constant=1/730, + cp_adsorpt_constant=2.4e3, + h_ads_constant=582e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair N<sub>2</sub> & activated carbon using the Toth isotherm model +according to Dantas et al. (2011). +</p> + +<h4>References</h4> +<ul> + <li> + Dantas, T.L.P. and Luna, F.M.T. and Silva Jr., I.J. and Azevedo, D.C.S. and Grande, C.A. and Rodrigues, A.E. and Moreira, R.F.P.M. (2011). Carbon dioxide–nitrogen separation through adsorption on activated carbon in a fixed bed, Chemical Engineering Journal, 169: 11–19. DOI: https://doi.org/10.1016/j.cej.2010.08.026. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ActivatedCarbon_Toth_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/N2/Zeolith13X_Toth_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/N2/Zeolith13X_Toth_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..6c569c2a13c5be2444838938fe3542ff78e444e1 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/N2/Zeolith13X_Toth_DantasEtAl2011_Gas.mo @@ -0,0 +1,46 @@ +within SorpLib.Media.WorkingPairs.PureComponents.N2; +model Zeolith13X_Toth_DantasEtAl2011_Gas + "N2 & Zeolith 13X via the Toth isotherm model according to Dantas et al. (2011)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.N2, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.N2.Zeolith13X_Toth_DantasEtAl2011 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + redeclare replaceable model Sorbent = + Solids.Sorbents.GenericSorbent ( + v_constant=1/1940, + c_constant=920, + lambda_constant=0.085), + v_adsorpt_constant=1/730, + cp_adsorpt_constant=2.4e3, + h_ads_constant=582e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair N<sub>2</sub> & Zeolith 13X using the Toth isotherm model according +to Dantas et al. (2011). +</p> + +<h4>References</h4> +<ul> + <li> + Dantas, T.L.P. and Luna, F.M.T. and Silva Jr., I.J. and Torres, A.E.B. and Azevedo, D.C.S. and Rodrigues, A.E. and Moreira, R.F.P.M. (2011). Carbon dioxide–nitrogen separation through pressure swing adsorption, Chemical Engineering Journal, 172:698-704. DOI: https://doi.org/10.1016/j.cej.2011.06.037. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Zeolith13X_Toth_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/N2/ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/N2/ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..9bd67765680b3b1f3c16de93b3407548b75058d8 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/N2/ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo @@ -0,0 +1,45 @@ +within SorpLib.Media.WorkingPairs.PureComponents.N2; +model ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas + "N2 & Zeolith LiLSX via the Langmuir isotherm model according to Li et al. (2021)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.N2, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.N2.ZeolithLiLSX_Langmuir_LiEtAl2021 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + redeclare replaceable model Sorbent = Solids.Sorbents.GenericSorbent ( + v_constant=1/1940, + c_constant=920, + lambda_constant=0.085), + v_adsorpt_constant=1/730, + cp_adsorpt_constant=2.4e3, + h_ads_constant=582e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair N<sub>2</sub> & Zeolith LiLSX using the Langmuir isotherm model according +to Li et al. (2011). +</p> + +<h4>References</h4> +<ul> + <li> + Li, L., and Yu, M., and Zi, Y., and Dang, Y., and Wu, Q., and Wang, Z., and Xu, Y., and Yan, H, and Dang, Y. (2021). A Thermodynamic Model for Pure and Binary Adsorption Equilibria of N<sub>2</sub> and O<sub>2</sub> on Lithium-Exchanged Low Silicon-to-Aluminum Ratio X Zeolite, Journal of Chemical & Engineering Data, 60:1032-1042. DOI: https://dx.doi.org/10.1021/acs.jced.0c00830. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/N2/package.mo b/SorpLib/Media/WorkingPairs/PureComponents/N2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..66e56989a5aece4052decacbad27620ef435df0c --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/N2/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Media.WorkingPairs.PureComponents; +package N2 "Package containing parametrizations for N2 as adsorptive" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrizations for N<sub>2</sub> as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end N2; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/N2/package.order b/SorpLib/Media/WorkingPairs/PureComponents/N2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..c6943f73b523d00bd027b9558b81a3b2c635f0a3 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/N2/package.order @@ -0,0 +1,3 @@ +ActivatedCarbon_Toth_DantasEtAl2011_Gas +Zeolith13X_Toth_DantasEtAl2011_Gas +ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas diff --git a/SorpLib/Media/WorkingPairs/PureComponents/O2/ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/O2/ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..153b91edb61ea034f5cac3a64aa297ba637d13aa --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/O2/ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo @@ -0,0 +1,45 @@ +within SorpLib.Media.WorkingPairs.PureComponents.O2; +model ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas + "O2 & Zeolith LiLSX via the Langmuir isotherm model according to Li et al. (2021)" + extends SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas( + redeclare replaceable package Medium = + SorpLib.Media.IdealGases.O2, + redeclare final package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.O2.ZeolithLiLSX_Langmuir_LiEtAl2021 + (redeclare final package MediumSpecificFunctions = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.MediumSpecificFunctions.Gas + ( + redeclare final package Medium = Medium)), + redeclare replaceable model Sorbent = Solids.Sorbents.GenericSorbent ( + v_constant=1/1940, + c_constant=920, + lambda_constant=0.085), + v_adsorpt_constant=1/2200, + cp_adsorpt_constant=1e3, + h_ads_constant=250e3); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the adsorption equilibrium and thermodynamic properties of +the working pair O<sub>2</sub> & Zeolith LiLSX using the Langmuir isotherm model according +to Li et al. (2011). +</p> + +<h4>References</h4> +<ul> + <li> + Li, L., and Yu, M., and Zi, Y., and Dang, Y., and Wu, Q., and Wang, Z., and Xu, Y., and Yan, H, and Dang, Y. (2021). A Thermodynamic Model for Pure and Binary Adsorption Equilibria of N<sub>2</sub> and O<sub>2</sub> on Lithium-Exchanged Low Silicon-to-Aluminum Ratio X Zeolite, Journal of Chemical & Engineering Data, 60:1032-1042. DOI: https://dx.doi.org/10.1021/acs.jced.0c00830. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/O2/package.mo b/SorpLib/Media/WorkingPairs/PureComponents/O2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..5b5919f72723c6b8a5d9d6c85d68c78a18bcc086 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/O2/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Media.WorkingPairs.PureComponents; +package O2 "Package containing parametrizations for O2 as adsorptive" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains parametrizations for O<sub>2</sub> as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end O2; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/O2/package.order b/SorpLib/Media/WorkingPairs/PureComponents/O2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..478957a2e778289231c8cc948bd46ac87c6ba309 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/O2/package.order @@ -0,0 +1 @@ +ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..51dee566ba234385ab5056269db4f5162d4f4b98 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo @@ -0,0 +1,34 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.CO2; +model Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas + "Tester for the working pair CO2 & Activated carbon via the Toth isotherm model according to Dantas et al. (2011)" + extends + SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(3e5-1)/20, + T_adsorpt_start=301, + p_adsorpt_start=1, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.CO2.ActivatedCarbon_Toth_DantasEtAl2011_Gas + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(info="<html> +<p> +This tester shows the behavior of the working pair CO<sub>2</sub> & activated +carbon using the Toth isotherm model according to Dantas et al. (2011). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_SilicaGel_Toth_WangDouglasLeVan2010.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_SilicaGel_Toth_WangDouglasLeVan2010.mo new file mode 100644 index 0000000000000000000000000000000000000000..9a4079ad66908e965bdcb8f2e2facf96412dfa7a --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_SilicaGel_Toth_WangDouglasLeVan2010.mo @@ -0,0 +1,36 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.CO2; +model Test_SilicaGel_Toth_WangDouglasLeVan2010 + "Tester for the working pair CO2 & silica gel via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1)/20, + T_adsorpt_start=283.15, + p_adsorpt_start=1, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.CO2.SilicaGel_Toth_WangDouglasLeVan2009_Gas + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair CO<sub>2</sub> & silica gel +using the Toth isotherm model according to Wang and Douglas LeVan (2009, 2010). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGel_Toth_WangDouglasLeVan2010; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_Zeolith13X_Toth_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_Zeolith13X_Toth_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..81d14f099260e8ee71dfd5c4819f5d9dffd685a3 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_Zeolith13X_Toth_DantasEtAl2011_Gas.mo @@ -0,0 +1,33 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.CO2; +model Test_Zeolith13X_Toth_DantasEtAl2011_Gas + "Tester for the working pair CO2 & Zeolith 13X via the Toth isotherm model according to Dantas et al. (2011)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(5e5-1)/20, + T_adsorpt_start=273.15+28, + p_adsorpt_start=1, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.CO2.Zeolith13X_Toth_DantasEtAl2011_Gas + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(info="<html> +<p> +This tester shows the behavior of the working pair CO<sub>2</sub> & Zeolith 13X +using the Toth isotherm model according to Dantas et al. (2011). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_Zeolith13X_Toth_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..d8a825c8a25af4eef9744ccb20fd0d20230d115d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo @@ -0,0 +1,36 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.CO2; +model Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas + "Tester for the working pair CO2 & Zeolith 13X via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1)/20, + T_adsorpt_start=273.15-45, + p_adsorpt_start=1, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.CO2.Zeolith13X_Toth_WangDouglasLeVan2010_Gas + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair CO<sub>2</sub> & Zeolith 13X +using the Toth isotherm model according to Wang and Douglas LeVan (2009, 2010). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..96a4f3ad019f77a358f63eb660701ecc5e2f8645 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.CO2; +model Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas + "Tester for the working pair CO2 & Zeolith 5A via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends + SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1)/20, + T_adsorpt_start=273.15-45, + p_adsorpt_start=1, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.CO2.Zeolith5A_Toth_WangDouglasLeVan2010_Gas + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair CO<sub>2</sub> & Zeolith 5A +using the Toth isotherm model according to Wang and Douglas LeVan (2009, 2010). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/package.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..2bcd0adb7e453b5f9bdcce203cdf51158f8cfdfb --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers; +package CO2 "Model to test and varify working pair models that use CO2 as adsorptive" +extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented working pair models +using CO<sub>2</sub> as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end CO2; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/package.order b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..cfaa6dde41f95e4ee8af61e47509d578b95d26bd --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/CO2/package.order @@ -0,0 +1,5 @@ +Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas +Test_SilicaGel_Toth_WangDouglasLeVan2010 +Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas +Test_Zeolith13X_Toth_DantasEtAl2011_Gas +Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..04a31097bdba853017c3b2aad61c143470183531 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo @@ -0,0 +1,38 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + "Tester for the working pair H2O & AQSOA-Z01 via the Dubinin isotherm model with a Lorentzian Cumulative according to measurment data from Goldsworty (2014) and fit from Bau (2017)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-615)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=615, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + (approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & AQSOA-Z01 +(FAM-Z01) using the Dubinin isotherm model with a Lorentzian Cumulative +characteristic curve generated by Bau (2017) using measurement data from +Goldsworthy (2014). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..81969f7de3eeeb49c20209afbd9f6d672cbbcbdc --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo @@ -0,0 +1,44 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + "Tester for the working pair H2O & AQSOA-Z02 via the Dubinin isotherm model with a Lorentzian Cumulative according to measurment data from Goldsworty (2014) and fit from Bau (2017)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=1, + p_adsorpt_der=(1e5-615)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=615, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + ( + redeclare model Sorbent = SorpLib.Media.Solids.Sorbents.RDSilicaGel ( + approach_c=SorpLib.Choices.SpecificHeatCapacitySolid.Constant), + calcAdsorptAdsorbateState=false, + approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Dubinin, + approachSpecificHeatCapacity=SorpLib.Choices.SpecificHeatCapacityAdsorpt.BoilingCurve, + approachSpecificVolume=SorpLib.Choices.SpecificVolumeAdsorpt.BoilingCurve)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & AQSOA-Z02 +(FAM-Z02) using the Dubinin isotherm model with a Lorentzian Cumulative +characteristic curve generated by Bau (2017) using measurement data from +Goldsworthy (2014). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..e27d8d812af7917bb9e2e650aa5027335a561701 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE.mo @@ -0,0 +1,38 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + "Tester for the working pair H2O & AQSOA-Z05 via the Dubinin isotherm model with a Lorentzian Cumulative according to measurment data from Goldsworty (2014) and fit from Bau (2017)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-615)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=615, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & AQSOA-Z05 +(FAM-Z05) using the Dubinin isotherm model with a Lorentzian Cumulative +characteristic curve generated by Bau (2017) using measurement data from +Goldsworthy (2014). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_NaZeolithY_DubininEmpirical2_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_NaZeolithY_DubininEmpirical2_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..fd1c931071284f484d13f10e4496ac6660b8fbbe --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_NaZeolithY_DubininEmpirical2_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_NaZeolithY_DubininEmpirical2_Schawe2000_VLE + "Tester for the working pair H2O & Na-Zeolith Y via the Dubinin isotherm model with an empirical 2 approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.NaZeolithY_DubininEmpirical2_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & Na-Zeolith Y +using the Dubinin isotherm model with an empirical 2 characteristic curve according +to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_NaZeolithY_DubininEmpirical2_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..aa083a7bfe072cb4199c8a78cfcf0158190f9b94 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE + "Tester for the working pair H2O & Silica gel 125 via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel 125 +using the Dubinin isotherm model with a Lorentzian Cumulative characteristic curve +according to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..f696fd9a36dbc57900abd6ea0a481eeb6386060e --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE + "Tester for the working pair H2O & Silica gel AF-25 via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel AF-25 +using the Dubinin isotherm model with a Lorentzian Cumulative characteristic curve +according to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..4942321ccafc17f918c609dd405982f2e0f11f6f --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE + "Tester for the working pair H2O & Silica gel Fuji via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel Fuji +using the Dubinin isotherm model with a Lorentzian Cumulative characteristic curve +according to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelH_DubininPearsonIV_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelH_DubininPearsonIV_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..0f238943b62612d7d085734ca7b9d5fb25a43aa2 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelH_DubininPearsonIV_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_SilicaGelH_DubininPearsonIV_Schawe2000_VLE + "Tester for the working pair H2O & Silica gel H via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGelH_DubininPearsonIV_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel H +using the Dubinin isotherm model with a Pearson IV characteristic curve according +to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGelH_DubininPearsonIV_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..832d14ed643f790ed045428f4bea217a7c26888d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE + "Tester for the working pair H2O & Silica gel LE-32 via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel LE-32 +using the Dubinin isotherm model with a Pearson IV characteristic curve according +to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..2e5a87e2a4884dddc4d995634f8bc8d56d1390da --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE + "Tester for the working pair H2O & Silica gel NAC via the Dubinin isotherm model with an empircal 1 approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel NAC +using the Dubinin isotherm model with an empirical 1 characteristic curve according +to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelN_DubininPearsonIV_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelN_DubininPearsonIV_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..a0caf0aee0aefb5845362b0b6e29872a1f417daa --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelN_DubininPearsonIV_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_SilicaGelN_DubininPearsonIV_Schawe2000_VLE + "Tester for the working pair H2O & Silica gel N via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(0.9e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGelN_DubininPearsonIV_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel N +using the Dubinin isotherm model with a Pearson IV characteristic curve according +to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGelN_DubininPearsonIV_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..73483b612722ddd00f566a38350035412e349890 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE + "Tester for the working pair H2O & Silica gel WS via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(0.9e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGelN_DubininPearsonIV_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel WS +using the Dubinin isotherm model with a Lorentzian Cumulative characteristic curve +according to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGel_Toth_WangDouglasLeVan2009_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGel_Toth_WangDouglasLeVan2009_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..1f94349a7ffdc82bceb6f19a45e06a58f22788fc --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGel_Toth_WangDouglasLeVan2009_Gas.mo @@ -0,0 +1,36 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_SilicaGel_Toth_WangDouglasLeVan2009_Gas + "Tester for the working pair H2O & silica gel via the Toth isotherm model according to Wang and Douglas LeVan (2009)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(0.1e5-615)/20, + T_adsorpt_start=348.15, + p_adsorpt_start=615, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGel_Toth_WangDouglasLeVan2009_Gas + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel +using the Toth isotherm model according to Wang and Douglas LeVan (2010). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGel_Toth_WangDouglasLeVan2009_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGel_Toth_WangDouglasLeVan2009_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGel_Toth_WangDouglasLeVan2009_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..e695ef9864ff967cfe2ecdacb60e84b6017a1f49 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_SilicaGel_Toth_WangDouglasLeVan2009_VLE.mo @@ -0,0 +1,36 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_SilicaGel_Toth_WangDouglasLeVan2009_VLE + "Tester for the working pair H2O & silica gel via the Toth isotherm model according to Wang and Douglas LeVan (2009)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(0.1e5-615)/20, + T_adsorpt_start=348.15, + p_adsorpt_start=615, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.SilicaGel_Toth_WangDouglasLeVan2009_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel +using the Toth isotherm model according to Wang and Douglas LeVan (2010). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_SilicaGel_Toth_WangDouglasLeVan2009_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..8ad1d5e1e8b0b360237c3097911ae364325e12da --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE.mo @@ -0,0 +1,38 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + "Tester for the working pair H2O & Silica gel 123 via the Dubinin isotherm model with a Lorentzian Cumulative approach according to Schawe (2000)" + extends + SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & silica gel +123 using the Dubinin isotherm model with a Lorentzian Cumulative characteristic +curve according to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Sizeo15_DubininPearsonIV_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Sizeo15_DubininPearsonIV_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..940c2d77c62a8c9699cf35fec807d3c9060472ba --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Sizeo15_DubininPearsonIV_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_Sizeo15_DubininPearsonIV_Schawe2000_VLE + "Tester for the working pair H2O & Sizeo 15 via the Dubinin isotherm model with a Pearson IV approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(0.9e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Sizeo15_DubininPearsonIV_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & Sizeo 15 using +the Dubinin isotherm model with a Pearson IV characteristic curve according to +Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Sizeo15_DubininPearsonIV_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith13X_DubininEmpirical2_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith13X_DubininEmpirical2_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..b4463dc05d3f00b54a948fbc3bdb188bc588f4f8 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith13X_DubininEmpirical2_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_Zeolith13X_DubininEmpirical2_Schawe2000_VLE + "Tester for the working pair H2O & Zeolith 13X via the Dubinin isotherm model with an empircal 2 approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Zeolith13X_DubininEmpirical2_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & Zeolith 13X +using the Dubinin isotherm model with an empirical 2 characteristic curve according +to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Zeolith13X_DubininEmpirical2_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..281d526f62b210647a870cb41d47f36364fc3f8a --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas.mo @@ -0,0 +1,36 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas + "Tester for the working pair H2O & Zeolith 13X via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(0.1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Zeolith13X_Toth_WangDouglasLeVan2010_Gas + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & Zeolith 13X +using the Toth isotherm model according to Wang and Douglas LeVan (2010). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith13X_Toth_WangDouglasLeVan2010_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith13X_Toth_WangDouglasLeVan2010_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..646e0e07f910982f031906284f205c96a76a1e21 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith13X_Toth_WangDouglasLeVan2010_VLE.mo @@ -0,0 +1,36 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_Zeolith13X_Toth_WangDouglasLeVan2010_VLE + "Tester for the working pair H2O & Zeolith 13X via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(0.1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Zeolith13X_Toth_WangDouglasLeVan2010_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & Zeolith 13X +using the Toth isotherm model according to Wang and Douglas LeVan (2010). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Zeolith13X_Toth_WangDouglasLeVan2010_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..ab50c5e3f5f59cce1b871d0b2919a4e0d226280f --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas.mo @@ -0,0 +1,36 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas + "Tester for the working pair H2O & Zeolith 5A via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(0.1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Zeolith5A_Toth_WangDouglasLeVan2010_Gas + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & Zeolith 5A +using the Toth isotherm model according to Wang and Douglas LeVan (2010). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith5A_Toth_WangDouglasLeVan2010_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith5A_Toth_WangDouglasLeVan2010_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..586e65f25eac40caa398f47871fe42e03ce6cd69 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_Zeolith5A_Toth_WangDouglasLeVan2010_VLE.mo @@ -0,0 +1,36 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_Zeolith5A_Toth_WangDouglasLeVan2010_VLE + "Tester for the working pair H2O & Zeolith 5A via the Toth isotherm model according to Wang and Douglas LeVan (2010)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(0.1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.Zeolith5A_Toth_WangDouglasLeVan2010_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & Zeolith 5A +using the Toth isotherm model according to Wang and Douglas LeVan (2010). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_Zeolith5A_Toth_WangDouglasLeVan2010_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..3f964feecde4929f7f949011bf0665d835e91422 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/Test_ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE.mo @@ -0,0 +1,37 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.H2O; +model Test_ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE + "Tester for the working pair H2O & Zeolith Type A via the Dubinin isotherm model with a Chebyshev Series rational order 3/3 approach according to Schawe (2000)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairVLE( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(1e5-1000)/20, + T_adsorpt_start=373.15, + p_adsorpt_start=1000, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.H2O.ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(revisions="<html> +<ul> + <li> + November 21, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the working pair H<sub>2</sub>0 & Zeolith Type A +using the Dubinin isotherm model with a Chebyshev series rational order 3/3 +characteristic curve according to Schawe (2000). +<br/><br/> +As an example, this tester increases the uptake and temperature with time. The +simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/package.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..4ac8975457a34b5ec1a92d3367185feccdf2813c --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers; +package H2O "Model to test and varify working pair models that use H2O as adsorptive" +extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented working pair models +using H<sub>2</sub> as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end H2O; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/package.order b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/package.order new file mode 100644 index 0000000000000000000000000000000000000000..8cc90e5951b1900f01c089a63553b9f07622f7e6 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/H2O/package.order @@ -0,0 +1,22 @@ +Test_AQSOAZ01_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE +Test_AQSOAZ02_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE +Test_AQSOAZ05_DubininLorentzianCumulative_Goldsworthy2014_Bau2017_VLE +Test_NaZeolithY_DubininEmpirical2_Schawe2000_VLE +Test_SilicaGel_Toth_WangDouglasLeVan2009_Gas +Test_SilicaGel_Toth_WangDouglasLeVan2009_VLE +Test_Silicagel123_DubininLorentzianCumulative_Schawe2000_VLE +Test_SilicaGelAF25_DubininLorentzianCumulative_Schawe2000_VLE +Test_SilicaGel125_DubininLorentzianCumulative_Schawe2000_VLE +Test_SilicaGelFuji_DubininLorentzianCumulative_Schawe2000_VLE +Test_SilicaGelH_DubininPearsonIV_Schawe2000_VLE +Test_SilicaGelLE32_DubininPearsonIV_Schawe2000_VLE +Test_SilicaGelNAC_DubininEmpirical1_Schawe2000_VLE +Test_SilicaGelN_DubininPearsonIV_Schawe2000_VLE +Test_SilicaGelWS_DubininLorentzianCumulative_Schawe2000_VLE +Test_Sizeo15_DubininPearsonIV_Schawe2000_VLE +Test_Zeolith5A_Toth_WangDouglasLeVan2010_Gas +Test_Zeolith5A_Toth_WangDouglasLeVan2010_VLE +Test_Zeolith13X_DubininEmpirical2_Schawe2000_VLE +Test_Zeolith13X_Toth_WangDouglasLeVan2010_Gas +Test_Zeolith13X_Toth_WangDouglasLeVan2010_VLE +Test_ZeolithTypeA_DubininChebyshevSeries33_Schawe2000_VLE diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..00a1d827b277904eced4b6e564883ce2ed2b36ac --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas.mo @@ -0,0 +1,34 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.N2; +model Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas + "Tester for the working pair N2 & Activated carbon via the Toth isotherm model according to Dantas et al. (2011)" + extends + SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(5e5-1)/20, + T_adsorpt_start=323.15, + p_adsorpt_start=1, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.N2.ActivatedCarbon_Toth_DantasEtAl2011_Gas + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(info="<html> +<p> +This tester shows the behavior of the working pair N<sub>2</sub> & activated +carbon using the Toth isotherm model according to Dantas et al. (2011). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/Test_Zeolith13X_Toth_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/Test_Zeolith13X_Toth_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..e3f5cc17baec93658c98f607ebd5ddc81a4d31d0 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/Test_Zeolith13X_Toth_DantasEtAl2011_Gas.mo @@ -0,0 +1,34 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.N2; +model Test_Zeolith13X_Toth_DantasEtAl2011_Gas + "Tester for the working pair N2 & Zeolith 13X via the Toth isotherm model according to Dantas et al. (2011)" + extends + SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(5e5-1)/20, + T_adsorpt_start=323.15, + p_adsorpt_start=1, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.N2.Zeolith13X_Toth_DantasEtAl2011_Gas + ( approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(info="<html> +<p> +This tester shows the behavior of the working pair N<sub>2</sub> & Zeolith 13X +using the Toth isotherm model according to Dantas et al. (2011). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_Zeolith13X_Toth_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..908f91dce810b34b6256084fb87cd72afe3add49 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo @@ -0,0 +1,33 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.N2; +model Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas + "Tester for the working pair N2 & Zeolith LiLSX via the Langmuir isotherm model according to Li et al. (2021)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(7e5 - 1)/20, + T_adsorpt_start=293.15, + p_adsorpt_start=1, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.N2.ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas + (approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(info="<html> +<p> +This tester shows the behavior of the working pair N<sub>2</sub> & Zeolith LiLSX +using the Langmuir isotherm model according to Dantas et al. (2011). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/package.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..d68f0c5a7bcdfee958013666eea9c37050699bc5 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers; +package N2 "Model to test and varify working pair models that use N2 as adsorptive" +extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented working pair models +using N<sub>2</sub> as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end N2; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/package.order b/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..aa6bcb917ff40bf46ba3c43407c3141070fa87d1 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/N2/package.order @@ -0,0 +1,3 @@ +Test_ActivatedCarbon_Toth_DantasEtAl2011_Gas +Test_Zeolith13X_Toth_DantasEtAl2011_Gas +Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/O2/Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/O2/Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo new file mode 100644 index 0000000000000000000000000000000000000000..57dd6df22336681e3cd1f94e1866de9d791a97da --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/O2/Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas.mo @@ -0,0 +1,33 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers.O2; +model Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas + "Tester for the working pair O2 & Zeolith LiLSX via the Langmuir isotherm model according to Li et al. (2021)" + extends SorpLib.Media.WorkingPairs.PureComponents.Testers.TestWorkingPairGas( + stateVariables=SorpLib.Choices.IndependentVariablesPureComponentWorkingPair.pT, + T_adsorpt_der=0, + p_adsorpt_der=(7e5 - 1)/20, + T_adsorpt_start=293.15, + p_adsorpt_start=1, + redeclare final model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.O2.ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas + (approachSorptionEnthalpy=SorpLib.Choices.SorptionEnthalpy.Formal)); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(info="<html> +<p> +This tester shows the behavior of the working pair N<sub>2</sub> & Zeolith LiLSX +using the Toth isotherm model according to Dantas et al. (2011). +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/O2/package.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/O2/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..88a77cb117faa4a82dde4654b200f3074453e980 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/O2/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers; +package O2 "Model to test and varify working pair models that use O2 as adsorptive" +extends Modelica.Icons.ExamplesPackage; + +annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented working pair models +using O<sub>2</sub> as adsorptive. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end O2; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/O2/package.order b/SorpLib/Media/WorkingPairs/PureComponents/Testers/O2/package.order new file mode 100644 index 0000000000000000000000000000000000000000..70e301601716d1441ef3d64ac6b28b21a5fc776d --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/O2/package.order @@ -0,0 +1 @@ +Test_ZeolithLiLSX_Langmuir_DantasEtAl2011_Gas diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/TestWorkingPairGas.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/TestWorkingPairGas.mo new file mode 100644 index 0000000000000000000000000000000000000000..7415eff2d17ee2a6b01167584056e4d3f7c90dac --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/TestWorkingPairGas.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers; +model TestWorkingPairGas + "Tester for working pair models using a fluid with just one regime (i.e., gas/vapor) based on the MSL" + extends SorpLib.Media.WorkingPairs.BaseClasses.PartialPureTest( + redeclare replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairGas); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(info="<html> +<p> +This model is the basic model for all testers of working pair models describing +adsorption of pure components and using a medium model of a fluid with just one +regime (i.e., gas/vapor) based on the Modelica Standard Library. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end TestWorkingPairGas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/TestWorkingPairVLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/TestWorkingPairVLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..3fa3927c72eb88c827a99f294473539680702588 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/TestWorkingPairVLE.mo @@ -0,0 +1,29 @@ +within SorpLib.Media.WorkingPairs.PureComponents.Testers; +model TestWorkingPairVLE + "Tester for working pair models using a real fluid with a two-phase regime based on the MSL" + extends SorpLib.Media.WorkingPairs.BaseClasses.PartialPureTest( + redeclare replaceable model PureWorkingPairModel = + SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE + constrainedby SorpLib.Media.WorkingPairs.PureComponents.WorkingPairVLE); + + // + // Annotations + // + annotation (experiment( + StopTime=20, + Tolerance=1e-06), +Documentation(info="<html> +<p> +This model is the basic model for all testers of working pair models describing +adsorption of pure components and using a medium model of a fluid with a two-phase +regime based on the Modelica Standard Library. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end TestWorkingPairVLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/package.mo b/SorpLib/Media/WorkingPairs/PureComponents/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..c199c035546888472eae0d7bf60f18db305bf109 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/package.mo @@ -0,0 +1,19 @@ +within SorpLib.Media.WorkingPairs.PureComponents; +package Testers "Models to test and varify models of pure component working pairs" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all implemented working pair model. +Each working pair model has its own test model that is saved in the correct adsorptive +package. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/Testers/package.order b/SorpLib/Media/WorkingPairs/PureComponents/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5e28fc5aa17de63e685934fd76aaa9ce92243e89 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/Testers/package.order @@ -0,0 +1,6 @@ +CO2 +H2O +N2 +O2 +TestWorkingPairGas +TestWorkingPairVLE diff --git a/SorpLib/Media/WorkingPairs/PureComponents/WorkingPairGas.mo b/SorpLib/Media/WorkingPairs/PureComponents/WorkingPairGas.mo new file mode 100644 index 0000000000000000000000000000000000000000..5ee32515569a52866707d14a4d9dc9e96eb61169 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/WorkingPairGas.mo @@ -0,0 +1,41 @@ +within SorpLib.Media.WorkingPairs.PureComponents; +model WorkingPairGas + "Model of a pure working pair using the MSL for fluid property data calculation of a fluid with just one-regime (i.e., gas/vapor)" + + // + // Definition of replaceable medium + // + replaceable package Medium = SorpLib.Media.IdealGases.CO2 + constrainedby Modelica.Media.IdealGases.Common.SingleGasNasa + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Working Pair and Medium"), + choicesAllMatching = true); + + // + // Finalize base classe + // + extends SorpLib.Media.WorkingPairs.BaseClasses.PartialPureWorkingPairs( + redeclare replaceable package WorkingPair = + SorpLib.Media.WorkingPairs.Parametrizations.PureComponents.CO2.ActivatedCarbon_Toth_DantasEtAl2011 + ( + MediumSpecificFunctions(redeclare replaceable package Medium = Medium))); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the thermodynamic properties of a working pair using +a fluid with just one regime (i.e., gas/vapor) as medium model for the adsorptive. +For details on the working pair model, check the model +<a href=\"Modelica://SorpLib.Media.WorkingPairs.BaseClasses.PartialPureWorkingPairs\">SorpLib.Media.WorkingPairs.BaseClasses.PartialPureWorkingPairs</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end WorkingPairGas; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/WorkingPairVLE.mo b/SorpLib/Media/WorkingPairs/PureComponents/WorkingPairVLE.mo new file mode 100644 index 0000000000000000000000000000000000000000..a5751d65ad519cac4c1f7c5c269bac3c00c5ad04 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/WorkingPairVLE.mo @@ -0,0 +1,42 @@ +within SorpLib.Media.WorkingPairs.PureComponents; +model WorkingPairVLE + "Model of a pure working pair using the MSL for fluid property data calculation of a real fluid with a two-phase regime" + + // + // Definition of replaceable medium + // + replaceable package Medium = Modelica.Media.Water.StandardWater + constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium + "Medium (i.e., adsorptive)" + annotation (Dialog(tab="General",group="Working Pair and Medium"), + choicesAllMatching = true); + + // + // Finalize base classe + // + extends SorpLib.Media.WorkingPairs.BaseClasses.PartialPureWorkingPairs( + redeclare replaceable package WorkingPair = + Parametrizations.PureComponents.H2O.SilicaGel123_DubininLorentzianCumulative_Schawe2000 + ( + MediumSpecificFunctions(redeclare replaceable package Medium = Medium))); + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This model calculates the thermodynamic properties of a working pair using +a real fluid with a two-phase regime as medium model for the adsorptive. Note +that isotherm models based on the model of Dubinin must have a real fluid. For +details on the working pair model, check the model +<a href=\"Modelica://SorpLib.Media.WorkingPairs.BaseClasses.PartialPureWorkingPairs\">SorpLib.Media.WorkingPairs.BaseClasses.PartialPureWorkingPairs</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end WorkingPairVLE; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/package.mo b/SorpLib/Media/WorkingPairs/PureComponents/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..8945edb801a2c4800159089da415dbe4636dcaff --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/package.mo @@ -0,0 +1,34 @@ +within SorpLib.Media.WorkingPairs; +package PureComponents "Package containing pure component working pair models" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains fully parameterized working models. For this purpose, +the partially parametrized pure working pair models are extended by a specific +<i>MediumSpecificFunctions</i> package. This package calculates fluid properties +based on the open-source Modelica Standard Library (MSL). +</p> + +<h4>Structure</h4> +<p> +The package +<a href=\"Modelica://SorpLib.Media.WorkingPairs.PureComponents.MediumSpecificFunctions\">SorpLib.Media.WorkingPairs.PureComponents.MediumSpecificFunctions</a> +contains different versions of packages providing medium specific functions. For +each package version there is also a corresponding working pair model. The finally +parametrized working pair models are alphabetically sorted by available asdsorptives +and are stored in seperate packages. The naming convention for the parameterized working +pair models is as follows +</p> +<pre> + NameSorbent_NameIsothermModel_NameAuthorsYear_MediumType; +</pre> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PureComponents; diff --git a/SorpLib/Media/WorkingPairs/PureComponents/package.order b/SorpLib/Media/WorkingPairs/PureComponents/package.order new file mode 100644 index 0000000000000000000000000000000000000000..062901a903fa81a398ebee85ad42acdb64f4d6df --- /dev/null +++ b/SorpLib/Media/WorkingPairs/PureComponents/package.order @@ -0,0 +1,7 @@ +CO2 +H2O +N2 +O2 +WorkingPairGas +WorkingPairVLE +Testers diff --git a/SorpLib/Media/WorkingPairs/Records/DerivativesPureEntropyBalance.mo b/SorpLib/Media/WorkingPairs/Records/DerivativesPureEntropyBalance.mo new file mode 100644 index 0000000000000000000000000000000000000000..63684f70d7adf7abe584b4cff0170553c103f9d1 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Records/DerivativesPureEntropyBalance.mo @@ -0,0 +1,51 @@ +within SorpLib.Media.WorkingPairs.Records; +record DerivativesPureEntropyBalance + "This record contains partial derivatives required for entropy balances of a working pair volume" + extends Modelica.Icons.Record; + + // + // Definition of paramters + // + SorpLib.Units.DerSpecificEntropyByPressure ds_sorbent_dp_T + "Partial derivative of the specific entropy of the sorbent w.r.t. pressure + at constant temperature"; + SorpLib.Units.DerSpecificEntropyByTemperature ds_sorbent_dT_p + "Partial derivative of the specific entropy of the sorbent w.r.t. temperature + at constant pressure"; + SorpLib.Units.DerSpecificEntropyByUptake ds_sorbent_dx_T + "Partial derivative of the specific entropy of the sorbent w.r.t. uptake + at constant temperature"; + SorpLib.Units.DerSpecificEntropyByTemperature ds_sorbent_dT_x + "Partial derivative of the specific entropy of the sorbent w.r.t. temperature + at constant uptake"; + + SorpLib.Units.DerUptakeSpecificEntropyByPressure dxs_avg_adsorpt_dp_T + "Partial derivative of the uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeSpecificEntropyByTemperature dxs_avg_adsorpt_dT_p + "Partial derivative of the uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. temperature at constant pressure"; + SorpLib.Units.DerUptakeSpecificEntropyByUptake dxs_avg_adsorpt_dx_T + "Partial derivative of the uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. uptake at constant temperature"; + SorpLib.Units.DerUptakeSpecificEntropyByTemperature dxs_avg_adsorpt_dT_x + "Partial derivative of the uptake-averaged specific entropy of the adsorpt + times the uptake w.r.t. temperature at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains partial derivatives required to calculate the entropy balance +of working pair volumes. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DerivativesPureEntropyBalance; diff --git a/SorpLib/Media/WorkingPairs/Records/DerivativesPureIsothermModel.mo b/SorpLib/Media/WorkingPairs/Records/DerivativesPureIsothermModel.mo new file mode 100644 index 0000000000000000000000000000000000000000..49f65ce4a7a9777232d2ac3dffdc80d8af07a8a1 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Records/DerivativesPureIsothermModel.mo @@ -0,0 +1,35 @@ +within SorpLib.Media.WorkingPairs.Records; +record DerivativesPureIsothermModel + "This record contains partial derivatives of the isotherm model" + extends Modelica.Icons.Record; + + // + // Definition of paramters + // + SorpLib.Units.DerUptakeByPressure dx_dp_T + "Partial derivative of the uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeByTemperature dx_dT_p + "Partial derivative of the uptake w.r.t. temperature at constant pressure"; + SorpLib.Units.DerPressureByUptake dp_dx_T + "Partial derivative of the uptake w.r.t. uptake at constant temperature"; + Modelica.Units.SI.DerPressureByTemperature dp_dT_x + "Partial derivative of the uptake w.r.t. temperature at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains partial derivatives of the isotherm model. These partial +derivatives may be required for the mass, energy, and entropy balance of working +pair volumes. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DerivativesPureIsothermModel; diff --git a/SorpLib/Media/WorkingPairs/Records/DerivativesPureMassEnergyBalances.mo b/SorpLib/Media/WorkingPairs/Records/DerivativesPureMassEnergyBalances.mo new file mode 100644 index 0000000000000000000000000000000000000000..def735ba0df186cb9e074c6c3656748de751c4ec --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Records/DerivativesPureMassEnergyBalances.mo @@ -0,0 +1,77 @@ +within SorpLib.Media.WorkingPairs.Records; +record DerivativesPureMassEnergyBalances + "This record contains partial derivatives required for mass and energy balances of a working pair volume" + extends Modelica.Icons.Record; + + // + // Definition of paramters + // + SorpLib.Units.DerSpecificVolumeByPressure dv_sorbent_dp_T + "Partial derivative of the specific volume of the sorbent w.r.t. pressure at + constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_sorbent_dT_p + "Partial derivative of the specific volume of the sorbent w.r.t. temperature + at constant pressure"; + SorpLib.Units.DerSpecificVolumeByUptake dv_sorbent_dx_T + "Partial derivative of the specific volume of the sorbent w.r.t. uptake at + constant temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_sorbent_dT_x + "Partial derivative of the specific volume of the sorbent w.r.t. temperature + at constant uptake"; + + SorpLib.Units.DerSpecificEnthalpyByPressure dh_sorbent_dp_T + "Partial derivative of the specific enthalpy of the sorbent w.r.t. pressure + at constant temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_sorbent_dT_p + "Partial derivative of the specific enthalpy of the sorbent w.r.t. temperature + at constant pressure"; + SorpLib.Units.DerSpecificEnthalpyByUptake dh_sorbent_dx_T + "Partial derivative of the specific enthalpy of the sorbent w.r.t. uptake + at constant temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_sorbent_dT_x + "Partial derivative of the specific enthalpy of the sorbent w.r.t. temperature + at constant uptake"; + + SorpLib.Units.DerUptakeSpecificVolumeByPressure dxv_avg_adsorpt_dp_T + "Partial derivative of the uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeSpecificVolumeByTemperature dxv_avg_adsorpt_dT_p + "Partial derivative of the uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. temperature at constant pressure"; + SorpLib.Units.DerUptakeSpecificVolumeByUptake dxv_avg_adsorpt_dx_T + "Partial derivative of the uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. uptake at constant temperature"; + SorpLib.Units.DerUptakeSpecificVolumeByTemperature dxv_avg_adsorpt_dT_x + "Partial derivative of the uptake-averaged specific volume of the adsorpt + times the uptake w.r.t. temperature at constant uptake"; + + SorpLib.Units.DerUptakeSpecificEnthalpyByPressure dxh_avg_adsorpt_dp_T + "Partial derivative of the uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeSpecificEnthalpyByTemperature dxh_avg_adsorpt_dT_p + "Partial derivative of the uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. temperature at constant pressure"; + SorpLib.Units.DerUptakeSpecificEnthalpyByUptake dxh_avg_adsorpt_dx_T + "Partial derivative of the uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. uptake at constant temperature"; + SorpLib.Units.DerUptakeSpecificEnthalpyByTemperature dxh_avg_adsorpt_dT_x + "Partial derivative of the uptake-averaged specific enthalpy of the adsorpt + times the uptake w.r.t. temperature at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains partial derivatives required for the mass and energy balance +of working pair volumes. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end DerivativesPureMassEnergyBalances; diff --git a/SorpLib/Media/WorkingPairs/Records/PropertiesPureAdsorpt.mo b/SorpLib/Media/WorkingPairs/Records/PropertiesPureAdsorpt.mo new file mode 100644 index 0000000000000000000000000000000000000000..ff0f70945eab129be2820ec5a78a5b611d544b61 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Records/PropertiesPureAdsorpt.mo @@ -0,0 +1,85 @@ +within SorpLib.Media.WorkingPairs.Records; +record PropertiesPureAdsorpt + "This record contains required properties of the adsorpt for pure working pairs" + extends Modelica.Icons.Record; + + // + // Uptake-averaged state variables + // + SorpLib.Media.WorkingPairs.Records.StateVariables state + "Thermodynamic state variables of the uptake-averaged adsorpt"; + + // + // State variables + // + Modelica.Units.SI.SpecificVolume v + "Specific volume of the last adsorbed molecule"; + + // + // Additional properties + // + Modelica.Units.SI.SpecificEnthalpy h_ads + "Specific enthalpy of adsorption of the last adsorbed molecule"; + + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity of the last adsorbed molecule or uptake-averaged + adsorpt, depending on the calculation approach"; + + // + // Partial derivatives + // + SorpLib.Media.WorkingPairs.Records.DerivativesPureIsothermModel derivatives_isotherm + "Partial derivatives of the isotherm model"; + + SorpLib.Units.DerUptakeSpecificVolumeByPressure dxv_avg_dp_T + "Partial derivative of the uptake-averaged specific volume times the uptake + w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeSpecificVolumeByTemperature dxv_avg_dT_p + "Partial derivative of the uptake-averaged specific volume times the uptake + w.r.t. temperature at constant pressure"; + + SorpLib.Units.DerUptakeSpecificEnthalpyByPressure dxh_avg_dp_T + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeSpecificEnthalpyByTemperature dxh_avg_dT_p + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. temperature at constant pressure"; + SorpLib.Units.DerUptakeSpecificEnthalpyByUptake dxh_avg_dx_T + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. uptake at constant temperature"; + SorpLib.Units.DerUptakeSpecificEnthalpyByTemperature dxh_avg_dT_x + "Partial derivative of the uptake-averaged specific enthalpy times the uptake + w.r.t. temperature at constant uptake"; + + SorpLib.Units.DerUptakeSpecificEntropyByPressure dxs_avg_dp_T + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. pressure at constant temperature"; + SorpLib.Units.DerUptakeSpecificEntropyByTemperature dxs_avg_dT_p + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. temperature at constant pressure"; + SorpLib.Units.DerUptakeSpecificEntropyByUptake dxs_avg_dx_T + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. uptake at constant temperature"; + SorpLib.Units.DerUptakeSpecificEntropyByTemperature dxs_avg_dT_x + "Partial derivative of the uptake-averaged specific entropy times the uptake + w.r.t. temperature at constant uptake"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains properties of the adsorption required for pure working pairs. +These properties are calculated at once if required, to keep the computational +costs low. Thus, e.g., multiple calculation of the same fluid property data is +avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PropertiesPureAdsorpt; diff --git a/SorpLib/Media/WorkingPairs/Records/PropertiesPureAdsorptive.mo b/SorpLib/Media/WorkingPairs/Records/PropertiesPureAdsorptive.mo new file mode 100644 index 0000000000000000000000000000000000000000..9ec7f02c1748bbf98adc387795db8eb6763f3188 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Records/PropertiesPureAdsorptive.mo @@ -0,0 +1,81 @@ +within SorpLib.Media.WorkingPairs.Records; +record PropertiesPureAdsorptive + "This record contains required properties of the adsorptive in the gas/vapor phase for pure working pairs" + extends Modelica.Icons.Record; + + // + // State variables + // + SorpLib.Media.WorkingPairs.Records.StateVariables state + "Thermodynamic state variables of the adsorptive"; + + // + // Additional properties of the one-phase regime + // + Modelica.Units.SI.SpecificHeatCapacity cp + "Specific heat capacity"; + + // + // Additional properties of the two-phase regime + // + Modelica.Units.SI.Pressure p_sat + "Saturated vapor pressure"; + + Modelica.Units.SI.SpecificVolume v_satLiq + "Specific volume at the bubble point at given temperature"; + + Modelica.Units.SI.SpecificEnthalpy h_adsorptiveToLiquid + "Specific enthalpy difference between adsorptive state and saturated liquid + state (i.e., bubble point)"; + + Modelica.Units.SI.SpecificHeatCapacity cp_satLiq + "Specific heat capacaity at the bubble point at given temperature"; + + // + // Partial derivatives + // + SorpLib.Units.DerSpecificVolumeByPressure dv_dp_T + "Partial derivative of the specific volume w.r.t. pressure at constant + temperature"; + SorpLib.Units.DerSpecificVolumeByTemperature dv_dT_p + "Partial derivative of the specific volume w.r.t. temperature at constant + pressure"; + + Modelica.Media.Common.DerPressureByTemperature dp_sat_dT + "Partial derivative of saturated vapor pressure w.r.t. temperature"; + + SorpLib.Units.DerSpecificVolumeByTemperature dv_satLiq_dT + "Partial derivative of the specific volume at the bubble point at given + temperature w.r.t. temperature"; + SorpLib.Units.DerSpecificVolumeByTemperatureTemperature ddv_satLiq_dT_dT + "Second-order partial derivative of the specific volume at the bubble point + at given temperature w.r.t. temperature"; + + SorpLib.Units.DerSpecificEnthalpyByPressure dh_adsorptiveToLiquid_dp_T + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. pressure at constant + temperature"; + Modelica.Units.SI.SpecificHeatCapacity dh_adsorptiveToLiquid_dT_p + "Partial derivative of specific enthalpy difference between adsorptive state + and saturated liquid state (i.e., bubble point) w.r.t. temperature at constant + pressure"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains properties of the adsorptie in the gas/vapor phase required +for pure working pairs. These properties are calculated at once if required, to +keep the computational costs low. Thus, e.g., multiple calculation of the same +fluid property data is avoided. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end PropertiesPureAdsorptive; diff --git a/SorpLib/Media/WorkingPairs/Records/StateVariables.mo b/SorpLib/Media/WorkingPairs/Records/StateVariables.mo new file mode 100644 index 0000000000000000000000000000000000000000..15972dec888b70c80f937be51a743d9b9ab28c06 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Records/StateVariables.mo @@ -0,0 +1,21 @@ +within SorpLib.Media.WorkingPairs.Records; +record StateVariables + "This record contains thermodynamic state variables" + extends SorpLib.Media.Solids.Records.StateVariables; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This record contains thermodynamic state variables. +</p> +</html>", revisions="<html> +<ul> + <li> + November 22, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end StateVariables; diff --git a/SorpLib/Media/WorkingPairs/Records/package.mo b/SorpLib/Media/WorkingPairs/Records/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..b382670c3320ebbd1fc75131712d004011583a15 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Records/package.mo @@ -0,0 +1,18 @@ +within SorpLib.Media.WorkingPairs; +package Records "Package containing records" + extends Modelica.Icons.RecordsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains definitions of records. These records are used to cluster +variables and tidy up the model output. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end Records; diff --git a/SorpLib/Media/WorkingPairs/Records/package.order b/SorpLib/Media/WorkingPairs/Records/package.order new file mode 100644 index 0000000000000000000000000000000000000000..093ab60bb26e05e04c7854a7c454a41b47ccfcd1 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/Records/package.order @@ -0,0 +1,6 @@ +StateVariables +DerivativesPureIsothermModel +DerivativesPureMassEnergyBalances +DerivativesPureEntropyBalance +PropertiesPureAdsorpt +PropertiesPureAdsorptive diff --git a/SorpLib/Media/WorkingPairs/package.mo b/SorpLib/Media/WorkingPairs/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..6c083c5c4027ffa88eb4d63aa17a398c441e2234 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/package.mo @@ -0,0 +1,64 @@ +within SorpLib.Media; +package WorkingPairs "Models to calcualte fluid property data of sorption working pairs" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +This package contains models calculating thermodynamic properties of pure component +and multi-component working pairs. Independent state variables may be (1) the pressure +and temperature or (2) the uptake and temperature. In the models, fundamental +thermodynamic properties can be calculated: +</p> +<ol> + <li> + Thermal state variables: <i>p</i>, <i>T</i>, and <i>ρ</i>. + </li> + <li> + Caloric state variables: <i>h</i> and <i>u</i>. + </li> + <li> + Entropic state variables: <i>s</i>, <i>g</i>, and <i>a</i>. + </li> +</ol> +<p> +Moreover, the model allow to calculate all partial derivatives with respect to the +independent state variables that are required for dynamic mass, energy, and entropy +balances in finite volume models. +</p> + +<h4>How to add new working pair models</h4> +<p> +To add a new working pair models, three steps are required: +</p> +<ol> + <li> + Duplicate an existing parametrization package and save it into the correct sub-pacakge + of the + <a href=\"Modelica://SorpLib.Media.WorkingPairs.Parametrizations\">Parametrizations package</a>. + Then, parametrize the dublicated package and write the documentation, including + references for the thermodynamic properties. + </li> + <li> + Duplicate an existing working pair model and save it into the correct sub-pacakge of the + <a href=\"Modelica://SorpLib.Media.WorkingPairs.PureComponents\">PureComponents package</a> + or the + <a href=\"Modelica://SorpLib.Media.WorkingPairs.MultiComponents\">MultiComponents package</a>. + Then, finalize the model. + </li> + <li> + Duplicate an existing test model and save it into the correct sub-pacakge of the + <a href=\"Modelica://SorpLib.Media.WorkingPairs.PureComponents.Testers\">PureComponents.Testers package</a> + or the + <a href=\"Modelica://SorpLib.Media.WorkingPairs.MultiComponents.Testers\">MultiComponents.Testers package</a>. + Then, test the new working pair model and varify calculations. + </li> +</ol> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end WorkingPairs; diff --git a/SorpLib/Media/WorkingPairs/package.order b/SorpLib/Media/WorkingPairs/package.order new file mode 100644 index 0000000000000000000000000000000000000000..fc209c69817fa5f5befbd978ad11abc636dc2711 --- /dev/null +++ b/SorpLib/Media/WorkingPairs/package.order @@ -0,0 +1,7 @@ +BaseClasses +Interfaces +Records +Parametrizations +PureComponents +MultiComponents +FluidPropertyDiagrams diff --git a/SorpLib/Media/package.mo b/SorpLib/Media/package.mo index c63b84721f518b30fbe0195eb67ac48f4234f47f..54e5cdbd99a5e275465068d6c252331ee1a8ec73 100644 --- a/SorpLib/Media/package.mo +++ b/SorpLib/Media/package.mo @@ -1,10 +1,42 @@ within SorpLib; -package Media "Equilibrium data of adsorbent / adsorbate working pairs" -extends SorpLib.Internals.ClassTypes.ModelPackage; +package Media "Library of media property models" + extends SorpLib.Icons.MediaPackage; - - - - -annotation (Icon(graphics)); +annotation (Documentation(info="<html> +<p> +This package contains functions required for calculating substance property data. +The functions are mainly used for calculating the adsorption equilibrium or +properties of a sorption working pair. This package contains the following +substance models: +</p> +<ul> + <li> + <a href=\"Modelica://SorpLib.Media.IdealGases\">IdealGases</a>: + Models for calculating ideal gases. + </li> + <li> + <a href=\"Modelica://SorpLib.Media.IdealGasMixtures\">IdealGasMixtures</a>: + Models for calculating ideal gas mixtures. + </li> + <li> + <a href=\"Modelica://SorpLib.Media.IdealGasVaporMixtures\">IdealGasVaporMixtures</a>: + Models for calculating ideal gas-vapor mixtures, i.e., ideal gas mixtures with a condensable substance (usually water). + </li> + <li> + <a href=\"Modelica://SorpLib.Media.Solids\">Solids</a>: + Models for calculating solids, such as metals or sorbents. + </li> + <li> + <a href=\"Modelica://SorpLib.Media.WorkingPairs\">WorkingPairs</a>: + Models for calculating sorption working pairs, either with one or multi components. + </li> +</ul> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); end Media; diff --git a/SorpLib/Media/package.order b/SorpLib/Media/package.order index 6848852409d88182b8a64a665d1beca69db9c429..f6920b3c6aae4f0d3acdaacfeef273d7507007f8 100644 --- a/SorpLib/Media/package.order +++ b/SorpLib/Media/package.order @@ -1,2 +1,6 @@ Functions -AdsorbentAdsorbate +IdealGases +IdealGasMixtures +IdealGasVaporMixtures +Solids +WorkingPairs diff --git a/SorpLib/Modules/Controllers/package.mo b/SorpLib/Modules/Controllers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..33ffa3906e53b3ead8a7359d515bf39fb4ea8ecb --- /dev/null +++ b/SorpLib/Modules/Controllers/package.mo @@ -0,0 +1,17 @@ +within SorpLib.Modules; +package Controllers "Controller to regulate soprtions modules or sorption systems" + extends SorpLib.Icons.ControllerPackage; + + annotation (Documentation(info="<html> +<p> +TO BE ADDED! +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Controllers; diff --git a/SorpLib/Modules/Controllers/package.order b/SorpLib/Modules/Controllers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/Modules/package.mo b/SorpLib/Modules/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..8d0d16f09db684be1b1920cdc6dc379c186fbc76 --- /dev/null +++ b/SorpLib/Modules/package.mo @@ -0,0 +1,17 @@ +within SorpLib; +package Modules "Library containing sorption modules" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info="<html> +<p> +TO BE ADDED! +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Modules; diff --git a/SorpLib/Modules/package.order b/SorpLib/Modules/package.order new file mode 100644 index 0000000000000000000000000000000000000000..5afbd1393075a4bbb61553065dc1ec592c3bfa3c --- /dev/null +++ b/SorpLib/Modules/package.order @@ -0,0 +1 @@ +Controllers diff --git a/SorpLib/Numerics/Testers/Test_regSquareWFactors_regSquareWFactors_inv.mo b/SorpLib/Numerics/Testers/Test_regSquareWFactors_regSquareWFactors_inv.mo new file mode 100644 index 0000000000000000000000000000000000000000..0fcc1a16893ee185b1c6ca25586ebb3dfd61cf55 --- /dev/null +++ b/SorpLib/Numerics/Testers/Test_regSquareWFactors_regSquareWFactors_inv.mo @@ -0,0 +1,70 @@ +within SorpLib.Numerics.Testers; +model Test_regSquareWFactors_regSquareWFactors_inv + "Tester for the functions 'regSquareWFactors' and 'regSquareWFactors_inv'" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real delta_x = 0.001 + "Defines region (-delta_x < x < delta_x) used to approximate square by a 3rd + order polynomial" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real f_positive = 2 + "Multplicator for x > 0" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real f_negative = 2 + "Multiplicator for x < 0" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of variables + // + Real x(start=-1.5, fixed=true) + "Abscissa value used for square aprroximation"; + + Real app_square = SorpLib.Numerics.regSquareWFactors( + x=x, delta_x=delta_x, f_positive=f_positive, f_negative=f_negative) + "Approximated square"; + Real dapp_square_dtau + "First derivative of app_square wrt. time"; + Real d2app_square_d2tau + "Second derivative of app_square wrt. time"; + + Real x_inv = SorpLib.Numerics.regSquareWFactors_inv( + y=app_square, delta_x=delta_x, f_positive=f_positive, f_negative=f_negative) + "Calculate inverse of function 'regSquare'"; + +equation + der(x) = 0.1 + "Predescribed slope of x to demonstrate function 'regSquare'"; + der(app_square) = dapp_square_dtau + "First derivative of app_square wrt. time"; + der(dapp_square_dtau) = d2app_square_d2tau + "Second derivative of app_square wrt. time"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=30, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the functions 'regSquareWFactors' and +'regSquare_invWFactors.' The approximation range can be influenced using the +value <i>delta_x</i>: Larger values cause a greater transition region than +smaller values. +<br/><br/> +To see the behavior of the approximated square, plot the variable <i>app_square</i> +over the variable <i>x</i>. To see the behavior of the inverse function, plot the +variables <i>x</i> and <i>x_inv</i> over the variable <i>x</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 30 s). +</p> +</html>")); +end Test_regSquareWFactors_regSquareWFactors_inv; diff --git a/SorpLib/Numerics/Testers/Test_regSquareWFactors_regSquareWFactors_inv_noEvent.mo b/SorpLib/Numerics/Testers/Test_regSquareWFactors_regSquareWFactors_inv_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..8911b48e83f4e60f6b1978663dea438abe11e8e6 --- /dev/null +++ b/SorpLib/Numerics/Testers/Test_regSquareWFactors_regSquareWFactors_inv_noEvent.mo @@ -0,0 +1,70 @@ +within SorpLib.Numerics.Testers; +model Test_regSquareWFactors_regSquareWFactors_inv_noEvent + "Tester for the functions 'regSquareWFactors_noEvent' and 'regSquareWFactors_inv_noEvent'" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real delta_x = 0.1 + "Defines region (-delta_x < x < delta_x) used to approximate square by a 3rd + order polynomial" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real f_positive = 2 + "Multplicator for x > 0" + annotation (Dialog(tab="General", group="Parameters")); + parameter Real f_negative = 2 + "Multiplicator for x < 0" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of variables + // + Real x(start=-1.5, fixed=true) + "Abscissa value used for square aprroximation"; + + Real app_square = SorpLib.Numerics.regSquareWFactors_noEvent( + x=x, delta_x=delta_x, f_positive=f_positive, f_negative=f_negative) + "Approximated square"; + Real dapp_square_dtau + "First derivative of app_square wrt. time"; + Real d2app_square_d2tau + "Second derivative of app_square wrt. time"; + + Real x_inv = SorpLib.Numerics.regSquareWFactors_inv_noEvent( + y=app_square, delta_x=delta_x, f_positive=f_positive, f_negative=f_negative) + "Calculate inverse of function 'regSquare'"; + +equation + der(x) = 0.1 + "Predescribed slope of x to demonstrate function 'regSquare'"; + der(app_square) = dapp_square_dtau + "First derivative of app_square wrt. time"; + der(dapp_square_dtau) = d2app_square_d2tau + "Second derivative of app_square wrt. time"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=30, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the functions 'regSquareWFactors_noEvent' and +'regSquare_invWFactors_noEvent.' The approximation range can be influenced using +the value <i>delta_x</i>: Larger values cause a greater transition region than +smaller values. +<br/><br/> +To see the behavior of the approximated square, plot the variable <i>app_square</i> +over the variable <i>x</i>. To see the behavior of the inverse function, plot the +variables <i>x</i> and <i>x_inv</i> over the variable <i>x</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 30 s). +</p> +</html>")); +end Test_regSquareWFactors_regSquareWFactors_inv_noEvent; diff --git a/SorpLib/Numerics/Testers/Test_regSquare_noEvent_regSquare_inv_noEvent.mo b/SorpLib/Numerics/Testers/Test_regSquare_noEvent_regSquare_inv_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..1c5924449b9100bdd6a4a4e16cdfb598da753169 --- /dev/null +++ b/SorpLib/Numerics/Testers/Test_regSquare_noEvent_regSquare_inv_noEvent.mo @@ -0,0 +1,62 @@ +within SorpLib.Numerics.Testers; +model Test_regSquare_noEvent_regSquare_inv_noEvent + "Tester for the functions 'regSquare_noEvent' and 'regSquare_inv_noEvent'" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real delta_x = 0.1 + "Defines region (-delta_x < x < delta_x) used to approximate square by a 3rd + order polynomial" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of variables + // + Real x(start=-1.5, fixed=true) + "Abscissa value used for square aprroximation"; + + Real app_square = SorpLib.Numerics.regSquare_noEvent(x=x, delta_x=delta_x) + "Approximated square"; + Real dapp_square_dtau + "First derivative of app_square wrt. time"; + Real d2app_square_d2tau + "Second derivative of app_square wrt. time"; + + Real x_inv = SorpLib.Numerics.regSquare_inv_noEvent(y=app_square, delta_x=delta_x) + "Calculate inverse of function 'regSquare'"; + +equation + der(x) = 0.1 + "Predescribed slope of x to demonstrate function 'regSquare'"; + der(app_square) = dapp_square_dtau + "First derivative of app_square wrt. time"; + der(dapp_square_dtau) = d2app_square_d2tau + "Second derivative of app_square wrt. time"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=30, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the functions 'regSquare_noEvent' and +'regSquare_inv_noEvent.' The approximation range can be influenced using the +value <i>delta_x</i>: Larger values cause a greater transition region than +smaller values. +<br/><br/> +To see the behavior of the approximated square, plot the variable <i>app_square</i> +over the variable <i>x</i>. To see the behavior of the inverse function, plot the +variables <i>x</i> and <i>x_inv</i> over the variable <i>x</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 30 s). +</p> +</html>")); +end Test_regSquare_noEvent_regSquare_inv_noEvent; diff --git a/SorpLib/Numerics/Testers/Test_regSquare_regSquare_inv.mo b/SorpLib/Numerics/Testers/Test_regSquare_regSquare_inv.mo new file mode 100644 index 0000000000000000000000000000000000000000..4d809cdcced93d279a78a5173675950ce941e91e --- /dev/null +++ b/SorpLib/Numerics/Testers/Test_regSquare_regSquare_inv.mo @@ -0,0 +1,61 @@ +within SorpLib.Numerics.Testers; +model Test_regSquare_regSquare_inv + "Tester for the functions 'regSquare' and 'regSquare_inv'" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real delta_x = 0.1 + "Defines region (-delta_x < x < delta_x) used to approximate square by a 3rd + order polynomial" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of variables + // + Real x(start=-1.5, fixed=true) + "Abscissa value used for square aprroximation"; + + Real app_square = SorpLib.Numerics.regSquare(x=x, delta_x=delta_x) + "Approximated square"; + Real dapp_square_dtau + "First derivative of app_square wrt. time"; + Real d2app_square_d2tau + "Second derivative of app_square wrt. time"; + + Real x_inv = SorpLib.Numerics.regSquare_inv(y=app_square, delta_x=delta_x) + "Calculate inverse of function 'regSquare'"; + +equation + der(x) = 0.1 + "Predescribed slope of x to demonstrate function 'regSquare'"; + der(app_square) = dapp_square_dtau + "First derivative of app_square wrt. time"; + der(dapp_square_dtau) = d2app_square_d2tau + "Second derivative of app_square wrt. time"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=30, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the functions 'regSquare' and 'regSquare_inv.' +The approximation range can be influenced using the value <i>delta_x</i>: Larger +values cause a greater transition region than smaller values. +<br/><br/> +To see the behavior of the approximated square, plot the variable <i>app_square</i> +over the variable <i>x</i>. To see the behavior of the inverse function, plot the +variables <i>x</i> and <i>x_inv</i> over the variable <i>x</i>. The simulation +time is correctly preset (Start: 0 s, Stop = 30 s). +</p> +</html>")); +end Test_regSquare_regSquare_inv; diff --git a/SorpLib/Numerics/Testers/Test_regStep.mo b/SorpLib/Numerics/Testers/Test_regStep.mo new file mode 100644 index 0000000000000000000000000000000000000000..e42f16d5d2b100d7872f7bd9c6b2940d144c4d66 --- /dev/null +++ b/SorpLib/Numerics/Testers/Test_regStep.mo @@ -0,0 +1,50 @@ +within SorpLib.Numerics.Testers; +model Test_regStep "Tester for the function 'regStep'" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real x_small = 0 + "Defines region (-x_small < x < x_small) used to approximate step by a 2nd + order polynomial" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of variables + // + Real x(start=-1, fixed=true) + "Abscissa value used for step"; + + Real reg_value = SorpLib.Numerics.regStep(x=x, y1=-1, y2=1, x_small=x_small) + "Regulated step"; + +equation + der(x) = 0.1 + "Predecsriped slope of x to demonstrate function 'regStep'"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=20, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'regStep' function. For example, the +function steps from <i>y1 = -1</i> (<i>x > 0</i>) to <i>y2 = 1</i> (<i>x +< 0</i>) at <i>x = 0</i>. The step characteristic at <i>x = 0</i> can be +influenced using the transition value <i>x_small</i>: Larger values cause a +smoother transition than smaller values. +<br/><br/> +To see the jump behavior, plot the variable <i>reg_value</i> over the +variable <i>x</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 20 s). +</p> +</html>")); +end Test_regStep; diff --git a/SorpLib/Numerics/Testers/Test_regStep_noEvent.mo b/SorpLib/Numerics/Testers/Test_regStep_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..a623277d0ecdd4a656f07ca8f0be855daf0fdd87 --- /dev/null +++ b/SorpLib/Numerics/Testers/Test_regStep_noEvent.mo @@ -0,0 +1,50 @@ +within SorpLib.Numerics.Testers; +model Test_regStep_noEvent "Tester for the function 'regStep_noEvent'" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real x_small = 0 + "Defines region (-x_small < x < x_small) used to approximate step by a 2nd + order polynomial" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of variables + // + Real x(start=-1, fixed=true) + "Abscissa value used for step"; + + Real reg_value = SorpLib.Numerics.regStep_noEvent(x=x, y1=-1, y2=1, x_small=x_small) + "Regulated step"; + +equation + der(x) = 0.1 + "Predecsriped slope of x to demonstrate function 'regStep'"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=20, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'regStep_noEvent' function. For example, the +function steps from <i>y1 = -1</i> (<i>x > 0</i>) to <i>y2 = 1</i> (<i>x +< 0</i>) at <i>x = 0</i>. The step characteristic at <i>x = 0</i> can be +influenced using the transition value <i>x_small</i>: Larger values cause a +smoother transition than smaller values. +<br/><br/> +To see the jump behavior, plot the variable <i>reg_value</i> over the +variable <i>x</i>. The simulation time is correctly preset (Start: 0 s, +Stop = 20 s). +</p> +</html>")); +end Test_regStep_noEvent; diff --git a/SorpLib/Numerics/Testers/Test_smoothTransition.mo b/SorpLib/Numerics/Testers/Test_smoothTransition.mo new file mode 100644 index 0000000000000000000000000000000000000000..fcb124cb3d7dbe4a0bceb45d1ffb96cc7f7b7b1d --- /dev/null +++ b/SorpLib/Numerics/Testers/Test_smoothTransition.mo @@ -0,0 +1,60 @@ +within SorpLib.Numerics.Testers; +model Test_smoothTransition + "Tester for the function 'smoothTransition' and its derivatives" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real transitionLength = 1 + "Defines transition length around transition point" + annotation (Dialog(tab="General", group="Parameters")); + parameter Integer noDiff = 1 + "Specification how often function can be differentiated (i.e., 1, 2 or 3)" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of variables + // + Real x(start=0, fixed=true) + "Abscissa value used for step"; + + Real weightingFactor = SorpLib.Numerics.smoothTransition(x=x, + transitionPoint=1, transitionLength=transitionLength, noDiff=noDiff) + "Smooth transition from 1 to 0 around x = 1"; + Real dweightingFactor_dtau + "First derivative of weighting_factor wrt. time"; + Real d2weightingFactor_d2tau + "Second derivative of weighting_factor wrt. time"; + +equation + der(x) = 0.1 + "Predecsriped slope of x to demonstrate function 'smoothTransition'"; + der(weightingFactor) = dweightingFactor_dtau + "First derivative of weighting_factor wrt. time"; + der(dweightingFactor_dtau) = d2weightingFactor_d2tau + "Second derivative of weighting_factor wrt. time"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=20, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'smoothTransition' function. For example, +the function smoothly changes the output from 1 to 0 at <i>transitionPoint = 1</i> +within <i>transitionLlength = 1</i>. The change characteristic can be +influenced using the value <i>noDiff</i>. +<br/><br/> +To see the transition behavior, plot the variable <i>weightingFactor</i> over the +variable <i>x</i>. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_smoothTransition; diff --git a/SorpLib/Numerics/Testers/Test_smoothTransition_noEvent.mo b/SorpLib/Numerics/Testers/Test_smoothTransition_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..dac916f9fb980dcd3a68c05a6d618fcd3da99666 --- /dev/null +++ b/SorpLib/Numerics/Testers/Test_smoothTransition_noEvent.mo @@ -0,0 +1,60 @@ +within SorpLib.Numerics.Testers; +model Test_smoothTransition_noEvent + "Tester for the function 'smoothTransition_noEvent' and its derivatives" + extends Modelica.Icons.Example; + + // + // Definition of parameters + // + parameter Real transitionLength = 1 + "Defines transition length around transition point" + annotation (Dialog(tab="General", group="Parameters")); + parameter Integer noDiff = 1 + "Specification how often function can be differentiated (i.e., 1, 2 or 3)" + annotation (Dialog(tab="General", group="Parameters")); + + // + // Definition of variables + // + Real x(start=0, fixed=true) + "Abscissa value used for step"; + + Real weigthingFactor = SorpLib.Numerics.smoothTransition_noEvent(x=x, + transitionPoint=1, transitionLength=transitionLength, noDiff=noDiff) + "Smooth transition from 1 to 0 around x = 1"; + Real dweigthingFactor_dtau + "First derivative of weigthingFactor wrt. time"; + Real d2weigthingFactor_d2tau + "Second derivative of weigthingFactor wrt. time"; + +equation + der(x) = 0.1 + "Predescribed slope of x to demonstrate function 'smoothTransition'"; + der(weigthingFactor) = dweigthingFactor_dtau + "First derivative of weigthingFactor wrt. time"; + der(dweigthingFactor_dtau) = d2weigthingFactor_d2tau + "Second derivative of weigthingFactor wrt. time"; + + // + // Annotations + // + annotation (experiment(StartTime=0, StopTime=20, Tolerance=1e-6), +Documentation(revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This tester shows the behavior of the 'smoothTransition_noEvent' function. For example, +the function smoothly changes the output from 1 to 0 at <i>transitionPoint = 1</i> +within <i>transitionLength = 1</i>. The change characteristic can be +influenced using the value <i>noDiff</i>. +<br/><br/> +To see the transition behavior, plot the variable <i>weigthingFactor</i> over the +variable <i>x</i>. The simulation time is correctly preset (Start: 0 s, Stop = 20 s). +</p> +</html>")); +end Test_smoothTransition_noEvent; diff --git a/SorpLib/Numerics/Testers/package.mo b/SorpLib/Numerics/Testers/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..fa0fba975ca66074bef6e0d0d92f03a1c2a6ba78 --- /dev/null +++ b/SorpLib/Numerics/Testers/package.mo @@ -0,0 +1,20 @@ +within SorpLib.Numerics; +package Testers "Models to test and/or varify functions for numerical implementations" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info="<html> +<p> +This package contains executable test models for all functions of the 'Numerics' +package. The test models check the implementation of the functions and enable +verification of the function behavior. In addition, the test models demonstrate +the functions' general applicability. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Testers; diff --git a/SorpLib/Numerics/Testers/package.order b/SorpLib/Numerics/Testers/package.order new file mode 100644 index 0000000000000000000000000000000000000000..4b0a08233c5bd8288d68185e5f01c5690279d16a --- /dev/null +++ b/SorpLib/Numerics/Testers/package.order @@ -0,0 +1,8 @@ +Test_regStep +Test_regStep_noEvent +Test_smoothTransition +Test_smoothTransition_noEvent +Test_regSquare_regSquare_inv +Test_regSquare_noEvent_regSquare_inv_noEvent +Test_regSquareWFactors_regSquareWFactors_inv +Test_regSquareWFactors_regSquareWFactors_inv_noEvent diff --git a/SorpLib/Numerics/package.mo b/SorpLib/Numerics/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..6a87549f46522b035d4f3239db6fcd3ca09f7f0c --- /dev/null +++ b/SorpLib/Numerics/package.mo @@ -0,0 +1,35 @@ +within SorpLib; +package Numerics "Library containing utility function regarding numeric implementations" + extends Modelica.Icons.FunctionsPackage; + +annotation (Documentation(info="<html> +<p> +This package contains utility functions to implement models in a mathematically +"robust" way. Mathematical robustness refers to the following: +</p> +<ol> + <li> + Mathematical approximation of functions so that they are continuous and + differentiable at specific points. + </li> + <li> + Mathematical transition between function values so that the transition is + continuous and differentiable. + </li> + <li> + Avoidance of events. + </li> +</ol> +<p> +A mathematically robust implementation of models is essential in the context of +mathematical optimization. +</p> +</html>", revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end Numerics; diff --git a/SorpLib/Numerics/package.order b/SorpLib/Numerics/package.order new file mode 100644 index 0000000000000000000000000000000000000000..92aa2b74b97966d9e0b82f3e5faff503ff4bed29 --- /dev/null +++ b/SorpLib/Numerics/package.order @@ -0,0 +1,17 @@ +regStep +regStep_noEvent +smoothTransition +smoothTransition_der +smoothTransition_der2 +smoothTransition_noEvent +smoothTransition_der_noEvent +smoothTransition_der2_noEvent +regSquare +regSquare_inv +regSquare_noEvent +regSquare_inv_noEvent +regSquareWFactors +regSquareWFactors_inv +regSquareWFactors_noEvent +regSquareWFactors_inv_noEvent +Testers diff --git a/SorpLib/Numerics/regSquare.mo b/SorpLib/Numerics/regSquare.mo new file mode 100644 index 0000000000000000000000000000000000000000..6a551f8b7ddbc28fdf3023f418ad0c7ffb897c3d --- /dev/null +++ b/SorpLib/Numerics/regSquare.mo @@ -0,0 +1,97 @@ +within SorpLib.Numerics; +function regSquare + "Anti-symmetric square approximation with non-zero derivative in the origin" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Input value" + annotation (Dialog(tab="General", group="Inputs")); + input Real delta_x = 1e-4 + "Regulation value for approximation" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real y + "Approximated value" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + if x > delta_x then + y := x*x + "No approximation"; + + elseif x < -delta_x then + y := -x*x + "Keep sign of input"; + + else + y := (0.5/delta_x * x^2 + 0.5*delta_x) * x + "Transition region"; + + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=false, +LateInline=true, +smoothOrder=1, +inverse(x=regSquare_inv(y,delta_x)), +Documentation(info="<html> +<p><p> +This function is used to approximate the equation +</p> +<pre> + y = x<sup>2</sup>; +</pre> + +<p> +for (1) the slope to be non-zero at the origin, (2) the function to be continuous +and differentiable, and (3) the sign of the input to not change: +</p> + +<pre> + y = <strong>if</strong> x > delta_x <strong>then</strong> x<sup>2</sup> <strong>else</strong> + <strong>if</strong> x < -delta_x <strong>then</strong> -x<sup>2</sup> <strong>else</strong> + 0.5 * x * (x<sup>2</sup> / delta_x + delta_x); +</pre> + +<p> +In the region -delta_x < x < delta_x a 3rd order polynomial is used. +</p> + +<h4>Typical use</h4> +<p> +This function is used, for example, to calculate pressure drop correlations. +</p> + +<h4>Example</h4> +<p> +The following figure shows the approximated square for different values of <i>delta_x</i>. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/numerics_regSquare.png\" alt=\"numerics_regSquare.png\"> + +<h4>References</h4> +<p> +The function is based on the MSL library +(<a href=\"Modelica://Modelica.Fluid.Utilities.regSquare\">Modelica.Fluid.Utilities.regSquare</a>) +and TIL library +(<a href=\"Modelica://TIL.Utilities.Numerics.squareFunction\">TIL.Utilities.Numerics.squareFunction</a>) +and has been slightly adapted. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end regSquare; diff --git a/SorpLib/Numerics/regSquareWFactors.mo b/SorpLib/Numerics/regSquareWFactors.mo new file mode 100644 index 0000000000000000000000000000000000000000..d96ad1cad827003aa882273aadb5cc8596fd2786 --- /dev/null +++ b/SorpLib/Numerics/regSquareWFactors.mo @@ -0,0 +1,140 @@ +within SorpLib.Numerics; +function regSquareWFactors + "Anti-symmetric square (with discontinuous factors) approximation with non-zero derivative in the origin" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Input value" + annotation (Dialog(tab="General", group="Inputs")); + input Real delta_x = 1e-4 + "Regulation value for approximation" + annotation (Dialog(tab="General", group="Inputs")); + input Real f_positive(min=0) = 1 + "Factor for x > 0 (must be >= 0)" + annotation (Dialog(tab="General", group="Inputs")); + input Real f_negative(min=0) = 1 + "Factor for x < 0 (must be >= 0)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real y + "Approximated value" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real f + "Factor"; + +algorithm + // + // Calculate factor + // + if x > 0 then + f := f_positive + "Factor"; + + elseif x < 0 then + f := f_negative + "Factor"; + + else + f := (f_positive + f_negative) / 2 + "Factor"; + end if; + + // + // Approximate value + // + if Modelica.Math.isEqual(s1=f, s2=0, eps=Modelica.Constants.small) then + y := Modelica.Constants.inf + "No finite solution"; + + elseif x > delta_x then + y := x*x / f + "No approximation"; + + elseif x < -delta_x then + y := -x*x / f + "Keep sign of input"; + + else + y := (0.5/delta_x * x^2 + 0.5*delta_x) * x / f + "Transition region"; + + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=false, +LateInline=true, +smoothOrder=1, +inverse(x=regSquareWFactors_inv(y,delta_x,f_positive,f_negative)), +Documentation(info="<html> +<p><p> +This function is used to approximate the equation +</p> +<pre> + y = x<sup>2</sup> / f; +</pre> +<p> +with the factor <i>f</i> beeing dependent on the flow direction: +</p> +<pre> + f = <strong>if</strong> x > 0 <strong>then</strong> f_positive <strong>elseif</strong> x < 0 <strong>then</strong> f_negative <strong>else</strong> (f_positive + f_negative) / 2; +</pre> +<p> +for (1) the slope to be non-zero at the origin, (2) the function to be continuous +and differentiable, and (3) the sign of the input to not change: +</p> + +<pre> + y = <strong>if</strong> x > delta_x <strong>then</strong> x<sup>2</sup> / f <strong>else</strong> + <strong>if</strong> x < -delta_x <strong>then</strong> -x<sup>2</sup> / f <strong>else</strong> + 0.5 * x * (x<sup>2</sup> / delta_x + delta_x) / f; +</pre> + +<p> +In the region -delta_x < x < delta_x, a 3rd order polynomial is used. +</p> + +<h4>Typical use</h4> +<p> +This function is used, for example, to calculate mass flow rates depending on +prssure drops. +</p> + +<h4>Example</h4> +<p> +The following figure shows the approximated square for different values of +<i>delta_x</i>, <i>f_positive=3</i>, and <i>f_negative=2</i>. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/numerics_regSquareWFactors.png\" alt=\"numerics_regSquareWFactors.png\"> + +<h4>References</h4> +<p> +The function is based on the MSL library +(<a href=\"Modelica://Modelica.Fluid.Utilities.regSquare2\">Modelica.Fluid.Utilities.regSquare2</a>) +and TIL library +(<a href=\"Modelica://TIL.Utilities.Numerics.inverseSquareRootFunctionWithFactorRevised\">TIL.Utilities.Numerics.inverseSquareRootFunctionWithFactorRevised</a>) +and has been slightly adapted. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end regSquareWFactors; diff --git a/SorpLib/Numerics/regSquareWFactors_inv.mo b/SorpLib/Numerics/regSquareWFactors_inv.mo new file mode 100644 index 0000000000000000000000000000000000000000..a95ac9f83baf1029668cd8e3967f8c171733855d --- /dev/null +++ b/SorpLib/Numerics/regSquareWFactors_inv.mo @@ -0,0 +1,99 @@ +within SorpLib.Numerics; +function regSquareWFactors_inv + "Inverse function of the anti-symmetric square (with discontinuous factors) approximation with non-zero derivative in the origin" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real y + "Approximated value" + annotation (Dialog(tab="General", group="Inputs")); + input Real delta_x = 1e-4 + "Regulation value for approximation" + annotation (Dialog(tab="General", group="Inputs")); + input Real f_positive(min=0) = 1 + "Factor for x > 0 (must be >= 0)" + annotation (Dialog(tab="General", group="Inputs")); + input Real f_negative(min=0) = 1 + "Factor for x < 0 (must be >= 0)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real x + "Original input value" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real f + "Factor"; + +algorithm + // + // Calculate factor + // + if y > 0 then + f := f_positive + "Factor"; + + elseif y < 0 then + f := f_negative + "Factor"; + + else + f := (f_positive + f_negative) / 2 + "Factor"; + end if; + + // + // Approximate value + // + if Modelica.Math.isEqual(s1=f, s2=0, eps=Modelica.Constants.small) then + x := 0 + "No finite solution"; + + elseif y > delta_x * delta_x / f then + x := sqrt(y * f) + "No approximation"; + + elseif y < -delta_x * delta_x / f then + x := -sqrt(-y * f) + "Keep sign of input"; + + else + x := delta_x^2 / + (-27*delta_x*y*f + sqrt(108*delta_x^6 + 2916*delta_x^2*y^2*f^2)/2)^(1/3) - + (-27*delta_x*y*f + sqrt(108*delta_x^6 + 2916*delta_x^2*y^2*f^2)/2)^(1/3) / 3 + "Transition region: Solving cubic equations and discarding complex + solutions"; + + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=false, +LateInline=true, +smoothOrder=1, +inverse(y=regSquareWFactors(x,delta_x,f_positive,f_negative)), +Documentation(info="<html> +<p> +This function is the inverse function of the function 'regSquareWFactors.' For full +details, check the documentation of the function +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors\">SorpLib.Numerics.regSquareWFactors</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end regSquareWFactors_inv; diff --git a/SorpLib/Numerics/regSquareWFactors_inv_noEvent.mo b/SorpLib/Numerics/regSquareWFactors_inv_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..fa296901aa6c1fe6898c30e3e6a02692f84a653d --- /dev/null +++ b/SorpLib/Numerics/regSquareWFactors_inv_noEvent.mo @@ -0,0 +1,99 @@ +within SorpLib.Numerics; +function regSquareWFactors_inv_noEvent + "Inverse function of the anti-symmetric square (with discontinuous factors) approximation with non-zero derivative in the origin (without events)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real y + "Approximated value" + annotation (Dialog(tab="General", group="Inputs")); + input Real delta_x = 1e-4 + "Regulation value for approximation" + annotation (Dialog(tab="General", group="Inputs")); + input Real f_positive(min=0) = 1 + "Factor for x > 0 (must be >= 0)" + annotation (Dialog(tab="General", group="Inputs")); + input Real f_negative(min=0) = 1 + "Factor for x < 0 (must be >= 0)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real x + "Original input value" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real f + "Factor"; + +algorithm + // + // Calculate factor + // + if noEvent(y > 0) then + f := f_positive + "Factor"; + + elseif noEvent(y < 0) then + f := f_negative + "Factor"; + + else + f := (f_positive + f_negative) / 2 + "Factor"; + end if; + + // + // Approximate value + // + if noEvent(Modelica.Math.isEqual(s1=f, s2=0, eps=Modelica.Constants.small)) then + x := 0 + "No finite solution"; + + elseif noEvent(y > delta_x * delta_x / f) then + x := sqrt(y * f) + "No approximation"; + + elseif noEvent(y < -delta_x * delta_x / f) then + x := -sqrt(-y * f) + "Keep sign of input"; + + else + x := delta_x^2 / + (-27*delta_x*y*f + sqrt(108*delta_x^6 + 2916*delta_x^2*y^2*f^2)/2)^(1/3) - + (-27*delta_x*y*f + sqrt(108*delta_x^6 + 2916*delta_x^2*y^2*f^2)/2)^(1/3) / 3 + "Transition region: Solving cubic equations and discarding complex + solutions"; + + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=false, +LateInline=true, +smoothOrder=1, +inverse(y=regSquareWFactors_noEvent(x,delta_x,f_positive,f_negative)), +Documentation(info="<html> +<p> +This function is the inverse function of the function 'regSquareWFactors.' For full +details, check the documentation of the function +<a href=\"Modelica://SorpLib.Numerics.regSquareWFactors_noEvent\">SorpLib.Numerics.regSquareWFactors_noEvent</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end regSquareWFactors_inv_noEvent; diff --git a/SorpLib/Numerics/regSquareWFactors_noEvent.mo b/SorpLib/Numerics/regSquareWFactors_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..b56d7947184fc78a470b35593a1afb748ed5cbef --- /dev/null +++ b/SorpLib/Numerics/regSquareWFactors_noEvent.mo @@ -0,0 +1,140 @@ +within SorpLib.Numerics; +function regSquareWFactors_noEvent + "Anti-symmetric square (with discontinuous factors) approximation with non-zero derivative in the origin (without events)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Input value" + annotation (Dialog(tab="General", group="Inputs")); + input Real delta_x = 1e-4 + "Regulation value for approximation" + annotation (Dialog(tab="General", group="Inputs")); + input Real f_positive(min=0) = 1 + "Factor for x > 0 (must be >= 0)" + annotation (Dialog(tab="General", group="Inputs")); + input Real f_negative(min=0) = 1 + "Factor for x < 0 (must be >= 0)" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real y + "Approximated value" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + + // + // Definition of variables + // +protected + Real f + "Factor"; + +algorithm + // + // Calculate factor + // + if noEvent(x > 0) then + f := f_positive + "Factor"; + + elseif noEvent(x < 0) then + f := f_negative + "Factor"; + + else + f := (f_positive + f_negative) / 2 + "Factor"; + end if; + + // + // Approximate value + // + if noEvent(Modelica.Math.isEqual(s1=f, s2=0, eps=Modelica.Constants.small)) then + y := Modelica.Constants.inf + "No finite solution"; + + elseif noEvent(x > delta_x) then + y := x*x / f + "No approximation"; + + elseif noEvent(x < -delta_x) then + y := -x*x / f + "Keep sign of input"; + + else + y := (0.5/delta_x * x^2 + 0.5*delta_x) * x / f + "Transition region"; + + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=false, +LateInline=true, +smoothOrder=1, +inverse(x=regSquareWFactors_inv_noEvent(y,delta_x,f_positive,f_negative)), +Documentation(info="<html> +<p><p> +This function is used to approximate the equation +</p> +<pre> + y = x<sup>2</sup> / f; +</pre> +<p> +with the factor <i>f</i> beeing dependent on the flow direction: +</p> +<pre> + f = <strong>if</strong> x > 0 <strong>then</strong> f_positive <strong>elseif</strong> x < 0 <strong>then</strong> f_negative <strong>else</strong> (f_positive + f_negative) / 2; +</pre> +<p> +for (1) the slope to be non-zero at the origin, (2) the function to be continuous +and differentiable, and (3) the sign of the input to not change: +</p> + +<pre> + y = <strong>if</strong> x > delta_x <strong>then</strong> x<sup>2</sup> / f <strong>else</strong> + <strong>if</strong> x < -delta_x <strong>then</strong> -x<sup>2</sup> / f <strong>else</strong> + 0.5 * x * (x<sup>2</sup> / delta_x + delta_x) / f; +</pre> + +<p> +In the region -delta_x < x < delta_x, a 3rd order polynomial is used. +</p> + +<h4>Typical use</h4> +<p> +This function is used, for example, to calculate mass flow rates depending on +prssure drops. +</p> + +<h4>Example</h4> +<p> +The following figure shows the approximated square for different values of +<i>delta_x</i>, <i>f_positive=3</i>, and <i>f_negative=2</i>. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/numerics_regSquareWFactors.png\" alt=\"numerics_regSquareWFactors.png\"> + +<h4>References</h4> +<p> +The function is based on the MSL library +(<a href=\"Modelica://Modelica.Fluid.Utilities.regSquare2\">Modelica.Fluid.Utilities.regSquare2</a>) +and TIL library +(<a href=\"Modelica://TIL.Utilities.Numerics.inverseSquareRootFunctionWithFactorRevised\">TIL.Utilities.Numerics.inverseSquareRootFunctionWithFactorRevised</a>) +and has been slightly adapted. +</p> +</html>", revisions="<html> +<ul> + <li> + December 19, 2023, by Mirko Engelpracht:<br/> + First implementation. + </li> +</ul> +</html>")); +end regSquareWFactors_noEvent; diff --git a/SorpLib/Numerics/regSquare_inv.mo b/SorpLib/Numerics/regSquare_inv.mo new file mode 100644 index 0000000000000000000000000000000000000000..a78756069aa043b1f2fb1ff70fa58874d7d1d35b --- /dev/null +++ b/SorpLib/Numerics/regSquare_inv.mo @@ -0,0 +1,62 @@ +within SorpLib.Numerics; +function regSquare_inv + "Inverse function of the anti-symmetric square approximation with non-zero derivative in the origin" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real y + "Approximated value" + annotation (Dialog(tab="General", group="Inputs")); + input Real delta_x = 1e-4 + "Regulation value for approximation" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real x + "Input value" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + if (y > delta_x*delta_x) then + x := sqrt(y) + "No approximation"; + + elseif (y < -delta_x*delta_x) then + x := -sqrt(-y) + "Keep sign of input"; + + else + x := delta_x^2 / + (-27*delta_x*y + sqrt(108*delta_x^6 + 2916*delta_x^2*y^2)/2)^(1/3) - + (-27*delta_x*y + sqrt(108*delta_x^6 + 2916*delta_x^2*y^2)/2)^(1/3) / 3 + "Transition region: Solving cubic equations and discarding complex + solutions"; + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=false, +LateInline=true, +smoothOrder=1, +inverse(y=regSquare(x,delta_x)), +Documentation(info="<html> +<p> +This function is the inverse function of the function 'regSquare.' For full +details, check the documentation of the function +<a href=\"Modelica://SorpLib.Numerics.regSquare\">SorpLib.Numerics.regSquare</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end regSquare_inv; diff --git a/SorpLib/Numerics/regSquare_inv_noEvent.mo b/SorpLib/Numerics/regSquare_inv_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..256f4e28b022c560b1d32375c6c72f7f11184c81 --- /dev/null +++ b/SorpLib/Numerics/regSquare_inv_noEvent.mo @@ -0,0 +1,62 @@ +within SorpLib.Numerics; +function regSquare_inv_noEvent + "Inverse function of the anti-symmetric square approximation with non-zero derivative in the origin (without events)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real y + "Approximated value" + annotation (Dialog(tab="General", group="Inputs")); + input Real delta_x = 1e-4 + "Regulation value for approximation" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real x + "Input value" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + if noEvent(y > delta_x*delta_x) then + x := sqrt(y) + "No approximation"; + + elseif noEvent(y < -delta_x*delta_x) then + x := -sqrt(-y) + "Keep sign of input"; + + else + x := delta_x^2 / + (-27*delta_x*y + sqrt(108*delta_x^6 + 2916*delta_x^2*y^2)/2)^(1/3) - + (-27*delta_x*y + sqrt(108*delta_x^6 + 2916*delta_x^2*y^2)/2)^(1/3) / 3 + "Transition region: Solving cubic equations and discarding complex + solutions"; + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=false, +LateInline=true, +smoothOrder=1, +inverse(y=regSquare_noEvent(x,delta_x)), +Documentation(info="<html> +<p> +This function is the inverse function of the function 'regSquare_noEvent.' For +full details, check the documentation of the function +<a href=\"Modelica://SorpLib.Numerics.regSquare_noEvent\">SorpLib.Numerics.regSquare_noEvent</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end regSquare_inv_noEvent; diff --git a/SorpLib/Numerics/regSquare_noEvent.mo b/SorpLib/Numerics/regSquare_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..64c1481c52a985de10e12563c9cf559fdf5979fb --- /dev/null +++ b/SorpLib/Numerics/regSquare_noEvent.mo @@ -0,0 +1,98 @@ +within SorpLib.Numerics; +function regSquare_noEvent + "Anti-symmetric square approximation with non-zero derivative in the origin (without events)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Input value" + annotation (Dialog(tab="General", group="Inputs")); + input Real delta_x = 1e-4 + "Regulation value for approximation" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real y + "Approximated value" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + if noEvent(x > delta_x) then + y := x*x + "No approximation"; + + elseif noEvent(x < -delta_x) then + y := -x*x + "Keep sign of input"; + + else + y := (0.5/delta_x * x^2 + 0.5*delta_x) * x + "Transition region"; + + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=false, +LateInline=true, +smoothOrder=1, +inverse(x=regSquare_inv_noEvent(y,delta_x)), +Documentation(info="<html> +<p><p> +This function is used to approximate the equation +</p> +<pre> + y = x<sup>2</sup>; +</pre> + +<p> +for (1) the slope to be non-zero at the origin, (2) the function to be continuous +and differentiable, (3) the sign of the input to not change, and (4) no events to +occur: +</p> + +<pre> + y = <strong>if</strong> x > delta_x <strong>then</strong> x<sup>2</sup> <strong>else</strong> + <strong>if</strong> x < -delta_x <strong>then</strong> -x<sup>2</sup> <strong>else</strong> + 0.5 * x * (x<sup>2</sup> / delta_x + delta_x); +</pre> + +<p> +In the region -delta_x < x < delta_x a 3rd order polynomial is used. +</p> + +<h4>Typical use</h4> +<p> +This function is used, for example, to calculate pressure drop correlations. +</p> + +<h4>Example</h4> +<p> +The following figure shows the approximated square for different values of <i>delta_x</i>. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/numerics_regSquare.png\" alt=\"numerics_regSquare.png\"> + +<h4>References</h4> +<p> +The function is based on the MSL library +(<a href=\"Modelica://Modelica.Fluid.Utilities.regSquare\">Modelica.Fluid.Utilities.regSquare</a>) +and TIL library +(<a href=\"Modelica://TIL.Utilities.Numerics.squareFunction\">TIL.Utilities.Numerics.squareFunction</a>) +and has been slightly adapted. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end regSquare_noEvent; diff --git a/SorpLib/Numerics/regStep.mo b/SorpLib/Numerics/regStep.mo new file mode 100644 index 0000000000000000000000000000000000000000..8f2d7496f9d1b68f4577332cd7aba093f285ad23 --- /dev/null +++ b/SorpLib/Numerics/regStep.mo @@ -0,0 +1,84 @@ +within SorpLib.Numerics; +function regStep + "Approximation of a general step to get a continuous and differentiable characteristic" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Abscissa value" + annotation (Dialog(tab="General", group="Inputs")); + input Real y1 + "Ordinate value for x > 0" + annotation (Dialog(tab="General", group="Inputs")); + input Real y2 + "Ordinate value for x < 0" + annotation (Dialog(tab="General", group="Inputs")); + input Real x_small(min=0) = 1e-5 + "Approximation of step for -x_small <= x <= x_small; x_small >= 0 required" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real y + "Ordinate value to approximate y = if x > 0 then y1 else y2" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + y := smooth(1, if x > x_small then y1 else + if x < -x_small then y2 else + if x_small > 0 then + (x/x_small)*((x/x_small)^2 - 3)*(y2-y1)/4 + (y1+y2)/2 else + (y1+y2)/2) + "Smooth transition"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is used to approximate the equation +</p> +<pre> + y = <strong>if</strong> x > 0 <strong>then</strong> y1 <strong>else</strong> y2; +</pre> + +<p> +by a smooth characteristic to get a continuous and differentiable expression: +</p> + +<pre> + y = <strong>smooth</strong>(1, <strong>if</strong> x > x_small <strong>then</strong> y1 <strong>else</strong> + <strong>if</strong> x < -x_small <strong>then</strong> y2 <strong>else</strong> f(y1, y2)); +</pre> + +<p> +In the region -x_small < x < x_small a 2nd order polynomial is used +for a smooth transition from y1 to y2. +</p> + +<h4>Example</h4> +<p> +The following figure shows the smooth characteristic for different values of +<i>x_small</i>, <i>y1 = -1</i>, and <i>y2 = 1</i>. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/numerics_regStep.png\" alt=\"numerics_regStep.png\"> + +<h4>References</h4> +<p> +The function and documentation are taken from the Modelica standard library +(<a href=\"Modelica://Modelica.Fluid.Utilities.regStep\">Modelica.Fluid.Utilities.regStep</a>) +and have been slightly adapted. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end regStep; diff --git a/SorpLib/Numerics/regStep_noEvent.mo b/SorpLib/Numerics/regStep_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..6d3b53d33a01fcd06e5a79e0c1208878bffd108f --- /dev/null +++ b/SorpLib/Numerics/regStep_noEvent.mo @@ -0,0 +1,86 @@ +within SorpLib.Numerics; +function regStep_noEvent + "Approximation of a general step to get a continuous and differentiable characteristic (without events)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Abscissa value" + annotation (Dialog(tab="General", group="Inputs")); + input Real y1 + "Ordinate value for x > 0" + annotation (Dialog(tab="General", group="Inputs")); + input Real y2 + "Ordinate value for x < 0" + annotation (Dialog(tab="General", group="Inputs")); + input Real x_small(min=0) = 1e-5 + "Approximation of step for -x_small <= x <= x_small; x_small >= 0 required" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real y + "Ordinate value to approximate y = if x > 0 then y1 else y2" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +algorithm + y := smooth(1, + noEvent(if x > x_small then y1 else + if x < -x_small then y2 else + if x_small > 0 then + (x/x_small)*((x/x_small)^2 - 3)*(y2-y1)/4 + (y1+y2)/2 else + (y1+y2)/2)) + "Smooth transition"; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is used to approximate the equation +</p> +<pre> + y = <strong>if</strong> x > 0 <strong>then</strong> y1 <strong>else</strong> y2; +</pre> + +<p> +by a smooth characteristic to get a continuous and differentiable expression +and events are avoided: +</p> + +<pre> + y = <strong>smooth</strong>(1, <strong>if</strong> x > x_small <strong>then</strong> y1 <strong>else</strong> + <strong>if</strong> x < -x_small <strong>then</strong> y2 <strong>else</strong> f(y1, y2)); +</pre> + +<p> +In the region -x_small < x < x_small a 2nd order polynomial is used +for a smooth transition from y1 to y2. +</p> + +<h4>Example</h4> +<p> +The following figure shows the smooth characteristic for different values of +<i>x_small</i>, <i>y1 = -1</i>, and <i>y2 = 1</i>. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/numerics_regStep.png\" alt=\"numerics_regStep.png\"> + +<h4>References</h4> +<p> +The function and documentation are taken from the Modelica standard library +(<a href=\"Modelica://Modelica.Fluid.Utilities.regStep\">Modelica.Fluid.Utilities.regStep</a>) +and have been slightly adapted. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end regStep_noEvent; diff --git a/SorpLib/Numerics/smoothTransition.mo b/SorpLib/Numerics/smoothTransition.mo new file mode 100644 index 0000000000000000000000000000000000000000..0585afc671fa2a6a9fbcd4173a2ff7c14a45934e --- /dev/null +++ b/SorpLib/Numerics/smoothTransition.mo @@ -0,0 +1,147 @@ +within SorpLib.Numerics; +function smoothTransition + "Smoothly changes the output from 1 to 0 around the transition point to get a continuous and differentiable transition" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Actual value" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionPoint=1 + "Transition point" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionLength=1 + "Transition length" + annotation (Dialog(tab="General", group="Inputs")); + input Integer noDiff = 1 + "Specification how often function can be differentiated (i.e., 1, 2 or 3)" + annotation (Dialog(tab="General", group="Numerics")); + + // + // Definition of outputs + // + output Real weigthingFactor + "Weighting factor" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +protected + Real phi + "Phase"; + +algorithm + if x < transitionPoint - 0.5*transitionLength then + weigthingFactor := 1 + "No transition region"; + + elseif x < transitionPoint + 0.5*transitionLength then + phi := (x - transitionPoint)*Modelica.Constants.pi/transitionLength + "Phase"; + + if noDiff == 1 then + weigthingFactor := -1.0/2.0 * sin(phi) + 1.0/2.0 + "Transition region"; + + elseif noDiff == 2 then + weigthingFactor := -1.0/2.0 * (2*cos(phi)*sin(phi) + + 2*phi - Modelica.Constants.pi) / Modelica.Constants.pi + "Transition region"; + + else + weigthingFactor := 1.0/6.0 * (-4.0*sin(phi)*cos(phi)^3 - + 6.0*phi - 3.0*sin(2.0*phi) + 3.0*Modelica.Constants.pi) / + Modelica.Constants.pi + "Transition region"; + + end if; + + else + weigthingFactor := 0 + "No transition region"; + + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=true, +derivative(order=1, + noDerivative=transitionPoint, + noDerivative=transitionLength, + noDerivative=noDiff) = smoothTransition_der, +Documentation(info="<html> +<p> +This function is used to smoothly change a weighting factor <i>WF</i> from 1 +to 0 at the specified point <i>transitionPoint</i> within the specified length +<i>transitionLength</i>. The change is continuous and differentiable, and the +type of change is specified via the parameter <i>noDiff</i>. +<br/><br/> +The change is described using trigonometric functions that depend on the current +phase <i>φ</i>: +</p> + +<pre> + φ = (x - transitionPoint) * π / transitionLength; +</pre> + +<p> +For <i>noDiff = 1</i>, the change is continuously differentiable once: +</p> + +<pre> + WF = -0.5 * <strong>sin</strong>(φ) + 0.5; +</pre> + +<p> +For <i>noDiff = 2</i>, the change can be continuously differentiated twice: +</p> + +<pre> + WF = -0.5 * (2 * <strong>cos</strong>(φ) * <strong>sin</strong>(φ) + 2 * φ - π) / π; +</pre> + +<p> +For <i>noDiff = 3</i>, the change can be continuously differentiated three times: +</p> + +<pre> + WF = 1/6 * (-4 * <strong>sin</strong>(φ) * <strong>cos</strong><sup>3</sup>(φ) - 6 * φ - 3 * <strong>sin</strong>(2 * φ) + 3 * π) / π; +</pre> + +<h4>Typical use</h4> +<p> +This function is used, for example, to switch smoothly between different flow +regimes when calculating heat or mass transport. For this purpose, the function +can be used as follows: +</p> + +<pre> + y = WF * y(Regime 1) + (1 - WF) * y(Regime 2); +</pre> + +<h4>Example</h4> +<p> +The following figure shows the smooth transition of the weighting factor +<i>WF</i> and its derivatives for different values of <i>noDiff</i> at +<i>transitionPoint = 1</i> for <i>transitionLength = 1</i>. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/numerics_smoothTransition.png\" alt=\"numerics_smoothTransition.png\"> + +<h4>References</h4> +<p> +The function is based on the TIL library +(<a href=\"Modelica://TIL.Utilities.Numerics.smoothTransition\">TIL.Utilities.Numerics.smoothTransition</a>) +and has been slightly adapted. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end smoothTransition; diff --git a/SorpLib/Numerics/smoothTransition_der.mo b/SorpLib/Numerics/smoothTransition_der.mo new file mode 100644 index 0000000000000000000000000000000000000000..590af2d094466fe39e8aff36f10eddb6a451351c --- /dev/null +++ b/SorpLib/Numerics/smoothTransition_der.mo @@ -0,0 +1,95 @@ +within SorpLib.Numerics; +function smoothTransition_der + "First derivative of function 'smoothTransition'" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Actual value" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionPoint=1 + "Transition point" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionLength=1 + "Transition length" + annotation (Dialog(tab="General", group="Inputs")); + input Integer noDiff = 1 + "Specification how often function can be differentiated (i.e., 1, 2 or 3)" + annotation (Dialog(tab="General", group="Numerics")); + + input Real x_der + "First derivative of actual value wrt. time" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real weigthingFactor + "First derivative of weighting factor" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +protected + Real phi + "Phase"; + Real dphi_dtau + "First derivative of phase wrt. time"; + +algorithm + if x < transitionPoint-0.5*transitionLength then + weigthingFactor := 0 + "No transition region"; + + elseif x < transitionPoint+0.5*transitionLength then + phi := (x - transitionPoint)*Modelica.Constants.pi/transitionLength + "Phase"; + dphi_dtau := x_der*Modelica.Constants.pi/transitionLength + "First derivative of weighting factor"; + + if noDiff == 1 then + weigthingFactor := -1.0/2.0 * cos(phi) * dphi_dtau + "Transition region"; + + elseif noDiff == 2 then + weigthingFactor := -dphi_dtau / Modelica.Constants.pi * + (cos(phi)^2 - sin(phi)^2 + 1) + "Transition region"; + + else + weigthingFactor := dphi_dtau / 3.0 / Modelica.Constants.pi * + (-2.0*cos(phi)^4 + 6.0*sin(phi)^2*cos(phi)^2 - 3.0 - 3.0*cos(2.0*phi)) + "Transition region"; + + end if; + + else + weigthingFactor := 0 + "No transition region"; + + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=true, +derivative(order=2, + noDerivative=transitionPoint, + noDerivative=transitionLength, + noDerivative=noDiff) = smoothTransition_der2, +Documentation(info="<html> +<p> +This function is the first derivative of the function 'smoothTransition' with +respect to time. For full details, check the documentation of the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition\">SorpLib.Numerics.smoothTransition</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end smoothTransition_der; diff --git a/SorpLib/Numerics/smoothTransition_der2.mo b/SorpLib/Numerics/smoothTransition_der2.mo new file mode 100644 index 0000000000000000000000000000000000000000..14a705abc82cb99c291069a68a730d06a3394d34 --- /dev/null +++ b/SorpLib/Numerics/smoothTransition_der2.mo @@ -0,0 +1,101 @@ +within SorpLib.Numerics; +function smoothTransition_der2 + "Second derivative of function 'smoothTransition'" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Actual value" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionPoint=1 + "Transition point" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionLength=1 + "Transition length" + annotation (Dialog(tab="General", group="Inputs")); + input Integer noDiff = 1 + "Specification how often function can be differentiated (i.e., 1, 2 or 3)" + annotation (Dialog(tab="General", group="Numerics")); + + input Real x_der + "First derivative of actual value wrt. time" + annotation (Dialog(tab="General", group="Inputs")); + input Real x_der2 + "Second derivative of actual value wrt. time" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real weigthingFactor + "Second derivative of weighting factor" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +protected + Real phi + "Phase"; + Real dphi_dtau + "First derivative of phase wrt. time"; + Real d2phi_d2tau + "Second derivative of phase wrt. time"; + +algorithm + if x < transitionPoint-0.5*transitionLength then + weigthingFactor := 0 + "No transition region"; + + elseif x < transitionPoint+0.5*transitionLength then + phi := (x - transitionPoint)*Modelica.Constants.pi/transitionLength + "Phase"; + dphi_dtau := x_der*Modelica.Constants.pi/transitionLength + "First derivative of weighting factor"; + d2phi_d2tau := x_der2*Modelica.Constants.pi/transitionLength + "First derivative of weighting factor"; + + if noDiff == 1 then + weigthingFactor := -1.0/2.0 * + (-sin(phi) * dphi_dtau^2 + cos(phi) * d2phi_d2tau) + "Transition region"; + + elseif noDiff == 2 then + weigthingFactor := -d2phi_d2tau / Modelica.Constants.pi * + (cos(phi)^2 - sin(phi)^2 + 1) + + 4 * dphi_dtau^2 / Modelica.Constants.pi * cos(phi)*sin(phi) + "Transition region"; + + else + weigthingFactor := d2phi_d2tau / 3.0 / Modelica.Constants.pi * + (-2.0*cos(phi)^4 + 6.0*sin(phi)^2*cos(phi)^2 - 3.0 - 3.0*cos(2.0*phi)) + + dphi_dtau^2 / 3.0 / Modelica.Constants.pi * + (8.0*cos(phi)^3*sin(phi) + 12.0*sin(phi)*cos(phi)^3 - + 12.0*sin(phi)^2*cos(phi)*sin(phi) + 6.0*sin(2.0*phi)) + "Transition region"; + + end if; + + else + weigthingFactor := 0 + "No transition region"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the first derivative of the function 'smoothTransition' with +respect to time. For full details, check the documentation of the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition\">SorpLib.Numerics.smoothTransition</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end smoothTransition_der2; diff --git a/SorpLib/Numerics/smoothTransition_der2_noEvent.mo b/SorpLib/Numerics/smoothTransition_der2_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..7edd3ae1bb81ed6acf6fac8d706ca3c21439a947 --- /dev/null +++ b/SorpLib/Numerics/smoothTransition_der2_noEvent.mo @@ -0,0 +1,101 @@ +within SorpLib.Numerics; +function smoothTransition_der2_noEvent + "Second derivative of function 'smoothTransition_noEvent' (without events)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Actual value" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionPoint=1 + "Transition point" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionLength=1 + "Transition length" + annotation (Dialog(tab="General", group="Inputs")); + input Integer noDiff = 1 + "Specification how often function can be differentiated (i.e., 1, 2 or 3)" + annotation (Dialog(tab="General", group="Numerics")); + + input Real x_der + "First derivative of actual value wrt. time" + annotation (Dialog(tab="General", group="Inputs")); + input Real x_der2 + "Second derivative of actual value wrt. time" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real weigthingFactor + "Second derivative of weighting factor" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +protected + Real phi + "Phase"; + Real dphi_dtau + "First derivative of phase wrt. time"; + Real d2phi_d2tau + "Second derivative of phase wrt. time"; + +algorithm + if noEvent(x < transitionPoint-0.5*transitionLength) then + weigthingFactor := 0 + "No transition region"; + + elseif noEvent(x < transitionPoint+0.5*transitionLength) then + phi := (x - transitionPoint)*Modelica.Constants.pi/transitionLength + "Phase"; + dphi_dtau := x_der*Modelica.Constants.pi/transitionLength + "First derivative of weighting factor"; + d2phi_d2tau := x_der2*Modelica.Constants.pi/transitionLength + "First derivative of weighting factor"; + + if noEvent(noDiff == 1) then + weigthingFactor := -1.0/2.0 * + (-sin(phi) * dphi_dtau^2 + cos(phi) * d2phi_d2tau) + "Transition region"; + + elseif noEvent(noDiff == 2) then + weigthingFactor := -d2phi_d2tau / Modelica.Constants.pi * + (cos(phi)^2 - sin(phi)^2 + 1) + + 4 * dphi_dtau^2 / Modelica.Constants.pi * cos(phi)*sin(phi) + "Transition region"; + + else + weigthingFactor := d2phi_d2tau / 3.0 / Modelica.Constants.pi * + (-2.0*cos(phi)^4 + 6.0*sin(phi)^2*cos(phi)^2 - 3.0 - 3.0*cos(2.0*phi)) + + dphi_dtau^2 / 3.0 / Modelica.Constants.pi * + (8.0*cos(phi)^3*sin(phi) + 12.0*sin(phi)*cos(phi)^3 - + 12.0*sin(phi)^2*cos(phi)*sin(phi) + 6.0*sin(2.0*phi)) + "Transition region"; + + end if; + + else + weigthingFactor := 0 + "No transition region"; + + end if; + + // + // Annotations + // + annotation (Documentation(info="<html> +<p> +This function is the first derivative of the function 'smoothTransition_noEvent' +with respect to time. For full details, check the documentation of the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition_noEvent\">SorpLib.Numerics.smoothTransition_noEvent</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end smoothTransition_der2_noEvent; diff --git a/SorpLib/Numerics/smoothTransition_der_noEvent.mo b/SorpLib/Numerics/smoothTransition_der_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..4abd68c3718c1b6d385a8787bda239f0ea089b66 --- /dev/null +++ b/SorpLib/Numerics/smoothTransition_der_noEvent.mo @@ -0,0 +1,95 @@ +within SorpLib.Numerics; +function smoothTransition_der_noEvent + "First derivative of function 'smoothTransition_noEvent' (without events)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Actual value" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionPoint=1 + "Transition point" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionLength=1 + "Transition length" + annotation (Dialog(tab="General", group="Inputs")); + input Integer noDiff = 1 + "Specification how often function can be differentiated (i.e., 1, 2 or 3)" + annotation (Dialog(tab="General", group="Numerics")); + + input Real x_der + "First derivative of actual value wrt. time" + annotation (Dialog(tab="General", group="Inputs")); + + // + // Definition of outputs + // + output Real weigthingFactor + "First derivative of weighting factor" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +protected + Real phi + "Phase"; + Real dphi_dtau + "First derivative of phase wrt. time"; + +algorithm + if noEvent(x < transitionPoint-0.5*transitionLength) then + weigthingFactor := 0 + "No transition region"; + + elseif noEvent(x < transitionPoint+0.5*transitionLength) then + phi := (x - transitionPoint)*Modelica.Constants.pi/transitionLength + "Phase"; + dphi_dtau := x_der*Modelica.Constants.pi/transitionLength + "First derivative of weighting factor"; + + if noEvent(noDiff == 1) then + weigthingFactor := -1.0/2.0 * cos(phi) * dphi_dtau + "Transition region"; + + elseif noEvent(noDiff == 2) then + weigthingFactor := -dphi_dtau / Modelica.Constants.pi * + (cos(phi)^2 - sin(phi)^2 + 1) + "Transition region"; + + else + weigthingFactor := dphi_dtau / 3.0 / Modelica.Constants.pi * + (-2.0*cos(phi)^4 + 6.0*sin(phi)^2*cos(phi)^2 - 3.0 - 3.0*cos(2.0*phi)) + "Transition region"; + + end if; + + else + weigthingFactor := 0 + "No transition region"; + + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=true, +derivative(order=2, + noDerivative=transitionPoint, + noDerivative=transitionLength, + noDerivative=noDiff) = smoothTransition_der2_noEvent, +Documentation(info="<html> +<p> +This function is the first derivative of the function 'smoothTransition_noEvent' +with respect to time. For full details, check the documentation of the function +<a href=\"Modelica://SorpLib.Numerics.smoothTransition_noEvent\">SorpLib.Numerics.smoothTransition_noEvent</a>. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end smoothTransition_der_noEvent; diff --git a/SorpLib/Numerics/smoothTransition_noEvent.mo b/SorpLib/Numerics/smoothTransition_noEvent.mo new file mode 100644 index 0000000000000000000000000000000000000000..0ec7cb15beb2e5882e861a6b1aba166766c3b9a6 --- /dev/null +++ b/SorpLib/Numerics/smoothTransition_noEvent.mo @@ -0,0 +1,148 @@ +within SorpLib.Numerics; +function smoothTransition_noEvent + "Smoothly changes the output from 1 to 0 around the transition point to get a continuous and differentiable transition (without events)" + extends Modelica.Icons.Function; + + // + // Definition of inputs + // + input Real x + "Actual value" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionPoint=1 + "Transition point" + annotation (Dialog(tab="General", group="Inputs")); + input Real transitionLength=1 + "Transition length" + annotation (Dialog(tab="General", group="Inputs")); + input Integer noDiff = 1 + "Specification how often function can be differentiated (i.e., 1, 2 or 3)" + annotation (Dialog(tab="General", group="Numerics")); + + // + // Definition of outputs + // + output Real weigthingFactor + "Weighting factor" + annotation (Dialog(tab="General", group="Outputs", enable=false)); + +protected + Real phi + "Phase"; + +algorithm + if noEvent(x < transitionPoint - 0.5*transitionLength) then + weigthingFactor := 1 + "No transition region"; + + elseif noEvent(x < transitionPoint + 0.5*transitionLength) then + phi := (x - transitionPoint)*Modelica.Constants.pi/transitionLength + "Phase"; + + if noEvent(noDiff == 1) then + weigthingFactor := -1.0/2.0 * sin(phi) + 1.0/2.0 + "Transition region"; + + elseif noEvent(noDiff == 2) then + weigthingFactor := -1.0/2.0 * (2*cos(phi)*sin(phi) + + 2*phi - Modelica.Constants.pi) / Modelica.Constants.pi + "Transition region"; + + else + weigthingFactor := 1.0/6.0 * (-4.0*sin(phi)*cos(phi)^3 - + 6.0*phi - 3.0*sin(2.0*phi) + 3.0*Modelica.Constants.pi) / + Modelica.Constants.pi + "Transition region"; + + end if; + + else + weigthingFactor := 0 + "No transition region"; + + end if; + + // + // Annotations + // + annotation (Inline=false, +InlineAfterIndexReduction=true, +derivative(order=1, + noDerivative=transitionPoint, + noDerivative=transitionLength, + noDerivative=noDiff) = smoothTransition_der_noEvent, +Documentation(info="<html> +<p> +This function is used to smoothly change a weighting factor <i>WF</i> from 1 +to 0 at the specified point <i>transitionPoint</i> within the specified length +<i>transitionLength</i>. The change is continuous and differentiable, and the +type of change is specified via the parameter <i>noDiff</i>. The function is +implemented to avoid events. +<br/><br/> +The change is described using trigonometric functions that depend on the current +phase <i>φ</i>: +</p> + +<pre> + φ = (x - transitionPoint) * π / transitionLength; +</pre> + +<p> +For <i>noDiff = 1</i>, the change is continuously differentiable once: +</p> + +<pre> + WF = -0.5 * <strong>sin</strong>(φ) + 0.5; +</pre> + +<p> +For <i>noDiff = 2</i>, the change can be continuously differentiated twice: +</p> + +<pre> + WF = -0.5 * (2 * <strong>cos</strong>(φ) * <strong>sin</strong>(φ) + 2 * φ - π) / π; +</pre> + +<p> +For <i>noDiff = 3</i>, the change can be continuously differentiated three times: +</p> + +<pre> + WF = 1/6 * (-4 * <strong>sin</strong>(φ) * <strong>cos</strong><sup>3</sup>(φ) - 6 * φ - 3 * <strong>sin</strong>(2 * φ) + 3 * π) / π; +</pre> + +<h4>Typical use</h4> +<p> +This function is used, for example, to switch smoothly between different flow +regimes when calculating heat or mass transport. For this purpose, the function +can be used as follows: +</p> + +<pre> + y = WF * y(Regime 1) + (1 - WF) * y(Regime 2); +</pre> + +<h4>Example</h4> +<p> +The following figure shows the smooth transition of the weighting factor +<i>WF</i> and its derivatives for different values of <i>noDiff</i> at +<i>transitionPoint = 1</i> for <i>transitionLength = 1</i>. +<br/><br/> +</p> +<img src=\"Modelica://SorpLib/Resources/doc/numerics_smoothTransition.png\" alt=\"numerics_smoothTransition.png\"> + +<h4>References</h4> +<p> +The function is based on the TIL library +(<a href=\"Modelica://TIL.Utilities.Numerics.smoothTransition\">TIL.Utilities.Numerics.smoothTransition</a>) +and has been slightly adapted. +</p> +</html>", revisions="<html> +<ul> + <li> + October 31, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); +end smoothTransition_noEvent; diff --git a/SorpLib/Resources/Images/AdsorbensAdsorbate.png b/SorpLib/Resources/Images/AdsorbensAdsorbate.png deleted file mode 100644 index f32bfe03948782418c489f02fa359daaeaf17ed7..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/AdsorbensAdsorbate.png and /dev/null differ diff --git a/SorpLib/Resources/Images/Adsorbent.png b/SorpLib/Resources/Images/Adsorbent.png deleted file mode 100644 index 79195b53c8f323a753665cd84212426971fcc27d..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/Adsorbent.png and /dev/null differ diff --git a/SorpLib/Resources/Images/ClosedAdsorber.png b/SorpLib/Resources/Images/ClosedAdsorber.png deleted file mode 100644 index f9c549dff10d5745cee0a1130a327814271e3125..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/ClosedAdsorber.png and /dev/null differ diff --git a/SorpLib/Resources/Images/DeltaP.png b/SorpLib/Resources/Images/DeltaP.png deleted file mode 100644 index 0af655b541e5fdf2c0aceff50ee1f75d34d659c9..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/DeltaP.png and /dev/null differ diff --git a/SorpLib/Resources/Images/Evaporator.png b/SorpLib/Resources/Images/Evaporator.png deleted file mode 100644 index 40b19bd8b72d9e800cd5c6f0fa4a7d9e81121a83..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/Evaporator.png and /dev/null differ diff --git a/SorpLib/Resources/Images/EvpCond.png b/SorpLib/Resources/Images/EvpCond.png deleted file mode 100644 index 8669d89df4eed8b52155ef9d7926fd3c86ed91b8..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/EvpCond.png and /dev/null differ diff --git a/SorpLib/Resources/Images/HXAirAir.png b/SorpLib/Resources/Images/HXAirAir.png deleted file mode 100644 index 39dc642406eae3c8ae2d17d8cd86f8c42ef0848f..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/HXAirAir.png and /dev/null differ diff --git a/SorpLib/Resources/Images/HeatTransfer.png b/SorpLib/Resources/Images/HeatTransfer.png deleted file mode 100644 index 2d5fc037c7c0c115317f1b8f9826a3850396deba..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/HeatTransfer.png and /dev/null differ diff --git a/SorpLib/Resources/Images/LTT_logo_RWTH_en.png b/SorpLib/Resources/Images/LTT_logo_RWTH_en.png deleted file mode 100644 index 1d38d6fc5362d0e54fd679acbfc69a199ae9c185..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/LTT_logo_RWTH_en.png and /dev/null differ diff --git a/SorpLib/Resources/Images/MassTransfer.png b/SorpLib/Resources/Images/MassTransfer.png deleted file mode 100644 index 03bc419e78a72da2c119d3dcb35d29b71ef6ff63..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/MassTransfer.png and /dev/null differ diff --git a/SorpLib/Resources/Images/MassTransferDiffusion.png b/SorpLib/Resources/Images/MassTransferDiffusion.png deleted file mode 100644 index 7868ff175c4550ae1b56296fc7a0da81f1d532b1..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/MassTransferDiffusion.png and /dev/null differ diff --git a/SorpLib/Resources/Images/MassTransferDiffusionFlow.png b/SorpLib/Resources/Images/MassTransferDiffusionFlow.png deleted file mode 100644 index 10f70ee61dfcc6046f5f326bdb55aba956c5f19b..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/MassTransferDiffusionFlow.png and /dev/null differ diff --git a/SorpLib/Resources/Images/OpenAdsorber.png b/SorpLib/Resources/Images/OpenAdsorber.png deleted file mode 100644 index c8a6f7d9927612ef4f8ae3473eb84812a64762e6..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/OpenAdsorber.png and /dev/null differ diff --git a/SorpLib/Resources/Images/Sorplib_info.png b/SorpLib/Resources/Images/Sorplib_info.png deleted file mode 100644 index 20455ed1634f49976affd8904b6562fcc5c4310c..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/Sorplib_info.png and /dev/null differ diff --git a/SorpLib/Resources/Images/Sorplib_logo.png b/SorpLib/Resources/Images/Sorplib_logo.png deleted file mode 100644 index 4541898aa3028fb855ec184c91938e2163901e03..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/Sorplib_logo.png and /dev/null differ diff --git a/SorpLib/Resources/Images/Wall.png b/SorpLib/Resources/Images/Wall.png deleted file mode 100644 index 4eec32e050a6eb19686d7cc1ea8624690405f28f..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/Wall.png and /dev/null differ diff --git a/SorpLib/Resources/Images/beta.png b/SorpLib/Resources/Images/beta.png deleted file mode 100644 index 39f7eae8d0108be50c870cfd4d22fdf944aa9475..0000000000000000000000000000000000000000 Binary files a/SorpLib/Resources/Images/beta.png and /dev/null differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_multi_iast_n2.png b/SorpLib/Resources/doc/media_functions_equilibria_multi_iast_n2.png new file mode 100644 index 0000000000000000000000000000000000000000..38ace84c5e9f2ca9d087739e54617d3e228c4acd Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_multi_iast_n2.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_multi_iast_n3.png b/SorpLib/Resources/doc/media_functions_equilibria_multi_iast_n3.png new file mode 100644 index 0000000000000000000000000000000000000000..b1bea28dadb9880a3523fc80ad40aac8cb5babc2 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_multi_iast_n3.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_multi_langmuir.png b/SorpLib/Resources/doc/media_functions_equilibria_multi_langmuir.png new file mode 100644 index 0000000000000000000000000000000000000000..2ff2cedc8c6a6b576ee2affba2d4f39109eafa91 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_multi_langmuir.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_multi_mechanistic_toth_gab.png b/SorpLib/Resources/doc/media_functions_equilibria_multi_mechanistic_toth_gab.png new file mode 100644 index 0000000000000000000000000000000000000000..1222134f9fc5026dd3c01c181d1068bede1fa82d Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_multi_mechanistic_toth_gab.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_multi_sips.png b/SorpLib/Resources/doc/media_functions_equilibria_multi_sips.png new file mode 100644 index 0000000000000000000000000000000000000000..29aa6802ef2b467bab056b676e7c128beff04e79 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_multi_sips.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_multi_toth.png b/SorpLib/Resources/doc/media_functions_equilibria_multi_toth.png new file mode 100644 index 0000000000000000000000000000000000000000..9852bc283787abb921c607ac6435c9ba6be1c532 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_multi_toth.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_multi_toth_gab_s.png b/SorpLib/Resources/doc/media_functions_equilibria_multi_toth_gab_s.png new file mode 100644 index 0000000000000000000000000000000000000000..ad930849a0c1fd5bca15d1343fcac8dd125eedcd Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_multi_toth_gab_s.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_multi_toth_gab_sb.png b/SorpLib/Resources/doc/media_functions_equilibria_multi_toth_gab_sb.png new file mode 100644 index 0000000000000000000000000000000000000000..4053983586df769c68d107ad4983065315953223 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_multi_toth_gab_sb.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_multi_wads_toth_gab.png b/SorpLib/Resources/doc/media_functions_equilibria_multi_wads_toth_gab.png new file mode 100644 index 0000000000000000000000000000000000000000..a25cf8459f43f07278a5b88fcdf07bae6756296d Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_multi_wads_toth_gab.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_bet.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_bet.png new file mode 100644 index 0000000000000000000000000000000000000000..ae00a2440cbd894111eb2b564a8724956e53c98c Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_bet.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_bi_langmuir.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_bi_langmuir.png new file mode 100644 index 0000000000000000000000000000000000000000..ce5512c27ebaeb1706fd24c999a2681fbd2b9d6f Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_bi_langmuir.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_astakhov.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_astakhov.png new file mode 100644 index 0000000000000000000000000000000000000000..955a4ee34ba7c26e10bbbd09fa6643f2081031a3 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_astakhov.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_chebyshev_series_3_3.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_chebyshev_series_3_3.png new file mode 100644 index 0000000000000000000000000000000000000000..e2406aa13c117b5c11c4a4be45d7f8530ba9a171 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_chebyshev_series_3_3.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_empirical_1.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_empirical_1.png new file mode 100644 index 0000000000000000000000000000000000000000..162a254629899be96241639af2c8a95fa559f436 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_empirical_1.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_empirical_2.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_empirical_2.png new file mode 100644 index 0000000000000000000000000000000000000000..deff7950b60d862952e6239c0e8a53f4be33a141 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_empirical_2.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_lorentzian_chebyshev_3_3.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_lorentzian_chebyshev_3_3.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2bd9ba2828829949ce93b782235b153898fd0d Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_lorentzian_chebyshev_3_3.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_lorentzian_cumulativ.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_lorentzian_cumulativ.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2bd9ba2828829949ce93b782235b153898fd0d Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_lorentzian_cumulativ.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_lorentzian_pearsonIV.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_lorentzian_pearsonIV.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2bd9ba2828829949ce93b782235b153898fd0d Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_lorentzian_pearsonIV.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_pearson_iv.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_pearson_iv.png new file mode 100644 index 0000000000000000000000000000000000000000..3f17b3e8161102445ff6ce3b947e90759e5d9899 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_dubinin_pearson_iv.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_freundlich.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_freundlich.png new file mode 100644 index 0000000000000000000000000000000000000000..5f299db167df9c1cafd3d80f3248ff609435ca79 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_freundlich.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_gab.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_gab.png new file mode 100644 index 0000000000000000000000000000000000000000..92fb15db27d09e5d9c314b03dfc51f58c3644e68 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_gab.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_henry.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_henry.png new file mode 100644 index 0000000000000000000000000000000000000000..71823a5f63385f42d3b1136aaa489eb5b19bff8f Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_henry.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_langmuir.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_langmuir.png new file mode 100644 index 0000000000000000000000000000000000000000..4d463892ae0b4a2157b18c11ed64272323a6f123 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_langmuir.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_sips.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_sips.png new file mode 100644 index 0000000000000000000000000000000000000000..72933bf168a5b2bcefb373decd81dcb091ffe682 Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_sips.png differ diff --git a/SorpLib/Resources/doc/media_functions_equilibria_pure_toth.png b/SorpLib/Resources/doc/media_functions_equilibria_pure_toth.png new file mode 100644 index 0000000000000000000000000000000000000000..443dcbc98fddfa787c1f492e4fa3eab5db96832e Binary files /dev/null and b/SorpLib/Resources/doc/media_functions_equilibria_pure_toth.png differ diff --git a/SorpLib/Resources/doc/numerics_regSquare.png b/SorpLib/Resources/doc/numerics_regSquare.png new file mode 100644 index 0000000000000000000000000000000000000000..f7e5216ae2ead2e1511131ea0315e7233a700985 Binary files /dev/null and b/SorpLib/Resources/doc/numerics_regSquare.png differ diff --git a/SorpLib/Resources/doc/numerics_regSquareWFactors.png b/SorpLib/Resources/doc/numerics_regSquareWFactors.png new file mode 100644 index 0000000000000000000000000000000000000000..0b3775a461c6e97d120735dce096be32f9b6054b Binary files /dev/null and b/SorpLib/Resources/doc/numerics_regSquareWFactors.png differ diff --git a/SorpLib/Resources/doc/numerics_regStep.png b/SorpLib/Resources/doc/numerics_regStep.png new file mode 100644 index 0000000000000000000000000000000000000000..fc31392e2a9422431cb6e27643b4bc8320a10518 Binary files /dev/null and b/SorpLib/Resources/doc/numerics_regStep.png differ diff --git a/SorpLib/Resources/doc/numerics_smoothTransition.png b/SorpLib/Resources/doc/numerics_smoothTransition.png new file mode 100644 index 0000000000000000000000000000000000000000..127eef46e416ba32a5542484e91f8adb640766e5 Binary files /dev/null and b/SorpLib/Resources/doc/numerics_smoothTransition.png differ diff --git a/SorpLib/Scripts/libraryinfo.mos b/SorpLib/Scripts/libraryinfo.mos deleted file mode 100644 index 1ba846cccb4df4691b69836719b8ef52b4b19bf1..0000000000000000000000000000000000000000 --- a/SorpLib/Scripts/libraryinfo.mos +++ /dev/null @@ -1,13 +0,0 @@ -LibraryInfoMenuSeparator( - category="libraries", - pos=170); - -LibraryInfoMenuCommand( - category = "libraries", - text = "SorpLib", - reference = "SorpLib", - version="0.1", - isModel = true, - description = "Modeling adsorption energy systems", - ModelicaVersion = ">= 3.2", - pos = 171); \ No newline at end of file diff --git a/SorpLib/Units/AdsorptionPotential.mo b/SorpLib/Units/AdsorptionPotential.mo new file mode 100644 index 0000000000000000000000000000000000000000..cb809479fc05890467dc97f4097555d4123e8ef3 --- /dev/null +++ b/SorpLib/Units/AdsorptionPotential.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type AdsorptionPotential =Real ( + final quantity="AdsorptionPotential", + final unit="J/kg", + displayUnit="kJ/kg", + min=0) "Adsorption potential"; diff --git a/SorpLib/Units/DerDensityByTemperature.mo b/SorpLib/Units/DerDensityByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..52328862c80fdfe6a173a808a2ed44a52cda3c1c --- /dev/null +++ b/SorpLib/Units/DerDensityByTemperature.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerDensityByTemperature = Real ( + final quantity="DerDensityByTemperature", + final unit="kg/(m3.K)", + displayUnit="kg/(m3.K)") + "First-order partial derivative of the density w.r.t. the temperature"; diff --git a/SorpLib/Units/DerDensityByTemperatureTemperature.mo b/SorpLib/Units/DerDensityByTemperatureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..c197351a1db595e64a67072cc6149661404222df --- /dev/null +++ b/SorpLib/Units/DerDensityByTemperatureTemperature.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerDensityByTemperatureTemperature = Real ( + final quantity="DerDensityByTemperatureTemperature", + final unit="kg/(m3.K2)", + displayUnit="kg/(m3.K2)") + "Second-order partial derivative of the density w.r.t. the temperature"; diff --git a/SorpLib/Units/DerFilledPoreVolumeByAdsorptionPotential.mo b/SorpLib/Units/DerFilledPoreVolumeByAdsorptionPotential.mo new file mode 100644 index 0000000000000000000000000000000000000000..89c07e7da30861a59db19c6e1062452658f1f2f7 --- /dev/null +++ b/SorpLib/Units/DerFilledPoreVolumeByAdsorptionPotential.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerFilledPoreVolumeByAdsorptionPotential = Real ( + final quantity="DerFilledPoreVolumeByAdsorptionPotential", + final unit="m3.mol/(kg.J)", + displayUnit="l.mol/(kg.kJ)") + "First-order partial derivative of the filled pore volume w.r.t. the adsorption + potential"; diff --git a/SorpLib/Units/DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential.mo b/SorpLib/Units/DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential.mo new file mode 100644 index 0000000000000000000000000000000000000000..ec93ce57b88e7d7dcc73fd58f98dab9792e5fd58 --- /dev/null +++ b/SorpLib/Units/DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential = Real ( + final quantity="DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential", + final unit="m3.mol2/(kg.J2)", + displayUnit="l.mol2/(kg.kJ2)") + "Second-order partial derivative of the filled pore volume w.r.t. the adsorption + potential"; diff --git a/SorpLib/Units/DerFilledPoreVolumeByAdsorptionPotentialTemperature.mo b/SorpLib/Units/DerFilledPoreVolumeByAdsorptionPotentialTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..f13e30c74957aba90a2fec63ffe057af008ac78f --- /dev/null +++ b/SorpLib/Units/DerFilledPoreVolumeByAdsorptionPotentialTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerFilledPoreVolumeByAdsorptionPotentialTemperature = Real ( + final quantity="DerFilledPoreVolumeByAdsorptionPotentialTemperature", + final unit="m3.mol/(kg.J.K)", + displayUnit="l.mol/(kg.kJ.K)") + "Second-order partial derivative of the filled pore volume w.r.t. the adsorption + potential and temperature"; diff --git a/SorpLib/Units/DerFilledPoreVolumeByTemperature.mo b/SorpLib/Units/DerFilledPoreVolumeByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..a90aaa46c2b14da3b68221fe85c064f3001b8254 --- /dev/null +++ b/SorpLib/Units/DerFilledPoreVolumeByTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerFilledPoreVolumeByTemperature = Real ( + final quantity="DerFilledPoreVolumeByTemperature", + final unit="m3/(kg.K)", + displayUnit="l/(kg.K)") + "First-order partial derivative of the filled pore volume w.r.t. the + temperature"; diff --git a/SorpLib/Units/DerIsobaricExpansionCoefficientByPressure.mo b/SorpLib/Units/DerIsobaricExpansionCoefficientByPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..d4eb14a5d24fd46e9acf2688c226627221a4946c --- /dev/null +++ b/SorpLib/Units/DerIsobaricExpansionCoefficientByPressure.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerIsobaricExpansionCoefficientByPressure = Real ( + final quantity="DerIsobaricExpansionCoefficientByPressure", + final unit="1/(K.Pa)", + displayUnit="1/(K.Pa)") + "First-order partial derivative of the isobaric expansion coefficient w.r.t. + the pressure"; diff --git a/SorpLib/Units/DerIsobaricExpansionCoefficientByTemperature.mo b/SorpLib/Units/DerIsobaricExpansionCoefficientByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..12e9ed3061ab1b9eae8df3a284b03b2aeaaeafff --- /dev/null +++ b/SorpLib/Units/DerIsobaricExpansionCoefficientByTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerIsobaricExpansionCoefficientByTemperature = Real ( + final quantity="DerIsobaricExpansionCoefficientByTemperature", + final unit="1/(K2)", + displayUnit="1/(K2)") + "First-order partial derivative of the isobaric expansion coefficient w.r.t. + the temperature"; diff --git a/SorpLib/Units/DerMolarAdsorptionPotentialByPressure.mo b/SorpLib/Units/DerMolarAdsorptionPotentialByPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..ee89d94ae8f0443e1cc9fc7e12f5a2f7e54eb3ed --- /dev/null +++ b/SorpLib/Units/DerMolarAdsorptionPotentialByPressure.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerMolarAdsorptionPotentialByPressure =Real ( + final quantity="DerMolarAdsorptionPotentialByPressure", + final unit="J/(mol.Pa)", + displayUnit="kJ/(mol.Pa)") + "First-order partial derivative of the molar adsorption potential w.r.t. + pressure"; diff --git a/SorpLib/Units/DerMolarAdsorptionPotentialByPressurePressure.mo b/SorpLib/Units/DerMolarAdsorptionPotentialByPressurePressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..47211e7490aba53c2ba38a6d4e0973eddc7a098e --- /dev/null +++ b/SorpLib/Units/DerMolarAdsorptionPotentialByPressurePressure.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerMolarAdsorptionPotentialByPressurePressure = Real ( + final quantity="DerMolarAdsorptionPotentialByPressurePressure", + final unit="J/(mol.Pa2)", + displayUnit="kJ/(mol.Pa2)") + "Second-order partial derivative of the molar adsorption potential w.r.t. + pressure"; diff --git a/SorpLib/Units/DerMolarAdsorptionPotentialByPressureTemperature.mo b/SorpLib/Units/DerMolarAdsorptionPotentialByPressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..5c87146f4fb76380f38cb8f38e2e6c1084359c2b --- /dev/null +++ b/SorpLib/Units/DerMolarAdsorptionPotentialByPressureTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerMolarAdsorptionPotentialByPressureTemperature = Real ( + final quantity="DerMolarAdsorptionPotentialByPressureTemperature", + final unit="J/(mol.Pa.K)", + displayUnit="kJ/(mol.Pa.K)") + "Second-order partial derivative of the molar adsorption potential w.r.t. + pressure and temperature"; diff --git a/SorpLib/Units/DerMolarAdsorptionPotentialByTemperature.mo b/SorpLib/Units/DerMolarAdsorptionPotentialByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..0281c022f6566b860987e683184868ae3feb1e89 --- /dev/null +++ b/SorpLib/Units/DerMolarAdsorptionPotentialByTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerMolarAdsorptionPotentialByTemperature =Real ( + final quantity="DerMolarAdsorptionPotentialByTemperature", + final unit="J/(mol.K)", + displayUnit="kJ/(mol.K)") + "First-order partial derivative of the molar adsorption potential w.r.t. + temperature"; diff --git a/SorpLib/Units/DerMolarAdsorptionPotentialByTemperatureTemperature.mo b/SorpLib/Units/DerMolarAdsorptionPotentialByTemperatureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..a80dffe0413c398c8b25442fe55fcd8fef732d6d --- /dev/null +++ b/SorpLib/Units/DerMolarAdsorptionPotentialByTemperatureTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerMolarAdsorptionPotentialByTemperatureTemperature = Real ( + final quantity="DerMolarAdsorptionPotentialByTemperatureTemperature", + final unit="J/(mol.K2)", + displayUnit="kJ/(mol.K2)") + "Second-order partial derivative of the molar adsorption potential w.r.t. + temperature"; diff --git a/SorpLib/Units/DerMolarEnthalpyByPressure.mo b/SorpLib/Units/DerMolarEnthalpyByPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..0489458573868318f93a23ff852fceee45a553f2 --- /dev/null +++ b/SorpLib/Units/DerMolarEnthalpyByPressure.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerMolarEnthalpyByPressure = Real ( + final quantity="DerMolarEnthalpyByPressure", + final unit="J/(mol.Pa)", + displayUnit="kJ/(mol.Pa)") + "First-order partial derivative of the molar enthalpy w.r.t. the presssure"; diff --git a/SorpLib/Units/DerMolarEnthalpyByUptake.mo b/SorpLib/Units/DerMolarEnthalpyByUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..9245d414878da5370921c2a95448cfe22496aae2 --- /dev/null +++ b/SorpLib/Units/DerMolarEnthalpyByUptake.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerMolarEnthalpyByUptake = Real ( + final quantity="DerMolarEnthalpyByUptake", + final unit="J.kg/(mol.kg)", + displayUnit="kJ.kg/(mol.kg)") + "First-order partial derivative of the molar enthalpy w.r.t. the uptake"; diff --git a/SorpLib/Units/DerPressureByTemperatureTemperature.mo b/SorpLib/Units/DerPressureByTemperatureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..18a8c6247e37e10ff2b615949a0ae2a958391bc9 --- /dev/null +++ b/SorpLib/Units/DerPressureByTemperatureTemperature.mo @@ -0,0 +1,5 @@ +within SorpLib.Units; +type DerPressureByTemperatureTemperature = Real ( + final quantity="DerPressureByTemperatureTemperature", + final unit="Pa/(K2)") + "Second-order partial derivative of the pressure w.r.t. the temperature"; diff --git a/SorpLib/Units/DerPressureByUptake.mo b/SorpLib/Units/DerPressureByUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..e81088cdaae6c0a4d9e631593ab0a8a590362a29 --- /dev/null +++ b/SorpLib/Units/DerPressureByUptake.mo @@ -0,0 +1,5 @@ +within SorpLib.Units; +type DerPressureByUptake = Real ( + final quantity="DerPressureByUptake", + final unit="Pa.kg/(kg)") + "First-order partial derivative of the pressure w.r.t. the uptake"; diff --git a/SorpLib/Units/DerSpecificEnthalpyByPressure.mo b/SorpLib/Units/DerSpecificEnthalpyByPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..f0196bfa0130bd9f46522f1e52841fe6226bf7b9 --- /dev/null +++ b/SorpLib/Units/DerSpecificEnthalpyByPressure.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerSpecificEnthalpyByPressure = Real ( + final quantity="DerSpecificEnthalpyByPressure", + final unit="J/(kg.Pa)", + displayUnit="kJ/(kg.Pa)") + "First-order partial derivative of specific enthalpy w.r.t. pressure"; diff --git a/SorpLib/Units/DerSpecificEnthalpyByUptake.mo b/SorpLib/Units/DerSpecificEnthalpyByUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..f622bcbdb65307731d47b96c9d7c19ad9802ebde --- /dev/null +++ b/SorpLib/Units/DerSpecificEnthalpyByUptake.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerSpecificEnthalpyByUptake = Real ( + final quantity="DerSpecificEnthalpyByUptake", + final unit="J.kg/(kg.kg)", + displayUnit="kJ.kg/(kg.kg)") + "First-order partial derivative of specific enthalpy w.r.t. uptake"; diff --git a/SorpLib/Units/DerSpecificEntropyByPressure.mo b/SorpLib/Units/DerSpecificEntropyByPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..c445a37596cfeee98a238febdf30305a258a9018 --- /dev/null +++ b/SorpLib/Units/DerSpecificEntropyByPressure.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerSpecificEntropyByPressure = Real ( + final quantity="DerSpecificEntropyByPressure", + final unit="J/(kg.K.Pa)", + displayUnit="kJ/(kg.K.Pa)") + "First-order partial derivative of specific entropy w.r.t. pressure"; diff --git a/SorpLib/Units/DerSpecificEntropyByTemperature.mo b/SorpLib/Units/DerSpecificEntropyByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..16c6a12d02b1219ff31b9d0d96af2c36f212ded4 --- /dev/null +++ b/SorpLib/Units/DerSpecificEntropyByTemperature.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerSpecificEntropyByTemperature = Real ( + final quantity="DerSpecificEntropyByTemperature", + final unit="J/(kg.K2)", + displayUnit="kJ/(kg.K2)") + "First-order partial derivative of specific temperature w.r.t. pressure"; diff --git a/SorpLib/Units/DerSpecificEntropyByUptake.mo b/SorpLib/Units/DerSpecificEntropyByUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..cffe4b15c87a50d262f246e534eefcbd91e82cd2 --- /dev/null +++ b/SorpLib/Units/DerSpecificEntropyByUptake.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerSpecificEntropyByUptake = Real ( + final quantity="DerSpecificEntropyByUptake", + final unit="J.kg/(kg2.K)", + displayUnit="kJ.kg/(kg2.K)") + "First-order partial derivative of specific entropy w.r.t. uptake"; diff --git a/SorpLib/Units/DerSpecificHeatCapacityByTemperature.mo b/SorpLib/Units/DerSpecificHeatCapacityByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..cb1fb9f86fbad3dd21aa068c18250194b6a8e425 --- /dev/null +++ b/SorpLib/Units/DerSpecificHeatCapacityByTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerSpecificHeatCapacityByTemperature = Real ( + final quantity="DerSpecificHeatCapacityByTemperature", + final unit="J/(kg.K2)", + displayUnit="kJ/(kg.K2)") + "First-order partial derivative of the specific heat capacity w.r.t. the + temperature"; diff --git a/SorpLib/Units/DerSpecificHeatCapacityByTemperatureTemperature.mo b/SorpLib/Units/DerSpecificHeatCapacityByTemperatureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..7e396aa640f58e55ff573b41a74946a467c29a6a --- /dev/null +++ b/SorpLib/Units/DerSpecificHeatCapacityByTemperatureTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerSpecificHeatCapacityByTemperatureTemperature = Real ( + final quantity="DerSpecificHeatCapacityByTemperature", + final unit="J/(kg.K3)", + displayUnit="kJ/(kg.K3)") + "Second-order partial derivative of the specific heat capacity w.r.t. the + temperature"; diff --git a/SorpLib/Units/DerSpecificVolumeByPressure.mo b/SorpLib/Units/DerSpecificVolumeByPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..f246908f439c0f1a329315365499673d5981e455 --- /dev/null +++ b/SorpLib/Units/DerSpecificVolumeByPressure.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerSpecificVolumeByPressure = Real ( + final quantity="DerSpecificVolumeByPressure", + final unit="m3/(kg.Pa)", + displayUnit="m3/(kg.Pa)") + "First-order partial derivative of the specific volume w.r.t. the pressure"; diff --git a/SorpLib/Units/DerSpecificVolumeByPressureTemperature.mo b/SorpLib/Units/DerSpecificVolumeByPressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..b668621ef5c32a991bcc866019ac1a6481474187 --- /dev/null +++ b/SorpLib/Units/DerSpecificVolumeByPressureTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerSpecificVolumeByPressureTemperature = Real ( + final quantity="DerSpecificVolumeByPressureTemperature", + final unit="m3/(kg.Pa.K)", + displayUnit="m3/(kg.Pa.K)") + "Second-order partial derivative of the specific volume w.r.t. the pressure + and temperature"; diff --git a/SorpLib/Units/DerSpecificVolumeByTemperature.mo b/SorpLib/Units/DerSpecificVolumeByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..367188a3575a70a53b53bc752fa93f69a3282103 --- /dev/null +++ b/SorpLib/Units/DerSpecificVolumeByTemperature.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerSpecificVolumeByTemperature = Real ( + final quantity="DerSpecificVolumeByTemperature", + final unit="m3/(kg.K)", + displayUnit="m3/(kg.K)") + "First-order partial derivative of the specific volume w.r.t. the temperature"; diff --git a/SorpLib/Units/DerSpecificVolumeByTemperatureTemperature.mo b/SorpLib/Units/DerSpecificVolumeByTemperatureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..66f824f4a9edfe0c3a6dc24e7d24e4226c7db94e --- /dev/null +++ b/SorpLib/Units/DerSpecificVolumeByTemperatureTemperature.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerSpecificVolumeByTemperatureTemperature = Real ( + final quantity="DerSpecificVolumeByTemperatureTemperature", + final unit="m3/(kg.K2)", + displayUnit="m3/(kg.K2)") + "Second-order partial derivative of the specific volume w.r.t. the temperature"; diff --git a/SorpLib/Units/DerSpecificVolumeByUptake.mo b/SorpLib/Units/DerSpecificVolumeByUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..53c1c6777ac93ebb16d267ee13a1d8115c28cb85 --- /dev/null +++ b/SorpLib/Units/DerSpecificVolumeByUptake.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerSpecificVolumeByUptake = Real ( + final quantity="DerSpecificVolumeByUptake", + final unit="m3.kg/(kg.kg)", + displayUnit="m3.kg/(kg.kg)") + "First-order partial derivative of the specific volume w.r.t. the uptake"; diff --git a/SorpLib/Units/DerThermalConductivityByTemperature.mo b/SorpLib/Units/DerThermalConductivityByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..027f039e28a0f1a1b85daf87ec7ee103368a33b8 --- /dev/null +++ b/SorpLib/Units/DerThermalConductivityByTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerThermalConductivityByTemperature = Real ( + final quantity="DerThermalConductivityByTemperature", + final unit="W/(m.K2)", + displayUnit="W/(m.K2)") + "First-order partial derivative of the thermal conductivity w.r.t. the + temperature"; diff --git a/SorpLib/Units/DerThermalConductivityByTemperatureTemperature.mo b/SorpLib/Units/DerThermalConductivityByTemperatureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..826d63ff8661fcf4fb9b5867fb7134e6a7aaec69 --- /dev/null +++ b/SorpLib/Units/DerThermalConductivityByTemperatureTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerThermalConductivityByTemperatureTemperature = Real ( + final quantity="DerThermalConductivityByTemperature", + final unit="W/(m.K3)", + displayUnit="W/(m.K3)") + "Second-order partial derivative of the thermal conductivity w.r.t. the + temperature"; diff --git a/SorpLib/Units/DerUptakeByMolarFraction.mo b/SorpLib/Units/DerUptakeByMolarFraction.mo new file mode 100644 index 0000000000000000000000000000000000000000..3233a459d79f90eaf74928921ea9624797ebaa11 --- /dev/null +++ b/SorpLib/Units/DerUptakeByMolarFraction.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeByMolarFraction = Real ( + final quantity="DerUptakeByMolarFraction", + final unit="kg.mol/(kg.mol)", + displayUnit="kg.mol/(kg.mol)") + "First-order partial derivative of the uptake w.r.t. molar fraction"; diff --git a/SorpLib/Units/DerUptakeByPressure.mo b/SorpLib/Units/DerUptakeByPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..cf8bcedea613540eae0c346f865ce42ac8e879c4 --- /dev/null +++ b/SorpLib/Units/DerUptakeByPressure.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeByPressure = Real ( + final quantity="DerUptakeByPressure", + final unit="kg/(kg.Pa)", + displayUnit="kg/(kg.Pa)") + "First-order partial derivative of the uptake w.r.t. pressure"; diff --git a/SorpLib/Units/DerUptakeByPressurePressure.mo b/SorpLib/Units/DerUptakeByPressurePressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..7fb7df77f50cf580627e2c0944b979d1b963ec34 --- /dev/null +++ b/SorpLib/Units/DerUptakeByPressurePressure.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeByPressurePressure = Real ( + final quantity="DerUptakeByPressurePressure", + final unit="kg/(kg.Pa2)", + displayUnit="kg/(kg.Pa2)") + "Second-order partial derivative of the uptake w.r.t. pressure"; diff --git a/SorpLib/Units/DerUptakeByPressureTemperature.mo b/SorpLib/Units/DerUptakeByPressureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..5b6796fc618498bb389ad962621115c4fd2fc76c --- /dev/null +++ b/SorpLib/Units/DerUptakeByPressureTemperature.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type DerUptakeByPressureTemperature = Real ( + final quantity="DerUptakeByPressureTemperature", + final unit="kg/(kg.Pa.K)", + displayUnit="kg/(kg.Pa.K)") + "Second-order partial derivative of the uptake w.r.t. pressure and + temperature"; diff --git a/SorpLib/Units/DerUptakeByTemperature.mo b/SorpLib/Units/DerUptakeByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..1d3c45be4db0d0912ef9958989f16280c9a0a69b --- /dev/null +++ b/SorpLib/Units/DerUptakeByTemperature.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeByTemperature = Real ( + final quantity="DerUptakeByTemperature", + final unit="kg/(kg.K)", + displayUnit="kg/(kg.K)") + "First-order partial derivative of the uptake w.r.t. temperature"; diff --git a/SorpLib/Units/DerUptakeByTemperatureTemperature.mo b/SorpLib/Units/DerUptakeByTemperatureTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..8dab74c6f3334ad9b14292170e7b090030e0e8be --- /dev/null +++ b/SorpLib/Units/DerUptakeByTemperatureTemperature.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeByTemperatureTemperature = Real ( + final quantity="DerUptakeByTemperatureTemperature", + final unit="kg/(kg.K2)", + displayUnit="kg/(kg.K2)") + "Second-order partial derivative of the uptake w.r.t. temperature"; diff --git a/SorpLib/Units/DerUptakeSpecificEnthalpyByPressure.mo b/SorpLib/Units/DerUptakeSpecificEnthalpyByPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..936c4fabf15a494251605e0462808141236a991c --- /dev/null +++ b/SorpLib/Units/DerUptakeSpecificEnthalpyByPressure.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeSpecificEnthalpyByPressure = Real ( + final quantity="DerUptakeSpecificEnthalpyByPressure", + final unit="J.kg/(kg.kg.Pa)", + displayUnit="kJ.kg/(kg.kg.Pa)") + "First-order partial derivative of specific enthalpy times the uptake w.r.t. pressure"; diff --git a/SorpLib/Units/DerUptakeSpecificEnthalpyByTemperature.mo b/SorpLib/Units/DerUptakeSpecificEnthalpyByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..793a7c2486979d4d1e29fab2a0d352453fae24c8 --- /dev/null +++ b/SorpLib/Units/DerUptakeSpecificEnthalpyByTemperature.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeSpecificEnthalpyByTemperature = Real ( + final quantity="DerUptakeSpecificEnthalpyByTemperature", + final unit="J.kg/(kg.kg.K)", + displayUnit="kJ.kg/(kg.kg.K)") + "First-order partial derivative of specific enthalpy times the uptake w.r.t. temperature"; diff --git a/SorpLib/Units/DerUptakeSpecificEnthalpyByUptake.mo b/SorpLib/Units/DerUptakeSpecificEnthalpyByUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..74de2dd74c245e5ca844179f1a2ba6d9da8a50e4 --- /dev/null +++ b/SorpLib/Units/DerUptakeSpecificEnthalpyByUptake.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeSpecificEnthalpyByUptake = Real ( + final quantity="DerUptakeSpecificEnthalpyByUptake", + final unit="J.kg.kg/(kg.kg.kg)", + displayUnit="kJ.kg.kg/(kg.kg.kg)") + "First-order partial derivative of specific enthalpy time the uptake w.r.t. uptake"; diff --git a/SorpLib/Units/DerUptakeSpecificEntropyByPressure.mo b/SorpLib/Units/DerUptakeSpecificEntropyByPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..541bc9e0a3379bb158731ca9df34947d15d6b40b --- /dev/null +++ b/SorpLib/Units/DerUptakeSpecificEntropyByPressure.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeSpecificEntropyByPressure = Real ( + final quantity="DerUptakeSpecificEntropyByPressure", + final unit="J.kg/(kg.kg.K.Pa)", + displayUnit="kJ.kg/(kg.kg.K.Pa)") + "First-order partial derivative of specific entropy times the uptake w.r.t. pressure"; diff --git a/SorpLib/Units/DerUptakeSpecificEntropyByTemperature.mo b/SorpLib/Units/DerUptakeSpecificEntropyByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..b98612b5c9cbab4c7da4791b6ad6a03814943cdd --- /dev/null +++ b/SorpLib/Units/DerUptakeSpecificEntropyByTemperature.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeSpecificEntropyByTemperature = Real ( + final quantity="DerUptakeSpecificEntropyByTemperature", + final unit="J.kg/(kg.kg.K2)", + displayUnit="kJ.kg/(kg.kg.K2)") + "First-order partial derivative of specific temperature times the uptake w.r.t. pressure"; diff --git a/SorpLib/Units/DerUptakeSpecificEntropyByUptake.mo b/SorpLib/Units/DerUptakeSpecificEntropyByUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..97856af3d770e5d555d7cef481fe4e84ca65850f --- /dev/null +++ b/SorpLib/Units/DerUptakeSpecificEntropyByUptake.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeSpecificEntropyByUptake = Real ( + final quantity="DerUptakeSpecificEntropyByUptake", + final unit="J.kg.kg/(kg2.kg.K)", + displayUnit="kJ.kg.kg/(kg2.kg.K)") + "First-order partial derivative of specific entropy times the uptake w.r.t. uptake"; diff --git a/SorpLib/Units/DerUptakeSpecificVolumeByPressure.mo b/SorpLib/Units/DerUptakeSpecificVolumeByPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..8b4bc87040d82808ca8b8519721405a969483acd --- /dev/null +++ b/SorpLib/Units/DerUptakeSpecificVolumeByPressure.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeSpecificVolumeByPressure = Real ( + final quantity="DerUptakeSpecificVolumeByPressure", + final unit="m3.kg/(kg.kg.Pa)", + displayUnit="m3.kg/(kg.kg.Pa)") + "First-order partial derivative of the specific volume time the uptake w.r.t. the pressure"; diff --git a/SorpLib/Units/DerUptakeSpecificVolumeByTemperature.mo b/SorpLib/Units/DerUptakeSpecificVolumeByTemperature.mo new file mode 100644 index 0000000000000000000000000000000000000000..95bda8d2ebf1b2e1625d1e4d8249a0640c1b297a --- /dev/null +++ b/SorpLib/Units/DerUptakeSpecificVolumeByTemperature.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeSpecificVolumeByTemperature = Real ( + final quantity="DerUptakeSpecificVolumeByTemperature", + final unit="m3.kg/(kg.kg.K)", + displayUnit="m3.kg/(kg.kg.K)") + "First-order partial derivative of the specific volume time the uptake w.r.t. the temperature"; diff --git a/SorpLib/Units/DerUptakeSpecificVolumeByUptake.mo b/SorpLib/Units/DerUptakeSpecificVolumeByUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..ee383028fb21a53ee8fe7f807651008ffacdecd7 --- /dev/null +++ b/SorpLib/Units/DerUptakeSpecificVolumeByUptake.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type DerUptakeSpecificVolumeByUptake = Real ( + final quantity="DerUptakeSpecificVolumeByUptake", + final unit="m3.kg.kg/(kg.kg.kg)", + displayUnit="m3.kg.kg/(kg.kg.kg)") + "First-order partial derivative of the specific volume time the uptake w.r.t. the uptake"; diff --git a/SorpLib/Units/FilledPoreVolume.mo b/SorpLib/Units/FilledPoreVolume.mo new file mode 100644 index 0000000000000000000000000000000000000000..8216ff5de937e140ff9189485d3802fc0c0cbfd0 --- /dev/null +++ b/SorpLib/Units/FilledPoreVolume.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type FilledPoreVolume = Real ( + final quantity="FilledPoreVolume", + final unit="m3/kg", + displayUnit="l/kg", + min=0) + "Filled pore volume"; diff --git a/SorpLib/Units/IntegralMolarHeatCapacityByUptake.mo b/SorpLib/Units/IntegralMolarHeatCapacityByUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..6550434e609c47c804fa2986ca6990fb19569fff --- /dev/null +++ b/SorpLib/Units/IntegralMolarHeatCapacityByUptake.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type IntegralMolarHeatCapacityByUptake=Real ( + final quantity="IntegralMolarHeatCapacityByUptake", + final unit="J.kg/(mol.kg.K)", + displayUnit="kJ.kg/(mol.kg.K)") + "Integral of the molar heat capacity w.r.t. the uptake"; diff --git a/SorpLib/Units/IntegralSpecificHeatCapacityByUptake.mo b/SorpLib/Units/IntegralSpecificHeatCapacityByUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..495dc027e643f25686dd8d9da53cb32ec71b7a8a --- /dev/null +++ b/SorpLib/Units/IntegralSpecificHeatCapacityByUptake.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type IntegralSpecificHeatCapacityByUptake = Real ( + final quantity="IntegralSpecificHeatCapacityByUptake", + final unit="J/(kg.K)", + displayUnit="kJ/(kg.K)") + "Integral of the specific heat capacity w.r.t. the uptake"; diff --git a/SorpLib/Units/MolarAdsorptionPotential.mo b/SorpLib/Units/MolarAdsorptionPotential.mo new file mode 100644 index 0000000000000000000000000000000000000000..9a8a8dbb404f5a0c35f4b5def1e48b89c89c55a5 --- /dev/null +++ b/SorpLib/Units/MolarAdsorptionPotential.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type MolarAdsorptionPotential =Real ( + final quantity="MolarAdsorptionPotential", + final unit="J/mol", + displayUnit="kJ/mol", + min=0) "Molar adsorption potential"; diff --git a/SorpLib/Units/MolarUptake.mo b/SorpLib/Units/MolarUptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..1b38f3839c951e146df548393faa2de1243d1087 --- /dev/null +++ b/SorpLib/Units/MolarUptake.mo @@ -0,0 +1,7 @@ +within SorpLib.Units; +type MolarUptake = Real ( + final quantity="MolarUptake", + final unit="mol/kg", + displayUnit="mol/kg", + min=0, + nominal=0.5) "Equilibrium molar uptake"; diff --git a/SorpLib/Units/ReducedSpreadingPressure.mo b/SorpLib/Units/ReducedSpreadingPressure.mo new file mode 100644 index 0000000000000000000000000000000000000000..fcc2c2ceca091467f436e8813a23f25ec1a8a008 --- /dev/null +++ b/SorpLib/Units/ReducedSpreadingPressure.mo @@ -0,0 +1,6 @@ +within SorpLib.Units; +type ReducedSpreadingPressure = Real ( + final quantity="ReducedSpreadingPressure", + final unit="mol/kg", + displayUnit="mol/kg") + "Reduced spreading pressure"; diff --git a/SorpLib/Units/Uptake.mo b/SorpLib/Units/Uptake.mo new file mode 100644 index 0000000000000000000000000000000000000000..62625924edefc3b94e589d9ae89759033ca5ba4a --- /dev/null +++ b/SorpLib/Units/Uptake.mo @@ -0,0 +1,8 @@ +within SorpLib.Units; +type Uptake = Real ( + final quantity="Uptake", + final unit="kg/kg", + displayUnit="kg/kg", + min=0, + nominal=0.5) + "Equilibrium uptake"; diff --git a/SorpLib/Units/package.mo b/SorpLib/Units/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..9547caeadf0e5d9b5b9347d1b691ae8911e3aeee --- /dev/null +++ b/SorpLib/Units/package.mo @@ -0,0 +1,53 @@ +within SorpLib; +package Units "Package containing definitions of units" +extends Modelica.Icons.Package; + +annotation (Icon(graphics={ + Polygon( + fillColor = {128,128,128}, + pattern = LinePattern.None, + fillPattern = FillPattern.Solid, + points={{-84,-42},{-84,-42},{-59,48},{-56.5,60.5},{-69,58},{-69,63},{ + -39,75.5},{-36.5,58},{-54,-2},{-54,-2},{-34,13},{-24,25.5},{-36.5, + 25.5},{-36.5,25.5},{-36.5,30.5},{-36.5,30.5},{-1.5,30.5},{-1.5,30.5}, + {-1.5,25.5},{-1.5,25.5},{-11.5,25.5},{-34,5.5},{-34,5.5},{-29,-27}, + {-21.5,-30.75},{-14,-27},{-9,-28.25},{-9,-34.5},{-20.25,-43.25},{ + -35.25,-45.75},{-44,-35.75},{-49,-7},{-49,-7},{-56.5,-12},{-56.5, + -12},{-64,-42},{-64,-42}}, + smooth = Smooth.Bezier), + Polygon( + fillColor = {128,128,128}, + pattern = LinePattern.None, + fillPattern = FillPattern.Solid, + points={{83.5,28},{58.5,28},{58.5,28},{51,31.75},{32.25,33},{12.25,23}, + {3.5,4.25},{7.25,-9.5},{18.5,-14.5},{18.5,-14.5},{2.25,-24.5},{2.25, + -37},{12.25,-40.75},{12.25,-40.75},{17.25,-43.25},{17.25,-43.25},{ + 41,-50.75},{43.5,-63.25},{28.5,-72},{8.5,-67},{3.5,-53.25},{17.25, + -43.25},{17.25,-43.25},{12.25,-40.75},{12.25,-40.75},{2.25,-43.25}, + {-10.25,-52},{-7.75,-70.75},{26,-78.25},{61,-64.5},{59.75,-37},{ + 23.5,-28.25},{18.5,-22},{23.5,-17},{23.5,-17},{26,-9.5},{26,-9.5},{ + 23.5,-4.5},{24.75,9.25},{32.25,25.5},{43.5,28},{49.75,20.5},{47.25, + 6.75},{41,-8.25},{31,-13.25},{26,-9.5},{26,-9.5},{23.5,-17},{23.5, + -17},{39.75,-18.25},{61,-8.25},{68.5,8},{66,18},{66,18},{76,18}}, + smooth = Smooth.Bezier)}), Documentation(revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>", info="<html> +<p> +This package contains definitions of types representing units used +within the Modelica library SorpLib. These types are used for type +checking (i.e., units) when implementing model equations. +</p> + +<h4>Adding new units</h4> +<p> +Before adding new units, please check if the unit is already +implemented in the +<a href=\"modelica://Modelica.Units\">Modelica standard library</a>. +</p> +</html>")); +end Units; diff --git a/SorpLib/Units/package.order b/SorpLib/Units/package.order new file mode 100644 index 0000000000000000000000000000000000000000..d7377619af30a7ee6bc5c16dac95606231b7b380 --- /dev/null +++ b/SorpLib/Units/package.order @@ -0,0 +1,54 @@ +MolarUptake +Uptake +DerUptakeByPressure +DerUptakeByMolarFraction +DerUptakeByTemperature +DerUptakeByPressurePressure +DerUptakeByTemperatureTemperature +DerUptakeByPressureTemperature +ReducedSpreadingPressure +AdsorptionPotential +MolarAdsorptionPotential +DerMolarAdsorptionPotentialByPressure +DerMolarAdsorptionPotentialByTemperature +DerMolarAdsorptionPotentialByPressurePressure +DerMolarAdsorptionPotentialByTemperatureTemperature +DerMolarAdsorptionPotentialByPressureTemperature +FilledPoreVolume +DerFilledPoreVolumeByTemperature +DerFilledPoreVolumeByAdsorptionPotential +DerFilledPoreVolumeByAdsorptionPotentialAdsorptionPotential +DerFilledPoreVolumeByAdsorptionPotentialTemperature +DerPressureByUptake +DerPressureByTemperatureTemperature +DerDensityByTemperature +DerDensityByTemperatureTemperature +DerSpecificVolumeByUptake +DerSpecificVolumeByPressure +DerSpecificVolumeByTemperature +DerSpecificVolumeByPressureTemperature +DerSpecificVolumeByTemperatureTemperature +DerSpecificEnthalpyByUptake +DerSpecificEnthalpyByPressure +DerMolarEnthalpyByPressure +DerMolarEnthalpyByUptake +DerSpecificEntropyByUptake +DerSpecificEntropyByPressure +DerSpecificEntropyByTemperature +DerIsobaricExpansionCoefficientByPressure +DerIsobaricExpansionCoefficientByTemperature +DerSpecificHeatCapacityByTemperature +DerSpecificHeatCapacityByTemperatureTemperature +DerThermalConductivityByTemperature +DerThermalConductivityByTemperatureTemperature +IntegralMolarHeatCapacityByUptake +IntegralSpecificHeatCapacityByUptake +DerUptakeSpecificVolumeByUptake +DerUptakeSpecificVolumeByPressure +DerUptakeSpecificVolumeByTemperature +DerUptakeSpecificEnthalpyByUptake +DerUptakeSpecificEnthalpyByPressure +DerUptakeSpecificEnthalpyByTemperature +DerUptakeSpecificEntropyByUptake +DerUptakeSpecificEntropyByPressure +DerUptakeSpecificEntropyByTemperature diff --git a/SorpLib/UsersGuide/Connectors/package.mo b/SorpLib/UsersGuide/Connectors/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a48db48550932627f475d2852277657757987f21 --- /dev/null +++ b/SorpLib/UsersGuide/Connectors/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide; +package Connectors "Connectors" +extends Modelica.Icons.Information; +end Connectors; diff --git a/SorpLib/UsersGuide/Connectors/package.order b/SorpLib/UsersGuide/Connectors/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/UsersGuide/Contact/package.mo b/SorpLib/UsersGuide/Contact/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..fab87edf72354dc74ba86d11c896704b4cb9531e --- /dev/null +++ b/SorpLib/UsersGuide/Contact/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide; +package Contact "Contact" +extends Modelica.Icons.Contact; +end Contact; diff --git a/SorpLib/UsersGuide/Contact/package.order b/SorpLib/UsersGuide/Contact/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/UsersGuide/Conventions/HTMLDocumentation/NamingConvention/package.mo b/SorpLib/UsersGuide/Conventions/HTMLDocumentation/NamingConvention/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..56cdbdf2007db5e1dd1be99f68e34cd2e4bfa9a2 --- /dev/null +++ b/SorpLib/UsersGuide/Conventions/HTMLDocumentation/NamingConvention/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide.Conventions.HTMLDocumentation; +package NamingConvention "Naming convention" +extends Modelica.Icons.Information; +end NamingConvention; diff --git a/SorpLib/UsersGuide/Conventions/HTMLDocumentation/NamingConvention/package.order b/SorpLib/UsersGuide/Conventions/HTMLDocumentation/NamingConvention/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/UsersGuide/Conventions/HTMLDocumentation/StructureFormat/package.mo b/SorpLib/UsersGuide/Conventions/HTMLDocumentation/StructureFormat/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..654c6a37668df913d68460fe63365f50773afce8 --- /dev/null +++ b/SorpLib/UsersGuide/Conventions/HTMLDocumentation/StructureFormat/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide.Conventions.HTMLDocumentation; +package StructureFormat "Structure and format" + extends Modelica.Icons.Information; +end StructureFormat; diff --git a/SorpLib/UsersGuide/Conventions/HTMLDocumentation/StructureFormat/package.order b/SorpLib/UsersGuide/Conventions/HTMLDocumentation/StructureFormat/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/UsersGuide/Conventions/HTMLDocumentation/package.mo b/SorpLib/UsersGuide/Conventions/HTMLDocumentation/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..0e0427a938451e2f48623e3d30508e61ba5668df --- /dev/null +++ b/SorpLib/UsersGuide/Conventions/HTMLDocumentation/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide.Conventions; +package HTMLDocumentation "HTML documentation" +extends Modelica.Icons.Information; +end HTMLDocumentation; diff --git a/SorpLib/UsersGuide/Conventions/HTMLDocumentation/package.order b/SorpLib/UsersGuide/Conventions/HTMLDocumentation/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e7738ab020a8a15f2857b4a6d73711fc097dc8ac --- /dev/null +++ b/SorpLib/UsersGuide/Conventions/HTMLDocumentation/package.order @@ -0,0 +1,2 @@ +StructureFormat +NamingConvention diff --git a/SorpLib/UsersGuide/Conventions/ModelicaCode/NamingConvention/package.mo b/SorpLib/UsersGuide/Conventions/ModelicaCode/NamingConvention/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..a4e440232d33394789faa39afeff16daabde92ce --- /dev/null +++ b/SorpLib/UsersGuide/Conventions/ModelicaCode/NamingConvention/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide.Conventions.ModelicaCode; +package NamingConvention "Naming convention" +extends Modelica.Icons.Information; +end NamingConvention; diff --git a/SorpLib/UsersGuide/Conventions/ModelicaCode/NamingConvention/package.order b/SorpLib/UsersGuide/Conventions/ModelicaCode/NamingConvention/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/UsersGuide/Conventions/ModelicaCode/StructureFormat/package.mo b/SorpLib/UsersGuide/Conventions/ModelicaCode/StructureFormat/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..892fe19d55ad98a91fa90a1ce8beedd16d20edc6 --- /dev/null +++ b/SorpLib/UsersGuide/Conventions/ModelicaCode/StructureFormat/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide.Conventions.ModelicaCode; +package StructureFormat "Structure and format" + extends Modelica.Icons.Information; +end StructureFormat; diff --git a/SorpLib/UsersGuide/Conventions/ModelicaCode/StructureFormat/package.order b/SorpLib/UsersGuide/Conventions/ModelicaCode/StructureFormat/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/UsersGuide/Conventions/ModelicaCode/package.mo b/SorpLib/UsersGuide/Conventions/ModelicaCode/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..1fd130b27a05dfd8a1143953416653a713083dd8 --- /dev/null +++ b/SorpLib/UsersGuide/Conventions/ModelicaCode/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide.Conventions; +package ModelicaCode "Modelica code" +extends Modelica.Icons.Information; +end ModelicaCode; diff --git a/SorpLib/UsersGuide/Conventions/ModelicaCode/package.order b/SorpLib/UsersGuide/Conventions/ModelicaCode/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e7738ab020a8a15f2857b4a6d73711fc097dc8ac --- /dev/null +++ b/SorpLib/UsersGuide/Conventions/ModelicaCode/package.order @@ -0,0 +1,2 @@ +StructureFormat +NamingConvention diff --git a/SorpLib/UsersGuide/Conventions/package.mo b/SorpLib/UsersGuide/Conventions/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..de5266b777aabc788578574075cd2b8e6233b789 --- /dev/null +++ b/SorpLib/UsersGuide/Conventions/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide; +package Conventions "Convetions" +extends Modelica.Icons.Information; +end Conventions; diff --git a/SorpLib/UsersGuide/Conventions/package.order b/SorpLib/UsersGuide/Conventions/package.order new file mode 100644 index 0000000000000000000000000000000000000000..33b365133a7f6c4794f4f33c56bcc9b97792ce5d --- /dev/null +++ b/SorpLib/UsersGuide/Conventions/package.order @@ -0,0 +1,2 @@ +ModelicaCode +HTMLDocumentation diff --git a/SorpLib/UsersGuide/Overview/package.mo b/SorpLib/UsersGuide/Overview/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..49410d329fd24ee0a28b6cad4c78a96ec7a1ba4d --- /dev/null +++ b/SorpLib/UsersGuide/Overview/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide; +package Overview "Overview of SorpLib library" +extends Modelica.Icons.Information; +end Overview; diff --git a/SorpLib/UsersGuide/Overview/package.order b/SorpLib/UsersGuide/Overview/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/UsersGuide/ReleaseNotes/package.mo b/SorpLib/UsersGuide/ReleaseNotes/package.mo new file mode 100644 index 0000000000000000000000000000000000000000..4e38b692610c6a9a0ef9158128467f7f7aa161aa --- /dev/null +++ b/SorpLib/UsersGuide/ReleaseNotes/package.mo @@ -0,0 +1,4 @@ +within SorpLib.UsersGuide; +package ReleaseNotes "Release notes" +extends Modelica.Icons.ReleaseNotes; +end ReleaseNotes; diff --git a/SorpLib/UsersGuide/ReleaseNotes/package.order b/SorpLib/UsersGuide/ReleaseNotes/package.order new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SorpLib/UsersGuide/package.mo b/SorpLib/UsersGuide/package.mo index 5a40f4ea2a5721dee3f2bed122fbd364cafb1292..1a8652ee11d8cd69b9c879dd6b6f7ddc359a5749 100644 --- a/SorpLib/UsersGuide/package.mo +++ b/SorpLib/UsersGuide/package.mo @@ -2,20 +2,9 @@ within SorpLib; package UsersGuide "User's Guide" extends Modelica.Icons.Information; -annotation (DocumentationClass=true, Documentation(info="<html> - <p> - <b>SorpLib - Adsorption Energy Systems Library</b> (short <b>SorpLib</b>) is a Modelica model library for simulating adsorption energy systems, such as adsorption chillers, adsorption heat pumps, adsorption thermal sorage systems, or desiccant systems. The library is being developed at RWTH Aachen University, Institute of Technical Thermodynamics, Sorption Systems Engineering group in Aachen, Germany. - </p> - <h3>Dependencies</h3> - Regarding non-adsorption specific models, the library partly depends on the libraries TIL and TILMedia: - <ul> - <li>TIL: Component library for thermal systems</li> - <li>TILMedia: Thermophysical media properties</li> - - </ul> - <p> TIL and TILMedia are commercial libraries provided by <a href='https://www.tlk-thermo.com/index.php/en/'> TLK-Thermo GmbH</a>. - At the moment, it is necessary to have these libraries to use the **SorpLib**. For the future, a light version of TIL and TIL-Media may be freely available. - </p> - + annotation (DocumentationClass=true, +Documentation(info="<html> +<p> +</p> </html>")); end UsersGuide; diff --git a/SorpLib/UsersGuide/package.order b/SorpLib/UsersGuide/package.order index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fdefe73d5b5355802516be5602280c39ad00a434 100644 --- a/SorpLib/UsersGuide/package.order +++ b/SorpLib/UsersGuide/package.order @@ -0,0 +1,5 @@ +Overview +Connectors +Conventions +ReleaseNotes +Contact diff --git a/SorpLib/package.mo b/SorpLib/package.mo index 99803786f0c62e28bb4c3b5726582b7c1b016b94..cc0d6bcf7339970dba146c3a92bd10b35077ebd4 100644 --- a/SorpLib/package.mo +++ b/SorpLib/package.mo @@ -1,36 +1,13 @@ within ; -package SorpLib "SorpLib" - import SI = Modelica.SIunits; - - - - - - - - - - - annotation ( - version="", - preferedView="info", - conversion(noneFromVersion=""), - uses( - TILMedia(version="3.5.0"), - TIL(version="3.5.0"), - Modelica(version="3.2.2")), - Documentation(info="<html> -<p> - <img src=\"modelica://SorpLib/Resources/Images/Sorplib_info.png\"> -</p> -<p> -The model library <b>SorpLib</b> is released by RWTH Aachen University, Chair of Technical Thermodynamics under the <a href=\"https://git.rwth-aachen.de/ltt_group/LTT_SorptionEnergySystems_library/blob/develop/LICENSE.md\"> BSD 3-Clause License</a>.<br> -Copyright © 2010-2017, RWTH Aachen University, Chair of Technical Thermodynamics. -</p> -</html>", revisions=""), - Icon(coordinateSystem(preserveAspectRatio=true, extent={{-100,-100},{100,100}}, grid={1,1}), graphics={ - Bitmap( - extent={{-162,-128},{123,134}}, - fileName="modelica://SorpLib/Resources/Images/Sorplib_logo.png")}), - Diagram(coordinateSystem(extent={{-1,-60},{80,40}}))); +package SorpLib "SorpLib 2.0 - Adsorption Systems Library" + extends SorpLib.Icons.SorpLibPackage; + + annotation (uses(Modelica(version="4.0.0")), Documentation(revisions="<html> +<ul> + <li> + October 26, 2023, by Mirko Engelpracht:<br/> + First implementation after restructuring the library. + </li> +</ul> +</html>")); end SorpLib; diff --git a/SorpLib/package.order b/SorpLib/package.order index f5e41cd8000556cb259594831fdd170c091d6e0c..7765b771ff12ec2a94c9feeeb7604b2b91fa5620 100644 --- a/SorpLib/package.order +++ b/SorpLib/package.order @@ -1,5 +1,10 @@ UsersGuide Media +Basics Components -Applications -Internals +Modules +Numerics +Icons +Choices +Units +Examples